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