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