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