/[pkg-mixmaster]/trunk/Mix/Src/pgp.c
ViewVC logotype

Contents of /trunk/Mix/Src/pgp.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 135 - (show annotations) (download)
Fri Aug 16 19:03:37 2002 UTC (10 years, 9 months ago) by rabbi
File MIME type: text/plain
File size: 10647 byte(s)
Mixmaster now uses the OpenPGP MDC packets (as specified in RFC 2440-bis06).

Mixmaster will use MDC packets if the MDC flag is found in the recipient's
PGP key, or by default if it is encrypting with AES.

New keys generated with Mixmaster will have the MDC flag placed in the key's
preferences. Also, cipher preferences are now advertised as CAST5, AES128,
3DES.
1 /* Mixmaster version 3 -- (C) 1999 Anonymizer Inc.
2
3 Mixmaster may be redistributed and modified under certain conditions.
4 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
5 ANY KIND, either express or implied. See the file COPYRIGHT for
6 details.
7
8 OpenPGP messages
9 $Id: pgp.c,v 1.5 2002/08/16 19:03:37 rabbi Exp $ */
10
11
12 #include "mix3.h"
13 #ifdef USE_PGP
14 #include "pgp.h"
15 #include <ctype.h>
16 #include <string.h>
17
18 int pgp_decrypt(BUFFER *in, BUFFER *pass, BUFFER *sig, char *pubring,
19 char *secring)
20 {
21 BUFFER *key;
22 int err;
23
24 key = buf_new();
25 if (pass)
26 buf_set(key, pass);
27 if (!pgp_ispacket(in))
28 pgp_dearmor(in, in);
29 err = pgp_getmsg(in, key, sig, pubring, secring);
30 buf_free(key);
31 return (err);
32 }
33
34 static void appendaddr(BUFFER *to, BUFFER *addr)
35 {
36 if (bufifind(addr, "<")) {
37 for (addr->ptr = 0; addr->ptr < addr->length; addr->ptr++)
38 if (addr->data[addr->ptr] == '<') {
39 buf_rest(to, addr);
40 break;
41 }
42 } else {
43 buf_appendc(to, '<');
44 buf_cat(to, addr);
45 buf_appendc(to, '>');
46 }
47 buf_nl(to);
48 buf_clear(addr);
49 }
50
51 int pgp_mailenc(int mode, BUFFER *msg, char *sigid,
52 BUFFER *pass, char *pubring, char *secring)
53 {
54 BUFFER *hdr, *body, *line, *uid, *field, *content;
55 int err = -1;
56
57 hdr = buf_new();
58 body = buf_new();
59 line = buf_new();
60 uid = buf_new();
61 field = buf_new();
62 content = buf_new();
63
64 buf_appendc(uid, '<');
65 buf_appends(uid, sigid);
66 if (sigid[strlen(sigid) - 1] != '@')
67 buf_appendc(uid, '>');
68
69 while (buf_getline(msg, line) == 0)
70 buf_cat(hdr, line), buf_nl(hdr);
71
72 if ((mode & PGP_SIGN) && !(mode & PGP_ENCRYPT))
73 while (buf_getheader(hdr, field, content) == 0)
74 if (bufileft(field, "content-") || bufieq(field, "mime-version")) {
75 /* Is MIME message */
76 err = pgpmime_sign(msg, uid, pass, secring);
77 goto end;
78 }
79
80 buf_rest(body, msg);
81
82 if ((mode & PGP_SIGN) && !(mode & PGP_ENCRYPT)) {
83 err = pgp_signtxt(body, uid, pass, secring, mode & PGP_REMAIL);
84 }
85
86 if (mode & PGP_ENCRYPT) {
87 BUFFER *plainhdr, *encrhdr, *to, *addr;
88 int encapsulate = 0;
89
90 plainhdr = buf_new();
91 encrhdr = buf_new();
92 to = buf_new();
93 addr = buf_new();
94 while (buf_getheader(hdr, field, content) == 0) {
95 if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) {
96 buf_appendheader(plainhdr, field, content);
97 rfc822_addr(content, addr);
98 while (buf_getline(addr, content) != -1)
99 appendaddr(to, content);
100 } else
101 buf_appendheader(encrhdr, field, content);
102 }
103 #if 1
104 /* encrypt the headers */
105 buf_appends(plainhdr, "Subject: PGP encrypted message\n");
106 if (encrhdr->length) {
107 buf_nl(encrhdr);
108 buf_cat(encrhdr, body);
109 buf_move(body, encrhdr);
110 encapsulate = 1;
111 }
112 #else
113 /* send headers as plain text */
114 buf_cat(plainhdr, encrhdr);
115 #endif
116 buf_move(hdr, plainhdr);
117
118 buf_clear(line);
119 if (encapsulate)
120 buf_sets(line, "Content-Type: message/rfc822\n");
121 else if (strlen(DEFLTENTITY))
122 buf_setf(line, "Content-Type: %s\n", DEFLTENTITY);
123 buf_nl(line);
124 buf_cat(line, body);
125 buf_move(body, line);
126
127 /* Use the user keyring if pubring == NULL */
128 err = pgp_encrypt(mode, body, to, uid, pass,
129 pubring ? pubring : PGPPUBRING, secring);
130 buf_free(plainhdr);
131 buf_free(encrhdr);
132 buf_free(to);
133 buf_free(addr);
134 }
135 if (err == 0) {
136 if (mode & PGP_ENCRYPT) {
137 #if 1
138 buf_sets(field, "+--");
139 #else
140 buf_setrnd(mboundary, 18);
141 encode(mboundary, 0);
142 #endif
143
144 buf_appendf(hdr,
145 "Content-Type: multipart/encrypted; boundary=\"%b\"; "
146 "protocol=\"application/pgp-encrypted\"\n\n"
147 "--%b\n"
148 "Content-Type: application/pgp-encrypted\n\n"
149 "Version: 1\n\n"
150 "--%b\n"
151 "Content-Type: application/octet-stream\n",
152 field, field, field);
153 buf_appendf(body, "\n--%b--\n", field);
154 }
155 buf_move(msg, hdr);
156 buf_nl(msg);
157 buf_cat(msg, body);
158 }
159 end:
160 buf_free(hdr);
161 buf_free(body);
162 buf_free(line);
163 buf_free(uid);
164 buf_free(field);
165 buf_free(content);
166 return (err);
167 }
168
169 static void pgp_setkey(BUFFER *key, int algo)
170 {
171 buf_setc(key, algo);
172 buf_appendrnd(key, pgp_keylen(algo));
173 }
174
175 int pgp_encrypt(int mode, BUFFER *in, BUFFER *to, BUFFER *sigid,
176 BUFFER *pass, char *pubring, char *secring)
177 {
178 BUFFER *dek, *out, *sig, *dest, *tmp;
179 int err = 0, sym = 0, mdc = 0;
180 int text;
181
182 out = buf_new();
183 tmp = buf_new();
184 dek = buf_new();
185 sig = buf_new();
186 dest = buf_new();
187
188 text = mode & PGP_TEXT ? 1 : 0;
189
190 if (mode & (PGP_CONV3DES | PGP_CONVCAST))
191 mode |= PGP_NCONVENTIONAL;
192
193 if (mode & PGP_SIGN) {
194 err = pgp_sign(in, NULL, sig, sigid, pass, text, 0, 0,
195 mode & PGP_REMAIL ? 1 : 0, NULL, secring);
196 if (err < 0)
197 goto end;
198 if (mode & PGP_DETACHEDSIG) {
199 buf_move(in, sig);
200 if (!(mode & PGP_NOARMOR))
201 pgp_armor(in, 4);
202 goto end;
203 }
204 }
205 if (mode & PGP_ENCRYPT) {
206 err = buf_getline(to, dest);
207 if (err == -1)
208 goto end;
209 if (to->ptr == to->length) {
210 if ((err = pgpdb_getkey(PK_ENCRYPT, PGP_ANY, &sym, &mdc, NULL, dest, NULL,
211 NULL, pubring, NULL)) < 0)
212 goto end;
213 pgp_setkey(dek, sym);
214 err = pgp_sessionkey(out, dest, NULL, dek, pubring);
215 #ifdef USE_IDEA
216 if (err < 0 && dek->data[0] == PGP_K_IDEA) {
217 pgp_setkey(dek, PGP_K_3DES);
218 err = pgp_sessionkey(out, dest, NULL, dek, pubring);
219 }
220 #endif
221 } else {
222 /* multiple recipients */
223 pgp_setkey(dek, PGP_K_3DES);
224 buf_rewind(to);
225 while (buf_getline(to, dest) != -1)
226 if (dest->length) {
227 err = pgp_sessionkey(tmp, dest, NULL, dek, pubring);
228 #ifdef USE_IDEA
229 if (err < 0 && dek->data[0] != PGP_K_IDEA) {
230 buf_rewind(to);
231 buf_clear(out);
232 pgp_setkey(dek, PGP_K_IDEA);
233 continue;
234 }
235 #endif
236 if (err < 0)
237 goto end;
238 buf_cat(out, tmp);
239 }
240 }
241 } else if (mode & PGP_NCONVENTIONAL) {
242 /* genereate DEK in pgp_symsessionkey */
243 buf_setc(dek, mode & PGP_CONVCAST ? PGP_K_CAST5 : PGP_K_3DES);
244 pgp_marker(out);
245 err = pgp_symsessionkey(tmp, dek, to);
246 buf_cat(out, tmp);
247 } else if (mode & PGP_CONVENTIONAL) {
248 digest_md5(to, tmp);
249 buf_setc(dek, PGP_K_IDEA);
250 buf_cat(dek, tmp);
251 }
252
253 pgp_literal(in, NULL, text);
254 if (sig->length) {
255 buf_cat(sig, in);
256 buf_move(in, sig);
257 }
258 pgp_compress(in);
259 if (mode & (PGP_ENCRYPT | PGP_CONVENTIONAL | PGP_NCONVENTIONAL))
260 pgp_symmetric(in, dek, mdc);
261 if (mode & (PGP_ENCRYPT | PGP_NCONVENTIONAL)) {
262 buf_cat(out, in);
263 buf_move(in, out);
264 }
265 if (!(mode & PGP_NOARMOR))
266 pgp_armor(in, (mode & PGP_REMAIL) ? 1 : 0);
267
268 end:
269 buf_free(out);
270 buf_free(tmp);
271 buf_free(dek);
272 buf_free(sig);
273 buf_free(dest);
274 return (err);
275 }
276
277 /* ASCII armor */
278
279 int pgp_dearmor(BUFFER *in, BUFFER *out)
280 {
281 BUFFER *line, *temp;
282 int err = 0;
283 int tempbuf = 0;
284
285 line = buf_new();
286 temp = buf_new();
287
288 if (in == out) {
289 out = buf_new();
290 tempbuf = 1;
291 }
292 do
293 if (buf_getline(in, line) == -1) {
294 err = -1;
295 goto end;
296 }
297 while (!bufleft(line, begin_pgp)) ;
298
299 while (buf_getheader(in, temp, line) == 0) ; /* scan for empty line */
300
301 err = decode(in, out);
302 err = buf_getline(in, line);
303 if (line->length == 5 && line->data[0] == '=') /* skip CRC */
304 err = buf_getline(in, line);
305 if (err == 0 && bufleft(line, end_pgp))
306 err = 0;
307 else
308 err = -1;
309
310 end:
311 buf_free(temp);
312 buf_free(line);
313
314 if (tempbuf) {
315 buf_move(in, out);
316 buf_free(out);
317 }
318 return (err);
319 }
320
321 #define POLY 0X1864CFB
322
323 int pgp_armor(BUFFER *in, int mode)
324 /* mode = 1: remailer message, 0: normal message, mode = 2: key 3=nym key
325 4=nym signature */
326 {
327 BUFFER *out;
328 unsigned long crc = 0xB704CE;
329 long p;
330 int i;
331
332 #if 0
333 /* CRC algorithm from RFC 2440 */
334 for (p = 0; p < in->length; p++) {
335 crc ^= in->data[p] << 16;
336 for (i = 0; i < 8; i++) {
337 crc <<= 1;
338 if (crc & 0x1000000)
339 crc ^= POLY;
340 }
341 }
342 #else
343 /* pre-computed CRC table -- much faster */
344 unsigned long table[256];
345 unsigned long t;
346 int q = 0;
347
348 table[0] = 0;
349 for (i = 0; i < 128; i++) {
350 t = table[i] << 1;
351 if (t & 0x1000000) {
352 table[q++] = t ^ POLY;
353 table[q++] = t;
354 } else {
355 table[q++] = t;
356 table[q++] = t ^ POLY;
357 }
358 }
359 for (p = 0; p < in->length; p++)
360 crc = crc << 8 ^ table[(in->data[p] ^ crc >> 16) & 255];
361 #endif
362 encode(in, 64);
363
364 out = buf_new();
365 if (mode == 2 || mode == 3)
366 buf_sets(out, begin_pgpkey);
367 else if (mode == 4)
368 buf_sets(out, begin_pgpsig);
369 else
370 buf_sets(out, begin_pgpmsg);
371 buf_nl(out);
372 #if 1
373 buf_appends(out, "Version: N/A\n");
374 #else
375 #ifdef MIMIC
376 if (mode == 1 || mode == 3 || mode == 4)
377 buf_appends(out, "Version: 2.6.3i\n");
378 else
379 #endif
380 {
381 buf_appends(out, "Version: Mixmaster ");
382 buf_appends(out, VERSION);
383 buf_appends(out, " (OpenPGP module)\n");
384 }
385 #endif
386 buf_nl(out);
387 buf_cat(out, in);
388 buf_reset(in);
389 buf_appendc(in, (crc >> 16) & 255);
390 buf_appendc(in, (crc >> 8) & 255);
391 buf_appendc(in, crc & 255);
392 encode(in, 0);
393 buf_appendc(out, '=');
394 buf_cat(out, in);
395 buf_nl(out);
396 if (mode == 2 || mode == 3)
397 buf_appends(out, end_pgpkey);
398 else if (mode == 4)
399 buf_appends(out, end_pgpsig);
400 else
401 buf_appends(out, end_pgpmsg);
402 buf_nl(out);
403
404 buf_move(in, out);
405 buf_free(out);
406 return (0);
407 }
408
409 int pgp_keygen(int algo, int bits, BUFFER *userid, BUFFER *pass, char *pubring,
410 char *secring, int remail)
411 {
412 switch (algo) {
413 #ifdef USE_RSA
414 case PGP_ES_RSA:
415 return (pgp_rsakeygen(bits, userid, pass, pubring, secring, remail));
416 #endif
417 case PGP_E_ELG:
418 return (pgp_dhkeygen(bits, userid, pass, pubring, secring, remail));
419 default:
420 return -1;
421 }
422 }
423
424 int pgp_signtxt(BUFFER *msg, BUFFER *uid, BUFFER *pass,
425 char *secring, int remail)
426 {
427 int err;
428 BUFFER *line, *sig, *out;
429
430 sig = buf_new();
431 out = buf_new();
432 line = buf_new();
433
434 buf_appends(out, begin_pgpsigned);
435 buf_nl(out);
436 if (pgpdb_getkey(PK_SIGN, PGP_ANY, NULL, NULL, NULL, uid, NULL, NULL, secring, pass) == PGP_S_DSA)
437 buf_appends(out, "Hash: SHA1\n");
438 buf_nl(out);
439 while (buf_getline(msg, line) != -1) {
440 if (line->data[0] == '-')
441 buf_appends(out, "- ");
442 buf_cat(out, line);
443 buf_nl(out);
444 }
445 buf_nl(out);
446
447 buf_rewind(msg);
448 err = pgp_encrypt(PGP_SIGN | PGP_DETACHEDSIG | PGP_TEXT |
449 (remail ? PGP_REMAIL : 0),
450 msg, NULL, uid, pass, NULL, secring);
451 if (err == -1)
452 goto end;
453 buf_cat(out, msg);
454 buf_move(msg, out);
455 end:
456 buf_free(line);
457 buf_free(sig);
458 buf_free(out);
459 return (err);
460 }
461
462 #endif /* USE_PGP */

  ViewVC Help
Powered by ViewVC 1.1.5