mixmaster

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

chain1.c (8551B)


      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    Encrypt message for Cypherpunk remailer chain
      9    $Id: chain1.c 934 2006-06-24 13:40:39Z rabbi $ */
     10 
     11 
     12 #include "mix3.h"
     13 #include "pgp.h"
     14 #include <string.h>
     15 #include <ctype.h>
     16 
     17 #define N(X) (isdigit(X) ? (X)-'0' : 0)
     18 
     19 int t1_rlist(REMAILER remailer[], int badchains[MAXREM][MAXREM])
     20 {
     21   FILE *list, *excl;
     22   int i, listed = 0;
     23   int n = 0;
     24   char line[2 * LINELEN], l2[LINELEN], name[LINELEN], *flags;
     25   BUFFER *starex;
     26 
     27   starex = buf_new();
     28   excl = mix_openfile(STAREX, "r");
     29   if (excl != NULL) {
     30     buf_read(starex, excl);
     31     fclose(excl);
     32   }
     33 
     34   list = mix_openfile(TYPE1LIST, "r");
     35   if (list == NULL) {
     36     buf_free(starex);
     37     return (-1);
     38   }
     39 
     40   while (fgets(line, sizeof(line), list) != NULL && n < MAXREM) {
     41     if (strleft(line, "$remailer") &&
     42 	strchr(line, '<') && strchr(line, '>') &&
     43 	strchr(line, '{') && strchr(line, '{') + 4 < strchr(line, '}')) {
     44       if (line[strlen(line) - 1] == '\n')
     45 	line[strlen(line) - 1] = '\0';
     46       if (line[strlen(line) - 1] == '\r')
     47 	line[strlen(line) - 1] = '\0';
     48       while (line[strlen(line) - 1] == ' ')
     49 	line[strlen(line) - 1] = '\0';
     50       if (line[strlen(line) - 1] != ';'
     51 	  && fgets(l2, sizeof(l2), list) != NULL)
     52 	strcatn(line, l2, LINELEN);
     53       flags = strchr(line, '>');
     54       strncpy(name, strchr(line, '{') + 2,
     55 	      strchr(line, '}') - strchr(line, '{') - 3);
     56       name[strchr(line, '}') - strchr(line, '{') - 3] = '\0';
     57       name[20] = '\0';
     58 
     59       for (i = 1; i <= n; i++)
     60 	if (streq(name, remailer[i].name))
     61 	  break;
     62       if (i > n) {
     63 	/* not in mix list */
     64 	n++;
     65 	strcpy(remailer[i].name, name);
     66 	strncpy(remailer[i].addr, strchr(line, '<') + 1,
     67 		strchr(line, '>') - strchr(line, '<'));
     68 	remailer[i].addr[strchr(line, '>') - strchr(line, '<') - 1]
     69 	  = '\0';
     70 	remailer[i].flags.mix = 0;
     71 	remailer[i].flags.post = strifind(flags, " post");
     72       }
     73       remailer[i].flags.cpunk = strfind(flags, " cpunk");
     74       remailer[i].flags.pgp = strfind(flags, " pgp");
     75       remailer[i].flags.pgponly = strfind(flags, " pgponly");
     76       remailer[i].flags.latent = strfind(flags, " latent");
     77       remailer[i].flags.middle = strfind(flags, " middle");
     78       remailer[i].flags.ek = strfind(flags, " ek");
     79       remailer[i].flags.esub = strfind(flags, " esub");
     80       remailer[i].flags.newnym = strfind(flags, " newnym");
     81       remailer[i].flags.nym = strfind(flags, " nym");
     82       remailer[i].info[1].reliability = 0;
     83       remailer[i].info[1].latency = 0;
     84       remailer[i].info[1].history[0] = '\0';
     85       remailer[i].flags.star_ex = bufifind(starex, name);
     86    }
     87     if (strleft(line,
     88 		"-----------------------------------------------------------------------"))
     89       break;
     90   }
     91   n++;				/* ?? */
     92   while (fgets(line, sizeof(line), list) != NULL) {
     93     if (strlen(line) >= 72 && strlen(line) <= 73)
     94       for (i = 1; i < n; i++)
     95 	if (strleft(line, remailer[i].name) &&
     96 	    line[strlen(remailer[i].name)] == ' ') {
     97 	  strncpy(remailer[i].info[1].history, line + 42, 12);
     98 	  remailer[i].info[1].history[12] = '\0';
     99 	  remailer[i].info[1].reliability = 10000 * N(line[64])
    100 	    + 1000 * N(line[65]) + 100 * N(line[66])
    101 	    + 10 * N(line[68]) + N(line[69]);
    102 	  remailer[i].info[1].latency = 36000 * N(line[55])
    103 	    + 3600 * N(line[56]) + 600 * N(line[58])
    104 	    + 60 * N(line[59]) + 10 * N(line[61])
    105 	    + N(line[62]);
    106 	  listed++;
    107 	}
    108   }
    109   fclose(list);
    110   parse_badchains(badchains, TYPE1LIST, "Broken type-I remailer chains", remailer, n);
    111   if (listed < 4)		/* we have no valid reliability info */
    112     for (i = 1; i < n; i++)
    113       remailer[i].info[1].reliability = 10000;
    114 
    115 #ifdef USE_PGP
    116   pgp_rlist(remailer, n);
    117 #endif /* USE_PGP */
    118   buf_free(starex);
    119   return (n);
    120 }
    121 
    122 int t1_ek(BUFFER *key, BUFFER *seed, int num)
    123 {
    124   buf_reset(key);
    125   buf_appendc(key, (byte) num);
    126   buf_cat(key, seed);
    127   digest_md5(key, key);
    128   encode(key, 0);
    129 #ifdef DEBUG
    130   fprintf(stderr, "passphrase=%s (%2X%2X%2X%2X %d)\n", key->data,
    131 	  seed->data[0], seed->data[1], seed->data[2], seed->data[3], num);
    132 #endif /* DEBUG */
    133   return (0);
    134 }
    135 
    136 int t1_encrypt(int type, BUFFER *message, char *chainstr, int latency,
    137 	       BUFFER *ek, BUFFER *feedback)
    138 {
    139   BUFFER *b, *rem, *dest, *line, *field, *content;
    140   REMAILER remailer[MAXREM];
    141   int badchains[MAXREM][MAXREM];
    142   int maxrem, chainlen = 0;
    143   int chain[20];
    144   int hop;
    145   int hashmark = 0;
    146   int err = 0;
    147 
    148   b = buf_new();
    149   rem = buf_new();
    150   dest = buf_new();
    151   line = buf_new();
    152   field = buf_new();
    153   content = buf_new();
    154 
    155   maxrem = t1_rlist(remailer, badchains);
    156   if (maxrem < 1) {
    157     clienterr(feedback, "No remailer list!");
    158     err = -1;
    159     goto end;
    160   }
    161   chainlen = chain_select(chain, chainstr, maxrem, remailer, 1, line);
    162   if (chainlen < 1) {
    163     if (line->length)
    164       clienterr(feedback, line->data);
    165     else
    166       clienterr(feedback, "Invalid remailer chain!");
    167     err = -1;
    168     goto end;
    169   }
    170   if (chain[0] == 0)
    171     chain[0] = chain_randfinal(type, remailer, badchains, maxrem, 1, chain, chainlen, 0);
    172 
    173   if (chain[0] == -1) {
    174     clienterr(feedback, "Invalid remailer chain!");
    175     err = -1;
    176     goto end;
    177   }
    178   if (chain_rand(remailer, badchains, maxrem, chain, chainlen, 1, 0) == -1) {
    179     clienterr(feedback, "No reliable remailers!");
    180     err = -1;
    181     goto end;
    182   }
    183   while (buf_getheader(message, field, content) == 0) {
    184     hdr_encode(content, 0);
    185     if (type == MSG_POST && bufieq(field, "newsgroups") &&
    186 	remailer[chain[0]].flags.post) {
    187       buf_appendf(dest, "Anon-Post-To: %b\n", content);
    188     } else if (type == MSG_MAIL && bufieq(field, "to")) {
    189       buf_appendf(dest, "Anon-To: %b\n", content);
    190     } else {
    191       /* paste header */
    192       if (type == MSG_POST && bufieq(field, "newsgroups"))
    193 	buf_appendf(dest, "Anon-To: %s\n", MAILtoNEWS);
    194       if (hashmark == 0) {
    195 	buf_appends(b, "##\n");
    196 	hashmark = 1;
    197       }
    198       buf_appendheader(b, field, content);
    199     }
    200   }
    201   buf_nl(b);
    202   buf_rest(b, message);
    203   buf_move(message, b);
    204 
    205   if (type != MSG_NULL && dest->length == 0) {
    206     clienterr(feedback, "No destination address!");
    207     err = -1;
    208     goto end;
    209   }
    210   if (type == MSG_NULL) {
    211     buf_sets(dest, "Null:\n");
    212   }
    213   for (hop = 0; hop < chainlen; hop++) {
    214     if (hop == 0) {
    215       buf_sets(b, "::\n");
    216       buf_cat(b, dest);
    217     } else {
    218       buf_sets(b, "::\nAnon-To: ");
    219       buf_appends(b, remailer[chain[hop - 1]].addr);
    220       buf_nl(b);
    221     }
    222     if (remailer[chain[hop]].flags.latent && latency > 0)
    223       buf_appendf(b, "Latent-Time: +%d:00r\n", latency);
    224     if (ek && remailer[chain[hop]].flags.ek) {
    225       t1_ek(line, ek, hop);
    226       buf_appendf(b, "Encrypt-Key: %b\n", line);
    227     }
    228     buf_nl(b);
    229     buf_cat(b, message);
    230 #ifdef USE_PGP
    231     if (remailer[chain[hop]].flags.pgp) {
    232       buf_clear(message);
    233       buf_clear(rem);
    234       buf_setf(rem, "<%s>", remailer[chain[hop]].addr);
    235       err = pgp_encrypt(PGP_ENCRYPT | PGP_REMAIL | PGP_TEXT, b, rem,
    236 			NULL, NULL, NULL, NULL);
    237       if (err < 0) {
    238 	buf_setf(line, "No PGP key for remailer %s!\n",
    239 		 remailer[chain[hop]].name);
    240 	clienterr(feedback, line->data);
    241 	goto end;
    242       }
    243       buf_appends(message, "::\nEncrypted: PGP\n\n");
    244       buf_cat(message, b);
    245     } else
    246 #endif /* USE_PGP */
    247     {
    248       if (remailer[chain[hop]].flags.pgponly) {
    249 	buf_setf(line, "PGP encryption needed for remailer %s!\n",
    250 		 remailer[chain[hop]].name);
    251 	clienterr(feedback, line->data);
    252 	goto end;
    253       }
    254       buf_move(message, b);
    255     }
    256     if (ek && remailer[chain[hop]].flags.ek)
    257       buf_appends(message, "\n**\n");
    258   }
    259   buf_clear(b);
    260   if (chainlen == 0) {
    261     buf_appends(b, "::\n");
    262     buf_cat(b, dest);
    263   } else {
    264     buf_appendf(b, "%s: %s\n", ek ? "::\nAnon-To" : "To",
    265 		remailer[chain[chainlen - 1]].addr);
    266   }
    267   buf_nl(b);
    268   buf_cat(b, message);
    269   buf_move(message, b);
    270 end:
    271   buf_free(b);
    272   buf_free(rem);
    273   buf_free(dest);
    274   buf_free(line);
    275   buf_free(field);
    276   buf_free(content);
    277   return (err);
    278 }
    279 
    280 #ifdef USE_PGP
    281 int t1_getreply(BUFFER *msg, BUFFER *ek, int len)
    282 {
    283   BUFFER *key, *decrypt;
    284   int err = -1;
    285   int hop = 0;
    286 
    287   key = buf_new();
    288   decrypt = buf_new();
    289 
    290   do {
    291     t1_ek(key, ek, hop);
    292     buf_set(decrypt, msg);
    293     if (pgp_decrypt(decrypt, key, NULL, NULL, NULL) == 0
    294 	&& decrypt->data != NULL)
    295       err = 0, buf_move(msg, decrypt);
    296   }
    297   while (hop++ < len);
    298   return (err);
    299 }
    300 
    301 #endif /* USE_PGP */