mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

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