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