#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include // BEGIN stuff shared with crypto.c #define FOURCC_D0PK (('d' << 0) | ('0' << 8) | ('p' << 16) | ('k' << 24)) #define FOURCC_D0SK (('d' << 0) | ('0' << 8) | ('s' << 16) | ('k' << 24)) #define FOURCC_D0PI (('d' << 0) | ('0' << 8) | ('p' << 16) | ('i' << 24)) #define FOURCC_D0SI (('d' << 0) | ('0' << 8) | ('s' << 16) | ('i' << 24)) #define FOURCC_D0IQ (('d' << 0) | ('0' << 8) | ('i' << 16) | ('q' << 24)) #define FOURCC_D0IR (('d' << 0) | ('0' << 8) | ('i' << 16) | ('r' << 24)) #define FOURCC_D0ER (('d' << 0) | ('0' << 8) | ('e' << 16) | ('r' << 24)) #define FOURCC_D0IC (('d' << 0) | ('0' << 8) | ('i' << 16) | ('c' << 24)) static unsigned long Crypto_LittleLong(const char *data) { return ((unsigned char) data[0]) | (((unsigned char) data[1]) << 8) | (((unsigned char) data[2]) << 16) | (((unsigned char) data[3]) << 24); } static void Crypto_UnLittleLong(char *data, unsigned long l) { data[0] = l & 0xFF; data[1] = (l >> 8) & 0xFF; data[2] = (l >> 16) & 0xFF; data[3] = (l >> 24) & 0xFF; } static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps) { size_t i; size_t pos; pos = 0; if(header) { if(len < 4) return 0; if(Crypto_LittleLong(buf) != header) return 0; pos += 4; } for(i = 0; i < nlumps; ++i) { if(pos + 4 > len) return 0; lumpsize[i] = Crypto_LittleLong(&buf[pos]); pos += 4; if(pos + lumpsize[i] > len) return 0; lumps[i] = &buf[pos]; pos += lumpsize[i]; } return pos; } static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, const char *const *lumps, const size_t *lumpsize, size_t nlumps) { size_t i; size_t pos; pos = 0; if(header) { if(len < 4) return 0; Crypto_UnLittleLong(buf, header); pos += 4; } for(i = 0; i < nlumps; ++i) { if(pos + 4 + lumpsize[i] > len) return 0; Crypto_UnLittleLong(&buf[pos], lumpsize[i]); pos += 4; memcpy(&buf[pos], lumps[i], lumpsize[i]); pos += lumpsize[i]; } return pos; } void file2buf(const char *fn, char **data, size_t *datasize) { FILE *f; *data = NULL; *datasize = 0; size_t n = 0, dn = 0; if(!strncmp(fn, "/dev/fd/", 8)) f = fdopen(atoi(fn + 8), "rb"); else f = fopen(fn, "rb"); if(!f) { return; } for(;;) { *data = realloc(*data, *datasize += 8192); if(!*data) { *datasize = 0; fclose(f); return; } dn = fread(*data + n, 1, *datasize - n, f); if(!dn) break; n += dn; } fclose(f); *datasize = n; } int buf2file(const char *fn, const char *data, size_t n) { FILE *f; if(!strncmp(fn, "/dev/fd/", 8)) f = fdopen(atoi(fn + 8), "wb"); else f = fopen(fn, "wb"); if(!f) return 0; n = fwrite(data, n, 1, f); if(fclose(f) || !n) return 0; return 1; } void file2lumps(const char *fn, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps) { char *buf; size_t n; file2buf(fn, &buf, &n); if(!buf) { fprintf(stderr, "could not open %s\n", fn); exit(1); } if(!Crypto_ParsePack(buf, n, header, lumps, lumpsize, nlumps)) { 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); free(buf); exit(1); } free(buf); } mode_t umask_save; void lumps2file(const char *fn, unsigned long header, const char *const *lumps, size_t *lumpsize, size_t nlumps, D0_BOOL private) { char buf[65536]; size_t n; if(private) umask(umask_save | 0077); else umask(umask_save); if(!(n = Crypto_UnParsePack(buf, sizeof(buf), header, lumps, lumpsize, nlumps))) { fprintf(stderr, "could not unparse for %s\n", fn); exit(1); } if(!buf2file(fn, buf, n)) { fprintf(stderr, "could not write %s\n", fn); exit(1); } } void USAGE(const char *me) { printf("Usage:\n" "%s [-F] [-b bits] [-n progress-denominator] [-x prefix] [-X infix] [-C] -o private.d0sk\n" "%s -P private.d0sk -o public.d0pk\n" "%s [-n progress-denominator] [-x prefix] [-X infix] [-C] -p public.d0pk -o idkey-unsigned.d0si\n" "%s -p public.d0pk -I idkey-unsigned.d0si -o request.d0iq -O camouflage.d0ic\n" "%s -P private.d0sk -j request.d0iq -o response.d0ir\n" "%s -p public.d0pk -I idkey-unsigned.d0si -c camouflage.d0ic -J response.d0ir -o idkey.d0si\n" "%s -P private.d0sk -I idkey-unsigned.d0si -o idkey.d0si\n" "%s -I idkey.d0si -o id.d0pi\n" "%s -p public.d0pk\n" "%s -P private.d0sk\n" "%s -p public.d0pk -i id.d0pi\n" "%s -p public.d0pk -I idkey.d0si\n" "%s -0 -p public.d0pk -I idkey.d0si\n" "%s -0 -p public.d0pk\n" "%s -p public.d0pk -I idkey.d0si -d file-to-sign.dat -o file-signed.dat\n" "%s -p public.d0pk -s file-signed.dat -o file-content.dat [-O id.d0pi]\n" "%s -p public.d0pk -I idkey.d0si -d file-to-sign.dat -O signature.dat\n" "%s -p public.d0pk -d file-to-sign.dat -s signature.dat [-O id.d0pi]\n", me, me, me, me, me, me, me, me, me, me, me, me, me, me, me, me, me, me ); } unsigned int seconds; unsigned int generated; unsigned int ntasks = 1; double generated_offset; double guesscount; double guessfactor; void print_generated(int signo) { (void) signo; ++seconds; if(generated >= 1000000000) { generated_offset += generated; generated = 0; } fprintf(stderr, "Generated: %.0f (about %.0f, %.1f/s, about %.2f hours for %.0f)\n", // nasty and dishonest hack: // we are adjusting the values "back", so the total count is // divided by guessfactor (as the check function is called // guessfactor as often as it would be if no fastreject were // done) // so the values indicate the relative speed of fastreject vs // normal! (generated + generated_offset) / guessfactor, (generated + generated_offset) * ntasks / guessfactor, (generated + generated_offset) * ntasks / (guessfactor * seconds), guesscount * ((guessfactor * seconds) / (generated + generated_offset) / ntasks) / 3600.0, guesscount); alarm(1); } #define CHECK(x) if(!(x)) { fprintf(stderr, "error exit: error returned by %s\n", #x); exit(2); } const char *prefix = NULL, *infix = NULL; size_t prefixlen = 0; int ignorecase; typedef D0_BOOL (*fingerprint_func) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); D0_BOOL fastreject(const d0_blind_id_t *ctx, void *pass) { static char fp64[513]; size_t fp64size = 512; CHECK(((fingerprint_func) pass)(ctx, fp64, &fp64size)); ++generated; if(ignorecase) { if(prefixlen) if(strncasecmp(fp64, prefix, prefixlen)) return 1; if(infix) { fp64[fp64size] = 0; if(!strcasestr(fp64, infix)) return 1; } } else { if(prefixlen) if(memcmp(fp64, prefix, prefixlen)) return 1; if(infix) { fp64[fp64size] = 0; if(!strstr(fp64, infix)) return 1; } } return 0; } int main(int argc, char **argv) { int opt; size_t lumpsize[2]; const char *lumps[2]; char *databuf_in; size_t databufsize_in; char *databuf_out; size_t databufsize_out; char *databuf_sig; size_t databufsize_sig; char lumps_w0[65536]; char lumps_w1[65536]; const char *pubkeyfile = NULL, *privkeyfile = NULL, *pubidfile = NULL, *prividfile = NULL, *idreqfile = NULL, *idresfile = NULL, *outfile = NULL, *outfile2 = NULL, *camouflagefile = NULL, *datafile = NULL, *sigfile = NULL; char fp64[513]; size_t fp64size = 512; int mask = 0; int bits = 1024; int i; D0_BOOL do_fastreject = 1; d0_blind_id_t *ctx; if(!d0_blind_id_INITIALIZE()) { fprintf(stderr, "could not initialize\n"); exit(1); } umask_save = umask(0022); ctx = d0_blind_id_new(); while((opt = getopt(argc, argv, "d:s:p:P:i:I:j:J:o:O:c:b:x:X:y:Fn:C0")) != -1) { switch(opt) { case 'C': ignorecase = 1; break; case 'n': ntasks = atoi(optarg); break; case 'b': bits = atoi(optarg); break; case 'p': // d0pk = pubkeyfile = optarg; mask |= 1; break; case 'P': // d0sk = privkeyfile = optarg; mask |= 2; break; case 'i': // d0pi = pubidfile = optarg; mask |= 4; break; case 'I': // d0si = prividfile = optarg; mask |= 8; break; case 'j': // d0iq = idreqfile = optarg; mask |= 0x10; break; case 'J': // d0ir = idresfile = optarg; mask |= 0x20; break; case 'o': outfile = optarg; mask |= 0x40; break; case 'O': outfile2 = optarg; mask |= 0x80; break; case 'c': camouflagefile = optarg; mask |= 0x100; break; case 'x': prefix = optarg; prefixlen = strlen(prefix); break; case '0': // test mode mask |= 0x200; break; case 'd': datafile = optarg; mask |= 0x400; break; case 's': sigfile = optarg; mask |= 0x800; break; case 'X': infix = optarg; break; case 'F': do_fastreject = 0; break; default: USAGE(*argv); return 1; } } // fastreject is a slight slowdown when rejecting nothing at all if(!infix && !prefixlen) do_fastreject = 0; guesscount = pow(64.0, prefixlen); if(infix) guesscount /= (1 - pow(1 - pow(1/64.0, strlen(infix)), 44 - prefixlen - strlen(infix))); // 44 chars; prefix is assumed to not match the infix (although it theoretically could) // 43'th char however is always '=' and does not count if(ignorecase) { if(infix) for(i = 0; infix[i]; ++i) if(toupper(infix[i]) != tolower(infix[i])) guesscount /= 2; for(i = 0; i < (int)prefixlen; ++i) if(toupper(prefix[i]) != tolower(prefix[i])) guesscount /= 2; } if(do_fastreject) { // fastreject: reject function gets called about log(2^bits) times more often guessfactor = bits * log(2) / 2; // so guess function gets called guesscount * guessfactor times, and it tests as many valid keys as guesscount } if(mask & 1) { file2lumps(pubkeyfile, FOURCC_D0PK, lumps, lumpsize, 2); if(!d0_blind_id_read_public_key(ctx, lumps[0], lumpsize[0])) { fprintf(stderr, "could not decode public key\n"); exit(1); } if(!d0_blind_id_read_private_id_modulus(ctx, lumps[1], lumpsize[1])) { fprintf(stderr, "could not decode modulus\n"); exit(1); } } else if(mask & 2) { file2lumps(privkeyfile, FOURCC_D0SK, lumps, lumpsize, 2); if(!d0_blind_id_read_private_key(ctx, lumps[0], lumpsize[0])) { fprintf(stderr, "could not decode private key\n"); exit(1); } if(!d0_blind_id_read_private_id_modulus(ctx, lumps[1], lumpsize[1])) { fprintf(stderr, "could not decode modulus\n"); exit(1); } } if(mask & 4) { file2lumps(pubidfile, FOURCC_D0PI, lumps, lumpsize, 1); if(!d0_blind_id_read_public_id(ctx, lumps[0], lumpsize[0])) { fprintf(stderr, "could not decode public ID\n"); exit(1); } } if(mask & 8) { file2lumps(prividfile, FOURCC_D0SI, lumps, lumpsize, 1); if(!d0_blind_id_read_private_id(ctx, lumps[0], lumpsize[0])) { fprintf(stderr, "could not decode private ID\n"); exit(1); } } if(mask & 0x10) { file2lumps(idreqfile, FOURCC_D0IQ, lumps, lumpsize, 1); lumpsize[1] = sizeof(lumps_w1); lumps[1] = lumps_w1; if(!d0_blind_id_answer_private_id_request(ctx, lumps[0], lumpsize[0], lumps_w1, &lumpsize[1])) { fprintf(stderr, "could not answer private ID request\n"); exit(1); } } else if((mask & 0x120) == 0x120) { file2lumps(camouflagefile, FOURCC_D0IC, lumps, lumpsize, 1); if(!d0_blind_id_read_private_id_request_camouflage(ctx, lumps[0], lumpsize[0])) { fprintf(stderr, "could not decode camouflage\n"); exit(1); } file2lumps(idresfile, FOURCC_D0IR, lumps, lumpsize, 1); if(!d0_blind_id_finish_private_id_request(ctx, lumps[0], lumpsize[0])) { fprintf(stderr, "could not finish private ID request\n"); exit(1); } } if(mask & 0x400) { file2buf(datafile, &databuf_in, &databufsize_in); if(!databuf_in) { fprintf(stderr, "could not decode data\n"); exit(1); } } if(mask & 0x800) { file2buf(sigfile, &databuf_sig, &databufsize_sig); if(!databuf_sig) { fprintf(stderr, "could not decode signature\n"); exit(1); } } switch(mask) { // modes of operation: case 0x40: // nothing -> private key file (incl modulus), print fingerprint generated = 0; generated_offset = 0; seconds = 0; signal(SIGALRM, print_generated); alarm(1); if(do_fastreject) { CHECK(d0_blind_id_generate_private_key_fastreject(ctx, bits, fastreject, d0_blind_id_fingerprint64_public_key)); } else { guessfactor = 1; // no fastreject here do { CHECK(d0_blind_id_generate_private_key(ctx, bits)); } while(fastreject(ctx, d0_blind_id_fingerprint64_public_key)); } alarm(0); signal(SIGALRM, NULL); CHECK(d0_blind_id_generate_private_id_modulus(ctx)); lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); lumps[1] = lumps_w1; lumpsize[1] = sizeof(lumps_w1); CHECK(d0_blind_id_write_private_key(ctx, lumps_w0, &lumpsize[0])); CHECK(d0_blind_id_write_private_id_modulus(ctx, lumps_w1, &lumpsize[1])); lumps2file(outfile, FOURCC_D0SK, lumps, lumpsize, 2, 1); break; case 0x42: // private key file -> public key file (incl modulus) lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); lumps[1] = lumps_w1; lumpsize[1] = sizeof(lumps_w1); CHECK(d0_blind_id_write_public_key(ctx, lumps_w0, &lumpsize[0])); CHECK(d0_blind_id_write_private_id_modulus(ctx, lumps_w1, &lumpsize[1])); lumps2file(outfile, FOURCC_D0PK, lumps, lumpsize, 2, 0); break; case 0x41: // public key file -> unsigned private ID file generated = 0; generated_offset = 0; seconds = 0; signal(SIGALRM, print_generated); alarm(1); guessfactor = 1; // no fastreject here do { CHECK(d0_blind_id_generate_private_id_start(ctx)); } while(fastreject(ctx, d0_blind_id_fingerprint64_public_id)); alarm(0); signal(SIGALRM, 0); lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); CHECK(d0_blind_id_write_private_id(ctx, lumps_w0, &lumpsize[0])); lumps2file(outfile, FOURCC_D0SI, lumps, lumpsize, 1, 1); break; case 0xC9: // public key file, unsigned private ID file -> ID request file and camouflage file lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); CHECK(d0_blind_id_generate_private_id_request(ctx, lumps_w0, &lumpsize[0])); lumps2file(outfile, FOURCC_D0IQ, lumps, lumpsize, 1, 0); lumpsize[0] = sizeof(lumps_w0); CHECK(d0_blind_id_write_private_id_request_camouflage(ctx, lumps_w0, &lumpsize[0])); lumps2file(outfile2, FOURCC_D0IC, lumps, lumpsize, 1, 1); break; case 0x52: // private key file, ID request file -> ID response file lumps2file(outfile, FOURCC_D0IR, lumps+1, lumpsize+1, 1, 0); break; case 0x169: // public key file, ID response file, private ID file -> signed private ID file lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); CHECK(d0_blind_id_write_private_id(ctx, lumps_w0, &lumpsize[0])); lumps2file(outfile, FOURCC_D0SI, lumps, lumpsize, 1, 1); break; case 0x4A: // private key file, private ID file -> signed private ID file { char buf[65536]; size_t bufsize; char buf2[65536]; size_t buf2size; D0_BOOL status; d0_blind_id_t *ctx2 = d0_blind_id_new(); CHECK(d0_blind_id_copy(ctx2, ctx)); bufsize = sizeof(buf); CHECK(d0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize)); buf2size = sizeof(buf2); CHECK(d0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status)); bufsize = sizeof(buf); CHECK(d0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize)); buf2size = sizeof(buf2); CHECK(d0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status)); CHECK(status == 0); CHECK(d0_blind_id_authenticate_with_private_id_generate_missing_signature(ctx2)); lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); CHECK(d0_blind_id_write_private_id(ctx2, lumps_w0, &lumpsize[0])); lumps2file(outfile, FOURCC_D0SI, lumps, lumpsize, 1, 1); } break; case 0x48: // private ID file -> public ID file lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); CHECK(d0_blind_id_write_public_id(ctx, lumps_w0, &lumpsize[0])); lumps2file(outfile, FOURCC_D0PI, lumps, lumpsize, 1, 0); break; case 0x01: case 0x02: // public/private key file -> fingerprint CHECK(d0_blind_id_fingerprint64_public_key(ctx, fp64, &fp64size)); printf("%.*s\n", (int)fp64size, fp64); break; case 0x05: case 0x09: // public/private ID file -> fingerprint CHECK(d0_blind_id_fingerprint64_public_id(ctx, fp64, &fp64size)); printf("%.*s\n", (int)fp64size, fp64); break; case 0x449: // public key, private ID, data -> signed data databufsize_out = databufsize_in + 8192; databuf_out = malloc(databufsize_out); CHECK(d0_blind_id_sign_with_private_id_sign(ctx, 1, 0, databuf_in, databufsize_in, databuf_out, &databufsize_out)); buf2file(outfile, databuf_out, databufsize_out); break; case 0x489: // public key, private ID, data -> signature databufsize_out = databufsize_in + 8192; databuf_out = malloc(databufsize_out); CHECK(d0_blind_id_sign_with_private_id_sign_detached(ctx, 1, 0, databuf_in, databufsize_in, databuf_out, &databufsize_out)); buf2file(outfile2, databuf_out, databufsize_out); break; case 0x841: case 0x8C1: // public key, signed data -> data, optional public ID { D0_BOOL status; databufsize_out = databufsize_sig; databuf_out = malloc(databufsize_out); CHECK(d0_blind_id_sign_with_private_id_verify(ctx, 1, 0, databuf_sig, databufsize_sig, databuf_out, &databufsize_out, &status)); CHECK(d0_blind_id_fingerprint64_public_id(ctx, fp64, &fp64size)); printf("%d\n", (int)status); printf("%.*s\n", (int)fp64size, fp64); buf2file(outfile, databuf_out, databufsize_out); if(outfile2) { lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); lumps[1] = lumps_w1; lumpsize[1] = sizeof(lumps_w1); CHECK(d0_blind_id_write_public_key(ctx, lumps_w0, &lumpsize[0])); CHECK(d0_blind_id_write_private_id_modulus(ctx, lumps_w1, &lumpsize[1])); lumps2file(outfile2, FOURCC_D0PK, lumps, lumpsize, 2, 0); } } break; case 0xC01: case 0xC81: // public key, signature, signed data -> optional public ID { D0_BOOL status; CHECK(d0_blind_id_sign_with_private_id_verify_detached(ctx, 1, 0, databuf_sig, databufsize_sig, databuf_in, databufsize_in, &status)); CHECK(d0_blind_id_fingerprint64_public_id(ctx, fp64, &fp64size)); printf("%d\n", (int)status); printf("%.*s\n", (int)fp64size, fp64); if(outfile2) { lumps[0] = lumps_w0; lumpsize[0] = sizeof(lumps_w0); lumps[1] = lumps_w1; lumpsize[1] = sizeof(lumps_w1); CHECK(d0_blind_id_write_public_key(ctx, lumps_w0, &lumpsize[0])); CHECK(d0_blind_id_write_private_id_modulus(ctx, lumps_w1, &lumpsize[1])); lumps2file(outfile2, FOURCC_D0PK, lumps, lumpsize, 2, 0); } } break; /* case 0x09: // public key, private ID file -> test whether key is properly signed { char buf[65536]; size_t bufsize; char buf2[65536]; size_t buf2size; D0_BOOL status; d0_blind_id_t *ctx2 = d0_blind_id_new(); CHECK(d0_blind_id_copy(ctx2, ctx)); bufsize = sizeof(buf); CHECK(d0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize)); buf2size = sizeof(buf2); CHECK(d0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status)); bufsize = sizeof(buf); CHECK(d0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize)); buf2size = sizeof(buf2); CHECK(d0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status)); if(status) printf("OK\n"); else printf("EPIC FAIL\n"); } break; */ case 0x209: // protocol client { char hexbuf[131073]; const char hex[] = "0123456789abcdef"; char buf[65536]; size_t bufsize; char buf2[65536]; size_t buf2size; bufsize = sizeof(buf); CHECK(d0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize)); for(i = 0; i < (int)bufsize; ++i) sprintf(&hexbuf[2*i], "%02x", (unsigned char)buf[i]); printf("%s\n", hexbuf); fgets(hexbuf, sizeof(hexbuf), stdin); buf2size = strlen(hexbuf) / 2; for(i = 0; i < (int)buf2size; ++i) buf2[i] = ((strchr(hex, hexbuf[2*i]) - hex) << 4) | (strchr(hex, hexbuf[2*i+1]) - hex); bufsize = sizeof(buf); CHECK(d0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize)); for(i = 0; i < (int)bufsize; ++i) sprintf(&hexbuf[2*i], "%02x", (unsigned char)buf[i]); printf("%s\n", hexbuf); } break; case 0x201: // protocol server { char hexbuf[131073]; const char hex[] = "0123456789abcdef"; char buf[65536]; size_t bufsize; char buf2[65536]; size_t buf2size; D0_BOOL status; fgets(hexbuf, sizeof(hexbuf), stdin); buf2size = strlen(hexbuf) / 2; for(i = 0; i < (int)buf2size; ++i) buf2[i] = ((strchr(hex, hexbuf[2*i]) - hex) << 4) | (strchr(hex, hexbuf[2*i+1]) - hex); bufsize = sizeof(buf); CHECK(d0_blind_id_authenticate_with_private_id_challenge(ctx, 1, 1, buf2, buf2size, buf, &bufsize, &status)); for(i = 0; i < (int)bufsize; ++i) sprintf(&hexbuf[2*i], "%02x", (unsigned char)buf[i]); printf("%s\n", hexbuf); fgets(hexbuf, sizeof(hexbuf), stdin); buf2size = strlen(hexbuf) / 2; for(i = 0; i < (int)buf2size; ++i) buf2[i] = ((strchr(hex, hexbuf[2*i]) - hex) << 4) | (strchr(hex, hexbuf[2*i+1]) - hex); bufsize = sizeof(buf); CHECK(d0_blind_id_authenticate_with_private_id_verify(ctx, buf2, buf2size, buf, &bufsize, &status)); printf("verify status: %d\n", status); CHECK(d0_blind_id_fingerprint64_public_id(ctx, fp64, &fp64size)); printf("%.*s\n", (int)fp64size, fp64); } break; default: USAGE(*argv); exit(1); break; } d0_blind_id_SHUTDOWN(); return 0; }