|
2 | 2 | #include "onion_key.h" |
3 | 3 | #include "secp256k1.h" |
4 | 4 | #include "secp256k1_ecdh.h" |
| 5 | +#include "version.h" |
5 | 6 | #include <openssl/hmac.h> |
6 | 7 | #include <openssl/evp.h> |
7 | 8 | #include <openssl/aes.h> |
|
15 | 16 | #include <ccan/mem/mem.h> |
16 | 17 | #include <ccan/crypto/sha256/sha256.h> |
17 | 18 | #include <ccan/endian/endian.h> |
| 19 | +#include <ccan/read_write_all/read_write_all.h> |
| 20 | +#include <ccan/opt/opt.h> |
| 21 | +#include <ccan/str/hex/hex.h> |
18 | 22 |
|
19 | 23 | /* |
20 | 24 | * The client knows the server's public key S (which has corresponding |
@@ -581,51 +585,102 @@ bool peel_onion(struct onion *onion, |
581 | 585 | sizeof(onion->hop[0]), enckey, pad_iv); |
582 | 586 | } |
583 | 587 |
|
| 588 | +static bool parse_onion_pubkey(secp256k1_context *ctx, |
| 589 | + const char *arg, secp256k1_pubkey *pubkey) |
| 590 | +{ |
| 591 | + unsigned char tmp[33] = { 0x2 }; |
| 592 | + |
| 593 | + if (!hex_decode(arg, strlen(arg), tmp + 1, sizeof(tmp) - 1)) |
| 594 | + return false; |
| 595 | + |
| 596 | + return secp256k1_ec_pubkey_parse(ctx, pubkey, tmp, sizeof(tmp)); |
| 597 | +} |
| 598 | + |
| 599 | +static char *make_message(const secp256k1_pubkey *pubkey) |
| 600 | +{ |
| 601 | + char *m; |
| 602 | + char hexstr[hex_str_size(20)]; |
| 603 | + |
| 604 | + hex_encode(pubkey, 20, hexstr, sizeof(hexstr)); |
| 605 | + asprintf(&m, "Message for %s...", hexstr); |
| 606 | + return m; |
| 607 | +} |
| 608 | + |
584 | 609 | int main(int argc, char *argv[]) |
585 | 610 | { |
586 | 611 | secp256k1_context *ctx; |
587 | | - size_t i, hops; |
588 | | - struct seckey seckeys[MAX_HOPS]; |
589 | | - secp256k1_pubkey pubkeys[MAX_HOPS]; |
590 | | - char *msgs[MAX_HOPS]; |
591 | 612 | struct onion onion; |
| 613 | + bool generate = false, decode = false; |
592 | 614 |
|
593 | 615 | assert(EVP_CIPHER_iv_length(EVP_aes_128_ctr()) == sizeof(struct iv)); |
594 | 616 |
|
595 | | - if (argc != 2) |
596 | | - errx(1, "Usage: %s <num hops>", argv[0]); |
597 | | - hops = atoi(argv[1]); |
598 | | - if (hops == 0 || hops > MAX_HOPS) |
599 | | - errx(1, "%s is invalid number of hops", argv[1]); |
600 | | - |
601 | | - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); |
602 | | - for (i = 0; i < hops; i++) { |
603 | | - asprintf(&msgs[i], "Message to %zu", i); |
604 | | - random_key(ctx, &seckeys[i], &pubkeys[i]); |
605 | | - printf(" * Keypair %zu:", i); |
606 | | - dump_hex(seckeys[i]); |
607 | | - dump_pkey(ctx, pubkeys[i]); |
608 | | - printf("\n"); |
609 | | - } |
| 617 | + opt_register_noarg("--help|-h", opt_usage_and_exit, |
| 618 | + "--generate <pubkey>... OR\n" |
| 619 | + "--decode <privkey>\n" |
| 620 | + "Either create an onion message, or decode one step", |
| 621 | + "Print this message."); |
| 622 | + opt_register_noarg("--generate", |
| 623 | + opt_set_bool, &generate, |
| 624 | + "Generate onion through the given hex pubkeys"); |
| 625 | + opt_register_noarg("--decode", |
| 626 | + opt_set_bool, &decode, |
| 627 | + "Decode onion given the private key"); |
| 628 | + opt_register_version(); |
| 629 | + |
| 630 | + opt_parse(&argc, argv, opt_log_stderr_exit); |
610 | 631 |
|
611 | | - if (!create_onion(pubkeys, msgs, hops, &onion)) |
612 | | - errx(1, "Creating onion packet failed"); |
613 | | - printf(" * Message:"); dump_hex(onion); printf("\n"); |
| 632 | + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); |
| 633 | + if (generate) { |
| 634 | + secp256k1_pubkey pubkeys[MAX_HOPS]; |
| 635 | + char *msgs[MAX_HOPS]; |
| 636 | + size_t i; |
| 637 | + |
| 638 | + if (argc == 1) |
| 639 | + opt_usage_exit_fail("Expected at least one pubkey"); |
| 640 | + if (argc-1 > MAX_HOPS) |
| 641 | + opt_usage_exit_fail("Expected at most %u pubkeys", |
| 642 | + MAX_HOPS); |
| 643 | + for (i = 1; i < argc; i++) { |
| 644 | + if (!parse_onion_pubkey(ctx, argv[i], &pubkeys[i-1])) |
| 645 | + errx(1, "Bad pubkey '%s'", argv[i]); |
| 646 | + msgs[i-1] = make_message(&pubkeys[i-1]); |
| 647 | + } |
614 | 648 |
|
615 | | - /* Now parse and peel. */ |
616 | | - for (i = 0; i < hops; i++) { |
| 649 | + if (!create_onion(pubkeys, msgs, argc - 1, &onion)) |
| 650 | + errx(1, "Creating onion packet failed"); |
| 651 | + if (!write_all(STDOUT_FILENO, &onion, sizeof(onion))) |
| 652 | + err(1, "Writing onion packet"); |
| 653 | + return 0; |
| 654 | + } else if (decode) { |
| 655 | + struct seckey seckey; |
| 656 | + secp256k1_pubkey pubkey; |
617 | 657 | struct enckey enckey; |
618 | 658 | struct iv pad_iv; |
619 | 659 |
|
620 | | - printf("Decrypting with key %zi\n", i); |
| 660 | + if (argc != 2) |
| 661 | + opt_usage_exit_fail("Expect a privkey with --decode"); |
| 662 | + |
| 663 | + if (!hex_decode(argv[1], strlen(argv[1]), &seckey, sizeof(seckey))) |
| 664 | + errx(1, "Invalid private key hex '%s'", argv[1]); |
| 665 | + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, seckey.u.u8)) |
| 666 | + errx(1, "Invalid private key '%s'", argv[1]); |
621 | 667 |
|
622 | | - if (!decrypt_onion(&seckeys[i], &onion, &enckey, &pad_iv)) |
623 | | - errx(1, "Decrypting onion for hop %zi", i); |
624 | | - if (strcmp((char *)myhop(&onion)->msg, msgs[i]) != 0) |
625 | | - errx(1, "Bad message for hop %zi", i); |
| 668 | + if (!read_all(STDIN_FILENO, &onion, sizeof(onion))) |
| 669 | + errx(1, "Reading in onion"); |
| 670 | + |
| 671 | + if (!decrypt_onion(&seckey, &onion, &enckey, &pad_iv)) |
| 672 | + errx(1, "Failed decrypting onion for '%s'", argv[1]); |
| 673 | + if (strncmp((char *)myhop(&onion)->msg, make_message(&pubkey), |
| 674 | + sizeof(myhop(&onion)->msg))) |
| 675 | + errx(1, "Bad message '%s'", (char *)myhop(&onion)->msg); |
626 | 676 | if (!peel_onion(&onion, &enckey, &pad_iv)) |
627 | | - errx(1, "Peeling onion for hop %zi", i); |
628 | | - } |
| 677 | + errx(1, "Peeling onion for '%s'", argv[1]); |
| 678 | + if (!write_all(STDOUT_FILENO, &onion, sizeof(onion))) |
| 679 | + err(1, "Writing onion packet"); |
| 680 | + return 0; |
| 681 | + } else |
| 682 | + opt_usage_exit_fail("Need --decode or --generate"); |
| 683 | + |
629 | 684 | secp256k1_context_destroy(ctx); |
630 | 685 | return 0; |
631 | 686 | } |
0 commit comments