]> icculus.org git repositories - divverent/darkplaces.git/blob - crypto-keygen-standalone.c
fix two typos
[divverent/darkplaces.git] / crypto-keygen-standalone.c
1 #define _GNU_SOURCE
2
3 #include <d0_blind_id/d0_blind_id.h>
4
5 #include <ctype.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <getopt.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <signal.h>
12 #include <math.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15
16 // BEGIN stuff shared with crypto.c
17 #define FOURCC_D0PK (('d' << 0) | ('0' << 8) | ('p' << 16) | ('k' << 24))
18 #define FOURCC_D0SK (('d' << 0) | ('0' << 8) | ('s' << 16) | ('k' << 24))
19 #define FOURCC_D0PI (('d' << 0) | ('0' << 8) | ('p' << 16) | ('i' << 24))
20 #define FOURCC_D0SI (('d' << 0) | ('0' << 8) | ('s' << 16) | ('i' << 24))
21 #define FOURCC_D0IQ (('d' << 0) | ('0' << 8) | ('i' << 16) | ('q' << 24))
22 #define FOURCC_D0IR (('d' << 0) | ('0' << 8) | ('i' << 16) | ('r' << 24))
23 #define FOURCC_D0ER (('d' << 0) | ('0' << 8) | ('e' << 16) | ('r' << 24))
24 #define FOURCC_D0IC (('d' << 0) | ('0' << 8) | ('i' << 16) | ('c' << 24))
25
26 static unsigned long Crypto_LittleLong(const char *data)
27 {
28         return
29                 ((unsigned char) data[0]) |
30                 (((unsigned char) data[1]) << 8) |
31                 (((unsigned char) data[2]) << 16) |
32                 (((unsigned char) data[3]) << 24);
33 }
34
35 static void Crypto_UnLittleLong(char *data, unsigned long l)
36 {
37         data[0] = l & 0xFF;
38         data[1] = (l >> 8) & 0xFF;
39         data[2] = (l >> 16) & 0xFF;
40         data[3] = (l >> 24) & 0xFF;
41 }
42
43 static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps)
44 {
45         size_t i;
46         size_t pos;
47         pos = 0;
48         if(header)
49         {
50                 if(len < 4)
51                         return 0;
52                 if(Crypto_LittleLong(buf) != header)
53                         return 0;
54                 pos += 4;
55         }
56         for(i = 0; i < nlumps; ++i)
57         {
58                 if(pos + 4 > len)
59                         return 0;
60                 lumpsize[i] = Crypto_LittleLong(&buf[pos]);
61                 pos += 4;
62                 if(pos + lumpsize[i] > len)
63                         return 0;
64                 lumps[i] = &buf[pos];
65                 pos += lumpsize[i];
66         }
67         return pos;
68 }
69
70 static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, const char *const *lumps, const size_t *lumpsize, size_t nlumps)
71 {
72         size_t i;
73         size_t pos;
74         pos = 0;
75         if(header)
76         {
77                 if(len < 4)
78                         return 0;
79                 Crypto_UnLittleLong(buf, header);
80                 pos += 4;
81         }
82         for(i = 0; i < nlumps; ++i)
83         {
84                 if(pos + 4 + lumpsize[i] > len)
85                         return 0;
86                 Crypto_UnLittleLong(&buf[pos], lumpsize[i]);
87                 pos += 4;
88                 memcpy(&buf[pos], lumps[i], lumpsize[i]);
89                 pos += lumpsize[i];
90         }
91         return pos;
92 }
93
94 void file2buf(const char *fn, char **data, size_t *datasize)
95 {
96         FILE *f;
97         *data = NULL;
98         *datasize = 0;
99         size_t n = 0, dn = 0;
100         f = fopen(fn, "rb");
101         if(!f)
102         {
103                 return;
104         }
105         for(;;)
106         {
107                 *data = realloc(*data, *datasize += 8192);
108                 if(!*data)
109                 {
110                         *datasize = 0;
111                         return;
112                 }
113                 dn = fread(*data + n, 1, *datasize - n, f);
114                 if(!dn)
115                         break;
116                 n += dn;
117         }
118         fclose(f);
119         *datasize = n;
120 }
121
122 int buf2file(const char *fn, const char *data, size_t n)
123 {
124         FILE *f;
125         f = fopen(fn, "wb");
126         if(!f)
127                 return 0;
128         n = fwrite(data, n, 1, f);
129         if(fclose(f) || !n)
130                 return 0;
131         return 1;
132 }
133
134 void file2lumps(const char *fn, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps)
135 {
136         char *buf;
137         size_t n;
138         file2buf(fn, &buf, &n);
139         if(!buf)
140         {
141                 fprintf(stderr, "could not open %s\n", fn);
142                 exit(1);
143         }
144         if(!Crypto_ParsePack(buf, n, header, lumps, lumpsize, nlumps))
145         {
146                 fprintf(stderr, "could not parse %s as %c%c%c%c (%d lumps expected)\n", fn, (int) header & 0xFF, (int) (header >> 8) & 0xFF, (int) (header >> 16) & 0xFF, (int) (header >> 24) & 0xFF, (int) nlumps);
147                 free(buf);
148                 exit(1);
149         }
150         free(buf);
151 }
152
153 mode_t umask_save;
154 void lumps2file(const char *fn, unsigned long header, const char *const *lumps, size_t *lumpsize, size_t nlumps, D0_BOOL private)
155 {
156         char buf[65536];
157         size_t n;
158         if(private)
159                 umask(umask_save | 0077);
160         else
161                 umask(umask_save);
162         if(!(n = Crypto_UnParsePack(buf, sizeof(buf), header, lumps, lumpsize, nlumps)))
163         {
164                 fprintf(stderr, "could not unparse for %s\n", fn);
165                 exit(1);
166         }
167         if(!buf2file(fn, buf, n))
168         {
169                 fprintf(stderr, "could not write %s\n", fn);
170                 exit(1);
171         }
172 }
173
174 void USAGE(const char *me)
175 {
176         printf("Usage:\n"
177                         "%s [-F] [-b bits] [-n progress-denominator] [-x prefix] [-X infix] [-C] -o private.d0sk\n"
178                         "%s -P private.d0sk -o public.d0pk\n"
179                         "%s [-n progress-denominator] [-x prefix] [-X infix] [-C] -p public.d0pk -o idkey-unsigned.d0si\n"
180                         "%s -p public.d0pk -I idkey-unsigned.d0si -o request.d0iq -O camouflage.d0ic\n"
181                         "%s -P private.d0sk -j request.d0iq -o response.d0ir\n"
182                         "%s -p public.d0pk -I idkey-unsigned.d0si -c camouflage.d0ic -J response.d0ir -o idkey.d0si\n"
183                         "%s -P private.d0sk -I idkey-unsigned.d0si -o idkey.d0si\n"
184                         "%s -I idkey.d0si -o id.d0pi\n"
185                         "%s -p public.d0pk\n"
186                         "%s -P private.d0sk\n"
187                         "%s -p public.d0pk -i id.d0pi\n"
188                         "%s -p public.d0pk -I idkey.d0si\n"
189                         "%s -0 -p public.d0pk -I idkey.d0si\n"
190                         "%s -0 -p public.d0pk\n"
191                         "%s -p public.d0pk -I idkey.d0si -d file-to-sign.dat -o file-signed.dat\n"
192                         "%s -p public.d0pk -s file-signed.dat -o file-content.dat [-O id.d0pi]\n"
193                         "%s -p public.d0pk -I idkey.d0si -d file-to-sign.dat -O signature.dat\n"
194                         "%s -p public.d0pk -d file-to-sign.dat -s signature.dat [-O id.d0pi]\n",
195                         me, me, me, me, me, me, me, me, me, me, me, me, me, me, me, me, me, me
196                    );
197 }
198
199 unsigned int seconds;
200 unsigned int generated;
201 unsigned int ntasks = 1;
202 double generated_offset;
203 double guesscount;
204 double guessfactor;
205 void print_generated(int signo)
206 {
207         (void) signo;
208         ++seconds;
209         if(generated >= 1000000000)
210         {
211                 generated_offset += generated;
212                 generated = 0;
213         }
214         fprintf(stderr, "Generated: %.0f (about %.0f, %.1f/s, about %.2f hours for %.0f)\n",
215                 // nasty and dishonest hack:
216                 // we are adjusting the values "back", so the total count is
217                 // divided by guessfactor (as the check function is called
218                 // guessfactor as often as it would be if no fastreject were
219                 // done)
220                 // so the values indicate the relative speed of fastreject vs
221                 // normal!
222                 (generated + generated_offset) / guessfactor,
223                 (generated + generated_offset) * ntasks / guessfactor,
224                 (generated + generated_offset) * ntasks / (guessfactor * seconds),
225                 guesscount * ((guessfactor * seconds) / (generated + generated_offset) / ntasks) / 3600.0,
226                 guesscount);
227         alarm(1);
228 }
229
230 #define CHECK(x) if(!(x)) { fprintf(stderr, "error exit: error returned by %s\n", #x); exit(2); }
231
232 const char *prefix = NULL, *infix = NULL;
233 size_t prefixlen = 0;
234 int ignorecase;
235 typedef D0_BOOL (*fingerprint_func) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
236 D0_BOOL fastreject(const d0_blind_id_t *ctx, void *pass)
237 {
238         static char fp64[513]; size_t fp64size = 512;
239         CHECK(((fingerprint_func) pass)(ctx, fp64, &fp64size));
240         ++generated;
241         if(ignorecase)
242         {
243                 if(prefixlen)
244                         if(strncasecmp(fp64, prefix, prefixlen))
245                                 return 1;
246                 if(infix)
247                 {
248                         fp64[fp64size] = 0;
249                         if(!strcasestr(fp64, infix))
250                                 return 1;
251                 }
252         }
253         else
254         {
255                 if(prefixlen)
256                         if(memcmp(fp64, prefix, prefixlen))
257                                 return 1;
258                 if(infix)
259                 {
260                         fp64[fp64size] = 0;
261                         if(!strstr(fp64, infix))
262                                 return 1;
263                 }
264         }
265         return 0;
266 }
267
268 int main(int argc, char **argv)
269 {
270         int opt;
271         size_t lumpsize[2];
272         const char *lumps[2];
273         char *databuf_in; size_t databufsize_in;
274         char *databuf_out; size_t databufsize_out;
275         char *databuf_sig; size_t databufsize_sig;
276         char lumps_w0[65536];
277         char lumps_w1[65536];
278         const char *pubkeyfile = NULL, *privkeyfile = NULL, *pubidfile = NULL, *prividfile = NULL, *idreqfile = NULL, *idresfile = NULL, *outfile = NULL, *outfile2 = NULL, *camouflagefile = NULL, *datafile = NULL, *sigfile = NULL;
279         char fp64[513]; size_t fp64size = 512;
280         int mask = 0;
281         int bits = 1024;
282         int i;
283         D0_BOOL do_fastreject = 1;
284         d0_blind_id_t *ctx;
285         if(!d0_blind_id_INITIALIZE())
286         {
287                 fprintf(stderr, "could not initialize\n");
288                 exit(1);
289         }
290
291         umask_save = umask(0022);
292
293         ctx = d0_blind_id_new();
294         while((opt = getopt(argc, argv, "d:s:p:P:i:I:j:J:o:O:c:b:x:X:y:Fn:C0")) != -1)
295         {
296                 switch(opt)
297                 {
298                         case 'C':
299                                 ignorecase = 1;
300                                 break;
301                         case 'n':
302                                 ntasks = atoi(optarg);
303                                 break;
304                         case 'b':
305                                 bits = atoi(optarg);
306                                 break;
307                         case 'p': // d0pk = <pubkey> <modulus>
308                                 pubkeyfile = optarg;
309                                 mask |= 1;
310                                 break;
311                         case 'P': // d0sk = <privkey> <modulus>
312                                 privkeyfile = optarg;
313                                 mask |= 2;
314                                 break;
315                         case 'i': // d0pi = <pubid>
316                                 pubidfile = optarg;
317                                 mask |= 4;
318                                 break;
319                         case 'I': // d0si = <privid>
320                                 prividfile = optarg;
321                                 mask |= 8;
322                                 break;
323                         case 'j': // d0iq = <req>
324                                 idreqfile = optarg;
325                                 mask |= 0x10;
326                                 break;
327                         case 'J': // d0ir = <resp>
328                                 idresfile = optarg;
329                                 mask |= 0x20;
330                                 break;
331                         case 'o':
332                                 outfile = optarg;
333                                 mask |= 0x40;
334                                 break;
335                         case 'O':
336                                 outfile2 = optarg;
337                                 mask |= 0x80;
338                                 break;
339                         case 'c':
340                                 camouflagefile = optarg;
341                                 mask |= 0x100;
342                                 break;
343                         case 'x':
344                                 prefix = optarg;
345                                 prefixlen = strlen(prefix);
346                                 break;
347                         case '0':
348                                 // test mode
349                                 mask |= 0x200;
350                                 break;
351                         case 'd':
352                                 datafile = optarg;
353                                 mask |= 0x400;
354                                 break;
355                         case 's':
356                                 sigfile = optarg;
357                                 mask |= 0x800;
358                                 break;
359                         case 'X':
360                                 infix = optarg;
361                                 break;
362                         case 'F':
363                                 do_fastreject = 0;
364                                 break;
365                         default:
366                                 USAGE(*argv);
367                                 return 1;
368                 }
369         }
370
371         // fastreject is a slight slowdown when rejecting nothing at all
372         if(!infix && !prefixlen)
373                 do_fastreject = 0;
374
375         guesscount = pow(64.0, prefixlen);
376         if(infix)
377                 guesscount /= (1 - pow(1 - pow(1/64.0, strlen(infix)), 44 - prefixlen - strlen(infix)));
378         // 44 chars; prefix is assumed to not match the infix (although it theoretically could)
379         // 43'th char however is always '=' and does not count
380         if(ignorecase)
381         {
382                 if(infix)
383                         for(i = 0; infix[i]; ++i)
384                                 if(toupper(infix[i]) != tolower(infix[i]))
385                                         guesscount /= 2;
386                 for(i = 0; i < (int)prefixlen; ++i)
387                         if(toupper(prefix[i]) != tolower(prefix[i]))
388                                 guesscount /= 2;
389         }
390
391         if(do_fastreject)
392         {
393                 // fastreject: reject function gets called about log(2^bits) times more often
394                 guessfactor = bits * log(2) / 2;
395                 // so guess function gets called guesscount * guessfactor times, and it tests as many valid keys as guesscount
396         }
397
398         if(mask & 1)
399         {
400                 file2lumps(pubkeyfile, FOURCC_D0PK, lumps, lumpsize, 2);
401                 if(!d0_blind_id_read_public_key(ctx, lumps[0], lumpsize[0]))
402                 {
403                         fprintf(stderr, "could not decode public key\n");
404                         exit(1);
405                 }
406                 if(!d0_blind_id_read_private_id_modulus(ctx, lumps[1], lumpsize[1]))
407                 {
408                         fprintf(stderr, "could not decode modulus\n");
409                         exit(1);
410                 }
411         }
412         else if(mask & 2)
413         {
414                 file2lumps(privkeyfile, FOURCC_D0SK, lumps, lumpsize, 2);
415                 if(!d0_blind_id_read_private_key(ctx, lumps[0], lumpsize[0]))
416                 {
417                         fprintf(stderr, "could not decode private key\n");
418                         exit(1);
419                 }
420                 if(!d0_blind_id_read_private_id_modulus(ctx, lumps[1], lumpsize[1]))
421                 {
422                         fprintf(stderr, "could not decode modulus\n");
423                         exit(1);
424                 }
425         }
426
427         if(mask & 4)
428         {
429                 file2lumps(pubidfile, FOURCC_D0PI, lumps, lumpsize, 1);
430                 if(!d0_blind_id_read_public_id(ctx, lumps[0], lumpsize[0]))
431                 {
432                         fprintf(stderr, "could not decode public ID\n");
433                         exit(1);
434                 }
435         }
436         if(mask & 8)
437         {
438                 file2lumps(prividfile, FOURCC_D0SI, lumps, lumpsize, 1);
439                 if(!d0_blind_id_read_private_id(ctx, lumps[0], lumpsize[0]))
440                 {
441                         fprintf(stderr, "could not decode private ID\n");
442                         exit(1);
443                 }
444         }
445
446         if(mask & 0x10)
447         {
448                 file2lumps(idreqfile, FOURCC_D0IQ, lumps, lumpsize, 1);
449                 lumpsize[1] = sizeof(lumps_w1);
450                 lumps[1] = lumps_w1;
451                 if(!d0_blind_id_answer_private_id_request(ctx, lumps[0], lumpsize[0], lumps_w1, &lumpsize[1]))
452                 {
453                         fprintf(stderr, "could not answer private ID request\n");
454                         exit(1);
455                 }
456         }
457         else if((mask & 0x120) == 0x120)
458         {
459                 file2lumps(camouflagefile, FOURCC_D0IC, lumps, lumpsize, 1);
460                 if(!d0_blind_id_read_private_id_request_camouflage(ctx, lumps[0], lumpsize[0]))
461                 {
462                         fprintf(stderr, "could not decode camouflage\n");
463                         exit(1);
464                 }
465
466                 file2lumps(idresfile, FOURCC_D0IR, lumps, lumpsize, 1);
467                 if(!d0_blind_id_finish_private_id_request(ctx, lumps[0], lumpsize[0]))
468                 {
469                         fprintf(stderr, "could not finish private ID request\n");
470                         exit(1);
471                 }
472         }
473
474         if(mask & 0x400)
475         {
476                 file2buf(datafile, &databuf_in, &databufsize_in);
477                 if(!databuf_in)
478                 {
479                         fprintf(stderr, "could not decode data\n");
480                         exit(1);
481                 }
482         }
483
484         if(mask & 0x800)
485         {
486                 file2buf(sigfile, &databuf_sig, &databufsize_sig);
487                 if(!databuf_sig)
488                 {
489                         fprintf(stderr, "could not decode signature\n");
490                         exit(1);
491                 }
492         }
493
494         switch(mask)
495         {
496                 // modes of operation:
497                 case 0x40:
498                         //   nothing -> private key file (incl modulus), print fingerprint
499                         generated = 0;
500                         generated_offset = 0;
501                         seconds = 0;
502                         signal(SIGALRM, print_generated);
503                         alarm(1);
504                         if(do_fastreject)
505                         {
506                                 CHECK(d0_blind_id_generate_private_key_fastreject(ctx, bits, fastreject, d0_blind_id_fingerprint64_public_key));
507                         }
508                         else
509                         {
510                                 guessfactor = 1; // no fastreject here
511                                 do
512                                 {
513                                         CHECK(d0_blind_id_generate_private_key(ctx, bits));
514                                 }
515                                 while(fastreject(ctx, d0_blind_id_fingerprint64_public_key));
516                         }
517                         alarm(0);
518                         signal(SIGALRM, NULL);
519                         CHECK(d0_blind_id_generate_private_id_modulus(ctx));
520                         lumps[0] = lumps_w0;
521                         lumpsize[0] = sizeof(lumps_w0);
522                         lumps[1] = lumps_w1;
523                         lumpsize[1] = sizeof(lumps_w1);
524                         CHECK(d0_blind_id_write_private_key(ctx, lumps_w0, &lumpsize[0]));
525                         CHECK(d0_blind_id_write_private_id_modulus(ctx, lumps_w1, &lumpsize[1]));
526                         lumps2file(outfile, FOURCC_D0SK, lumps, lumpsize, 2, 1);
527                         break;
528                 case 0x42:
529                         //   private key file -> public key file (incl modulus)
530                         lumps[0] = lumps_w0;
531                         lumpsize[0] = sizeof(lumps_w0);
532                         lumps[1] = lumps_w1;
533                         lumpsize[1] = sizeof(lumps_w1);
534                         CHECK(d0_blind_id_write_public_key(ctx, lumps_w0, &lumpsize[0]));
535                         CHECK(d0_blind_id_write_private_id_modulus(ctx, lumps_w1, &lumpsize[1]));
536                         lumps2file(outfile, FOURCC_D0PK, lumps, lumpsize, 2, 0);
537                         break;
538                 case 0x41:
539                         //   public key file -> unsigned private ID file
540                         generated = 0;
541                         generated_offset = 0;
542                         seconds = 0;
543                         signal(SIGALRM, print_generated);
544                         alarm(1);
545                         guessfactor = 1; // no fastreject here
546                         do
547                         {
548                                 CHECK(d0_blind_id_generate_private_id_start(ctx));
549                         }
550                         while(fastreject(ctx, d0_blind_id_fingerprint64_public_id));
551                         alarm(0);
552                         signal(SIGALRM, 0);
553                         lumps[0] = lumps_w0;
554                         lumpsize[0] = sizeof(lumps_w0);
555                         CHECK(d0_blind_id_write_private_id(ctx, lumps_w0, &lumpsize[0]));
556                         lumps2file(outfile, FOURCC_D0SI, lumps, lumpsize, 1, 1);
557                         break;
558                 case 0xC9:
559                         //   public key file, unsigned private ID file -> ID request file and camouflage file
560                         lumps[0] = lumps_w0;
561                         lumpsize[0] = sizeof(lumps_w0);
562                         CHECK(d0_blind_id_generate_private_id_request(ctx, lumps_w0, &lumpsize[0]));
563                         lumps2file(outfile, FOURCC_D0IQ, lumps, lumpsize, 1, 0);
564                         lumpsize[0] = sizeof(lumps_w0);
565                         CHECK(d0_blind_id_write_private_id_request_camouflage(ctx, lumps_w0, &lumpsize[0]));
566                         lumps2file(outfile2, FOURCC_D0IC, lumps, lumpsize, 1, 1);
567                         break;
568                 case 0x52:
569                         //   private key file, ID request file -> ID response file
570                         lumps2file(outfile, FOURCC_D0IR, lumps+1, lumpsize+1, 1, 0);
571                         break;
572                 case 0x169:
573                         //   public key file, ID response file, private ID file -> signed private ID file
574                         lumps[0] = lumps_w0;
575                         lumpsize[0] = sizeof(lumps_w0);
576                         CHECK(d0_blind_id_write_private_id(ctx, lumps_w0, &lumpsize[0]));
577                         lumps2file(outfile, FOURCC_D0SI, lumps, lumpsize, 1, 1);
578                         break;
579                 case 0x4A:
580                         //   private key file, private ID file -> signed private ID file
581                         {
582                                 char buf[65536]; size_t bufsize;
583                                 char buf2[65536]; size_t buf2size;
584                                 D0_BOOL status;
585                                 d0_blind_id_t *ctx2 = d0_blind_id_new();
586                                 CHECK(d0_blind_id_copy(ctx2, ctx));
587                                 bufsize = sizeof(buf);
588                                 CHECK(d0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize));
589                                 buf2size = sizeof(buf2);
590                                 CHECK(d0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status));
591                                 bufsize = sizeof(buf);
592                                 CHECK(d0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize));
593                                 buf2size = sizeof(buf2);
594                                 CHECK(d0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status));
595                                 CHECK(status == 0);
596                                 CHECK(d0_blind_id_authenticate_with_private_id_generate_missing_signature(ctx2));
597                                 lumps[0] = lumps_w0;
598                                 lumpsize[0] = sizeof(lumps_w0);
599                                 CHECK(d0_blind_id_write_private_id(ctx2, lumps_w0, &lumpsize[0]));
600                                 lumps2file(outfile, FOURCC_D0SI, lumps, lumpsize, 1, 1);
601                         }
602                         break;
603                 case 0x48:
604                         //   private ID file -> public ID file
605                         lumps[0] = lumps_w0;
606                         lumpsize[0] = sizeof(lumps_w0);
607                         CHECK(d0_blind_id_write_public_id(ctx, lumps_w0, &lumpsize[0]));
608                         lumps2file(outfile, FOURCC_D0PI, lumps, lumpsize, 1, 0);
609                         break;
610                 case 0x01:
611                 case 0x02:
612                         //   public/private key file -> fingerprint
613                         CHECK(d0_blind_id_fingerprint64_public_key(ctx, fp64, &fp64size));
614                         printf("%.*s\n", (int)fp64size, fp64);
615                         break;
616                 case 0x05:
617                 case 0x09:
618                         //   public/private ID file -> fingerprint
619                         CHECK(d0_blind_id_fingerprint64_public_id(ctx, fp64, &fp64size));
620                         printf("%.*s\n", (int)fp64size, fp64);
621                         break;
622                 case 0x449:
623                         //   public key, private ID, data -> signed data
624                         databufsize_out = databufsize_in + 8192;
625                         databuf_out = malloc(databufsize_out);
626                         CHECK(d0_blind_id_sign_with_private_id_sign(ctx, 1, 0, databuf_in, databufsize_in, databuf_out, &databufsize_out));
627                         buf2file(outfile, databuf_out, databufsize_out);
628                         break;
629                 case 0x489:
630                         //   public key, private ID, data -> signature
631                         databufsize_out = databufsize_in + 8192;
632                         databuf_out = malloc(databufsize_out);
633                         CHECK(d0_blind_id_sign_with_private_id_sign_detached(ctx, 1, 0, databuf_in, databufsize_in, databuf_out, &databufsize_out));
634                         buf2file(outfile2, databuf_out, databufsize_out);
635                         break;
636                 case 0x841:
637                 case 0x8C1:
638                         //   public key, signed data -> data, optional public ID
639                         {
640                                 D0_BOOL status;
641                                 databufsize_out = databufsize_sig;
642                                 databuf_out = malloc(databufsize_out);
643                                 CHECK(d0_blind_id_sign_with_private_id_verify(ctx, 1, 0, databuf_sig, databufsize_sig, databuf_out, &databufsize_out, &status));
644                                 CHECK(d0_blind_id_fingerprint64_public_id(ctx, fp64, &fp64size));
645                                 printf("%d\n", (int)status);
646                                 printf("%.*s\n", (int)fp64size, fp64);
647                                 buf2file(outfile, databuf_out, databufsize_out);
648
649                                 if(outfile2)
650                                 {
651                                         lumps[0] = lumps_w0;
652                                         lumpsize[0] = sizeof(lumps_w0);
653                                         lumps[1] = lumps_w1;
654                                         lumpsize[1] = sizeof(lumps_w1);
655                                         CHECK(d0_blind_id_write_public_key(ctx, lumps_w0, &lumpsize[0]));
656                                         CHECK(d0_blind_id_write_private_id_modulus(ctx, lumps_w1, &lumpsize[1]));
657                                         lumps2file(outfile2, FOURCC_D0PK, lumps, lumpsize, 2, 0);
658                                 }
659                         }
660                         break;
661                 case 0xC01:
662                 case 0xC81:
663                         //   public key, signature, signed data -> optional public ID
664                         {
665                                 D0_BOOL status;
666                                 CHECK(d0_blind_id_sign_with_private_id_verify_detached(ctx, 1, 0, databuf_sig, databufsize_sig, databuf_in, databufsize_in, &status));
667                                 CHECK(d0_blind_id_fingerprint64_public_id(ctx, fp64, &fp64size));
668                                 printf("%d\n", (int)status);
669                                 printf("%.*s\n", (int)fp64size, fp64);
670                                 buf2file(outfile, databuf_out, databufsize_out);
671
672                                 if(outfile2)
673                                 {
674                                         lumps[0] = lumps_w0;
675                                         lumpsize[0] = sizeof(lumps_w0);
676                                         lumps[1] = lumps_w1;
677                                         lumpsize[1] = sizeof(lumps_w1);
678                                         CHECK(d0_blind_id_write_public_key(ctx, lumps_w0, &lumpsize[0]));
679                                         CHECK(d0_blind_id_write_private_id_modulus(ctx, lumps_w1, &lumpsize[1]));
680                                         lumps2file(outfile2, FOURCC_D0PK, lumps, lumpsize, 2, 0);
681                                 }
682                         }
683                         break;
684 /*
685                 case 0x09:
686                         //   public key, private ID file -> test whether key is properly signed
687                         {
688                                 char buf[65536]; size_t bufsize;
689                                 char buf2[65536]; size_t buf2size;
690                                 D0_BOOL status;
691                                 d0_blind_id_t *ctx2 = d0_blind_id_new();
692                                 CHECK(d0_blind_id_copy(ctx2, ctx));
693                                 bufsize = sizeof(buf);
694                                 CHECK(d0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize));
695                                 buf2size = sizeof(buf2);
696                                 CHECK(d0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status));
697                                 bufsize = sizeof(buf);
698                                 CHECK(d0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize));
699                                 buf2size = sizeof(buf2);
700                                 CHECK(d0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status));
701                                 if(status)
702                                         printf("OK\n");
703                                 else
704                                         printf("EPIC FAIL\n");
705                         }
706                         break;
707 */
708                 case 0x209:
709                         // protocol client
710                         {
711                                 char hexbuf[131073];
712                                 const char hex[] = "0123456789abcdef";
713                                 char buf[65536]; size_t bufsize;
714                                 char buf2[65536]; size_t buf2size;
715                                 bufsize = sizeof(buf);
716                                 CHECK(d0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize));
717                                 for(i = 0; i < (int)bufsize; ++i)
718                                         sprintf(&hexbuf[2*i], "%02x", (unsigned char)buf[i]);
719                                 printf("%s\n", hexbuf);
720                                 fgets(hexbuf, sizeof(hexbuf), stdin);
721                                 buf2size = strlen(hexbuf) / 2;
722                                 for(i = 0; i < (int)buf2size; ++i)
723                                         buf2[i] = ((strchr(hex, hexbuf[2*i]) - hex) << 4) | (strchr(hex, hexbuf[2*i+1]) - hex);
724                                 bufsize = sizeof(buf);
725                                 CHECK(d0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize));
726                                 for(i = 0; i < (int)bufsize; ++i)
727                                         sprintf(&hexbuf[2*i], "%02x", (unsigned char)buf[i]);
728                                 printf("%s\n", hexbuf);
729                         }
730                         break;
731                 case 0x201:
732                         // protocol server
733                         {
734                                 char hexbuf[131073];
735                                 const char hex[] = "0123456789abcdef";
736                                 char buf[65536]; size_t bufsize;
737                                 char buf2[65536]; size_t buf2size;
738                                 D0_BOOL status;
739                                 fgets(hexbuf, sizeof(hexbuf), stdin);
740                                 buf2size = strlen(hexbuf) / 2;
741                                 for(i = 0; i < (int)buf2size; ++i)
742                                         buf2[i] = ((strchr(hex, hexbuf[2*i]) - hex) << 4) | (strchr(hex, hexbuf[2*i+1]) - hex);
743                                 bufsize = sizeof(buf);
744                                 CHECK(d0_blind_id_authenticate_with_private_id_challenge(ctx, 1, 1, buf2, buf2size, buf, &bufsize, &status));
745                                 for(i = 0; i < (int)bufsize; ++i)
746                                         sprintf(&hexbuf[2*i], "%02x", (unsigned char)buf[i]);
747                                 printf("%s\n", hexbuf);
748                                 fgets(hexbuf, sizeof(hexbuf), stdin);
749                                 buf2size = strlen(hexbuf) / 2;
750                                 for(i = 0; i < (int)buf2size; ++i)
751                                         buf2[i] = ((strchr(hex, hexbuf[2*i]) - hex) << 4) | (strchr(hex, hexbuf[2*i+1]) - hex);
752                                 bufsize = sizeof(buf);
753                                 CHECK(d0_blind_id_authenticate_with_private_id_verify(ctx, buf2, buf2size, buf, &bufsize, &status));
754                                 printf("verify status: %d\n", status);
755
756                                 CHECK(d0_blind_id_fingerprint64_public_id(ctx, fp64, &fp64size));
757                                 printf("%.*s\n", (int)fp64size, fp64);
758                         }
759                         break;
760                 default:
761                         USAGE(*argv);
762                         exit(1);
763                         break;
764         }
765         d0_blind_id_SHUTDOWN();
766         return 0;
767 }