pgp.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 */