tpgp.c - mixmaster - mixmaster 3.0 patched for libressl
 (HTM) 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 */