int main(int ac, char** av) { int r = -1; uint8_t pk[edsign_PUBLICKEYBYTES]; uint8_t sk[edsign_SECRETKEYBYTES]; uint8_t sig[edsign_sign_BYTES]; uint8_t* pass; uint64_t passlen; if (ac < 2) { pass = NULL; passlen = 0; } else { pass = (uint8_t*)av[1]; passlen = strlen(av[1]); } uint8_t* msg = (uint8_t*)"Hello world!"; edsign_keypair(pass, passlen, 14, 8, 1, pk, sk); edsign_sign(pass, passlen, sk, msg, 12, sig); r = edsign_verify(pk, sig, msg, 12); printf("result: %s\n", (r == 0) ? "OK" : "FAIL"); return r; }
static int sign(const char *msgfile) { struct seckey skey; struct sig sig = { .pkalg = "Ed", }; struct stat st; char buf[512]; void *pubkey = buf; long mlen; void *m; int mfd; if (!get_base64_file(seckeyfile, &skey, sizeof(skey), buf, sizeof(buf)) || memcmp(skey.pkalg, "Ed", 2) != 0) { fprintf(stderr, "Failed to decode secret key\n"); return 1; } if (skey.kdfrounds) { fprintf(stderr, "Password protected secret keys are not supported\n"); return 1; } mfd = open(msgfile, O_RDONLY, 0); if (mfd < 0 || fstat(mfd, &st) < 0 || (m = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, mfd, 0)) == MAP_FAILED) { if (mfd >= 0) close(mfd); perror("Cannot open message file"); return 1; } mlen = st.st_size; memcpy(sig.fingerprint, skey.fingerprint, sizeof(sig.fingerprint)); edsign_sec_to_pub(pubkey, skey.seckey); edsign_sign(sig.sig, pubkey, skey.seckey, m, mlen); munmap(m, mlen); close(mfd); if (b64_encode(&sig, sizeof(sig), buf, sizeof(buf)) < 0) return 1; write_file(sigfile, sig.fingerprint, "signed by key", buf); return 0; } static int fingerprint(void) { struct seckey skey; struct pubkey pkey; struct sig sig; char buf[512]; uint8_t *fp; if (seckeyfile && get_base64_file(seckeyfile, &skey, sizeof(skey), buf, sizeof(buf))) fp = skey.fingerprint; else if (pubkeyfile && get_base64_file(pubkeyfile, &pkey, sizeof(pkey), buf, sizeof(buf))) fp = pkey.fingerprint; else if (sigfile && get_base64_file(sigfile, &sig, sizeof(sig), buf, sizeof(buf))) fp = sig.fingerprint; else return 1; fprintf(stdout, "%"PRIx64"\n", fingerprint_u64(fp)); return 0; } static int generate(void) { struct seckey skey = { .pkalg = "Ed", .kdfalg = "BK", .kdfrounds = 0, }; struct pubkey pkey = { .pkalg = "Ed", }; struct sha512_state s; char buf[512]; FILE *f; f = fopen("/dev/urandom", "r"); if (!f || fread(skey.fingerprint, sizeof(skey.fingerprint), 1, f) != 1 || fread(skey.seckey, EDSIGN_SECRET_KEY_SIZE, 1, f) != 1 || fread(skey.salt, sizeof(skey.salt), 1, f) != 1) { fprintf(stderr, "Can't read data from /dev/urandom\n"); return 1; } if (f) fclose(f); ed25519_prepare(skey.seckey); edsign_sec_to_pub(skey.seckey + 32, skey.seckey); sha512_init(&s); sha512_add(&s, skey.seckey, sizeof(skey.seckey)); memcpy(skey.checksum, sha512_final_get(&s), sizeof(skey.checksum)); if (b64_encode(&skey, sizeof(skey), buf, sizeof(buf)) < 0) return 1; write_file(seckeyfile, skey.fingerprint, "public key", buf); memcpy(pkey.fingerprint, skey.fingerprint, sizeof(pkey.fingerprint)); memcpy(pkey.pubkey, skey.seckey + 32, sizeof(pkey.pubkey)); if (b64_encode(&pkey, sizeof(pkey), buf, sizeof(buf)) < 0) return 1; write_file(pubkeyfile, pkey.fingerprint, "private key", buf); return 0; } static int usage(const char *cmd) { fprintf(stderr, "Usage: %s <command> <options>\n" "Commands:\n" " -V: verify (needs at least -m and -p|-P)\n" " -S: sign (needs at least -m and -s)\n" " -F: print key fingerprint of public/secret key or signature\n" " -G: generate a new keypair\n" "Options:\n" " -c <comment>: add comment to keys\n" " -m <file>: message file\n" " -p <file>: public key file (verify/fingerprint only)\n" " -P <path>: public key directory (verify only)\n" " -q: quiet (do not print verification result, use return code only)\n" " -s <file>: secret key file (sign/fingerprint only)\n" " -x <file>: signature file (defaults to <message file>.sig)\n" "\n", cmd); return 1; } static void set_cmd(const char *prog, int val) { if (cmd != CMD_NONE) exit(usage(prog)); cmd = val; } int main(int argc, char **argv) { const char *msgfile = NULL; int ch; while ((ch = getopt(argc, argv, "FGSVc:m:P:p:qs:x:")) != -1) { switch (ch) { case 'V': set_cmd(argv[0], CMD_VERIFY); break; case 'S': set_cmd(argv[0], CMD_SIGN); break; case 'F': set_cmd(argv[0], CMD_FINGERPRINT); break; case 'G': set_cmd(argv[0], CMD_GENERATE); break; case 'c': comment = optarg; break; case 'm': msgfile = optarg; break; case 'P': pubkeydir = optarg; break; case 'p': pubkeyfile = optarg; break; case 's': seckeyfile = optarg; break; case 'x': sigfile = optarg; break; case 'q': quiet = true; break; default: return usage(argv[0]); } } if (!sigfile && msgfile) { char *buf = alloca(strlen(msgfile) + 5); if (!strcmp(msgfile, "-")) { fprintf(stderr, "Need signature file when reading message from stdin\n"); return 1; } sprintf(buf, "%s.sig", msgfile); sigfile = buf; } switch (cmd) { case CMD_VERIFY: if ((!pubkeyfile && !pubkeydir) || !msgfile) return usage(argv[0]); return verify(msgfile); case CMD_SIGN: if (!seckeyfile || !msgfile || !sigfile) return usage(argv[0]); return sign(msgfile); case CMD_FINGERPRINT: if (!!seckeyfile + !!pubkeyfile + !!sigfile != 1) { fprintf(stderr, "Need one secret/public key or signature\n"); return usage(argv[0]); } return fingerprint(); case CMD_GENERATE: if (!seckeyfile || !pubkeyfile) return usage(argv[0]); return generate(); default: return usage(argv[0]); } }