tpgp.c - mixmaster - mixmaster 3.0 patched for libressl
HTML git clone git://parazyd.org/mixmaster.git
DIR Log
DIR Files
DIR Refs
DIR README
---
tpgp.c (11937B)
---
1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
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 934 2006-06-24 13:40:39Z rabbi $ */
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 /* end of 1 */
113 /* send headers as plain text */
114 buf_cat(plainhdr, encrhdr);
115 #endif /* not 1 */
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 /* end of 1 */
140 buf_setrnd(mboundary, 18);
141 encode(mboundary, 0);
142 #endif /* else if not 1 */
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 = PGP_K_ANY, 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, PGP_ARMOR_NYMSIG);
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, 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 /* USE_IDEA */
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 /* USE_IDEA */
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) ? PGP_ARMOR_REM : PGP_ARMOR_NORMAL);
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 #define POLY 0X1864CFB
278
279 unsigned long crc24(BUFFER * in)
280 {
281 unsigned long crc = 0xB704CE;
282 long p;
283 int i;
284
285 #if 0
286 /* CRC algorithm from RFC 2440 */
287 for (p = 0; p < in->length; p++) {
288 crc ^= in->data[p] << 16;
289 for (i = 0; i < 8; i++) {
290 crc <<= 1;
291 if (crc & 0x1000000)
292 crc ^= POLY;
293 }
294 }
295 #else
296 /* pre-computed CRC table -- much faster */
297 unsigned long table[256];
298 unsigned long t;
299 int q = 0;
300
301 table[0] = 0;
302 for (i = 0; i < 128; i++) {
303 t = table[i] << 1;
304 if (t & 0x1000000) {
305 table[q++] = t ^ POLY;
306 table[q++] = t;
307 } else {
308 table[q++] = t;
309 table[q++] = t ^ POLY;
310 }
311 }
312 for (p = 0; p < in->length; p++)
313 crc = crc << 8 ^ table[(in->data[p] ^ crc >> 16) & 255];
314 #endif
315 return crc & ((1<<24)-1);
316 }
317
318 /* ASCII armor */
319
320 int pgp_dearmor(BUFFER *in, BUFFER *out)
321 {
322 BUFFER *line, *temp;
323 int err = 0;
324 int tempbuf = 0;
325 unsigned long crc1, crc2;
326
327 line = buf_new();
328 temp = buf_new();
329
330 if (in == out) {
331 out = buf_new();
332 tempbuf = 1;
333 }
334 do
335 if (buf_getline(in, line) == -1) {
336 err = -1;
337 goto end;
338 }
339 while (!bufleft(line, begin_pgp)) ;
340
341 while (buf_getheader(in, temp, line) == 0) ; /* scan for empty line */
342
343 err = decode(in, out);
344 crc1 = crc24(out);
345 err = buf_getline(in, line);
346 if (line->length == 5 && line->data[0] == '=') { /* CRC */
347 line->ptr = 1;
348 err = decode(line, temp);
349 crc2 = (((unsigned long)temp->data[0])<<16) | (((unsigned long)temp->data[1])<<8) | temp->data[2];
350 if (crc1 == crc2)
351 err = buf_getline(in, line);
352 else {
353 errlog(NOTICE, "Message CRC does not match.\n");
354 err = -1;
355 }
356 } else
357 err = -1;
358 if (err == 0 && bufleft(line, end_pgp))
359 err = 0;
360 else
361 err = -1;
362
363 end:
364 buf_free(temp);
365 buf_free(line);
366
367 if (tempbuf) {
368 buf_move(in, out);
369 buf_free(out);
370 }
371 return (err);
372 }
373
374 int pgp_armor(BUFFER *in, int mode)
375
376 /* mode = 1: remailer message (PGP_ARMOR_REM)
377 * 0: normal message, (PGP_ARMOR_NORMAL)
378 * 2: key (PGP_ARMOR_KEY)
379 * 3: nym key (PGP_ARMOR_NYMKEY)
380 * 4: nym signature (PGP_ARMOR_NYMSIG)
381 * 5: secret key (PGP_ARMOR_SECKEY)
382 */
383
384 {
385 BUFFER *out;
386 unsigned long crc;
387
388 crc = crc24(in);
389 encode(in, 64);
390
391 out = buf_new();
392 if (mode == PGP_ARMOR_KEY || mode == PGP_ARMOR_NYMKEY)
393 buf_sets(out, begin_pgpkey);
394 else if (mode == PGP_ARMOR_NYMSIG)
395 buf_sets(out, begin_pgpsig);
396 else if (mode == PGP_ARMOR_SECKEY)
397 buf_sets(out, begin_pgpseckey);
398 else
399 buf_sets(out, begin_pgpmsg);
400 buf_nl(out);
401 #ifdef CLOAK
402 if (mode == PGP_ARMOR_REM || mode == PGP_ARMOR_NYMKEY || mode == PGP_ARMOR_NYMSIG)
403 buf_appends(out, "Version: N/A\n");
404 else
405 #elif MIMIC /* end of CLOAK */
406 if (mode == PGP_ARMOR_REM || mode == PGP_ARMOR_NYMKEY || mode == PGP_ARMOR_NYMSIG)
407 buf_appends(out, "Version: 2.6.3i\n");
408 else
409 #endif /* MIMIC */
410 {
411 buf_appends(out, "Version: Mixmaster ");
412 buf_appends(out, VERSION);
413 buf_appends(out, " (OpenPGP module)\n");
414 }
415 buf_nl(out);
416 buf_cat(out, in);
417 buf_reset(in);
418 buf_appendc(in, (crc >> 16) & 255);
419 buf_appendc(in, (crc >> 8) & 255);
420 buf_appendc(in, crc & 255);
421 encode(in, 0);
422 buf_appendc(out, '=');
423 buf_cat(out, in);
424 buf_nl(out);
425 if (mode == PGP_ARMOR_KEY || mode == PGP_ARMOR_NYMKEY)
426 buf_appends(out, end_pgpkey);
427 else if (mode == PGP_ARMOR_NYMSIG)
428 buf_appends(out, end_pgpsig);
429 else if (mode == PGP_ARMOR_SECKEY)
430 buf_appends(out, end_pgpseckey);
431 else
432 buf_appends(out, end_pgpmsg);
433 buf_nl(out);
434
435 buf_move(in, out);
436 buf_free(out);
437 return (0);
438 }
439
440 int pgp_keygen(int algo, int bits, BUFFER *userid, BUFFER *pass, char *pubring,
441 char *secring, int remail)
442 {
443 switch (algo) {
444 case PGP_ES_RSA:
445 #ifndef USE_IDEA
446 errlog(WARNING, "IDEA disabled: OpenPGP RSA key cannot be used for decryption!\n");
447 #endif
448 return (pgp_rsakeygen(bits, userid, pass, pubring, secring, remail));
449 case PGP_E_ELG:
450 return (pgp_dhkeygen(bits, userid, pass, pubring, secring, remail));
451 default:
452 return -1;
453 }
454 }
455
456 int pgp_signtxt(BUFFER *msg, BUFFER *uid, BUFFER *pass,
457 char *secring, int remail)
458 {
459 int err;
460 BUFFER *line, *sig, *out;
461
462 sig = buf_new();
463 out = buf_new();
464 line = buf_new();
465
466 buf_appends(out, begin_pgpsigned);
467 buf_nl(out);
468 if (pgpdb_getkey(PK_SIGN, PGP_ANY, NULL, NULL, NULL, NULL, uid, NULL, NULL, secring, pass) == PGP_S_DSA)
469 buf_appends(out, "Hash: SHA1\n");
470 buf_nl(out);
471 while (buf_getline(msg, line) != -1) {
472 if (line->data[0] == '-')
473 buf_appends(out, "- ");
474 buf_cat(out, line);
475 buf_nl(out);
476 }
477 buf_nl(out);
478
479 buf_rewind(msg);
480 err = pgp_encrypt(PGP_SIGN | PGP_DETACHEDSIG | PGP_TEXT |
481 (remail ? PGP_REMAIL : 0),
482 msg, NULL, uid, pass, NULL, secring);
483 if (err == -1)
484 goto end;
485 buf_cat(out, msg);
486 buf_move(msg, out);
487 end:
488 buf_free(line);
489 buf_free(sig);
490 buf_free(out);
491 return (err);
492 }
493
494 #endif /* USE_PGP */