Skip to content

Commit ed46dd3

Browse files
committed
test_onion: split encode and decode, drive from cmdline.
This lets us test interaction with python code, for example. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 7c36a3e commit ed46dd3

File tree

3 files changed

+90
-33
lines changed

3 files changed

+90
-33
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ test-cli-tests: $(TEST_CLI_PROGRAMS)
100100
cd test-cli; scripts/shutdown.sh 2>/dev/null || true
101101
set -e; cd test-cli; for args in "" --steal --unilateral --htlc-onchain; do scripts/setup.sh && scripts/test.sh $$args && scripts/shutdown.sh; done
102102

103-
test-onion: test/test_onion
104-
set -e; for i in `seq 20`; do ./test/test_onion $$i; done
103+
test-onion: test/test_onion test/onion_key
104+
set -e; TMPF=/tmp/onion.$$$$; test/test_onion --generate $$(for k in `seq 20`; do test/onion_key $$k; done | cut -d: -f2) > $$TMPF; for k in `seq 20`; do test/test_onion --decode $$(test/onion_key $$k | cut -d: -f1) < $$TMPF > $$TMPF.unwrap; mv $$TMPF.unwrap $$TMPF; done; rm -f $$TMPF
105105

106106
check: test-cli-tests test-onion
107107

test/onion_key.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#ifndef ONION_KEY_H
22
#define ONION_KEY_H
33
#include <ccan/endian/endian.h>
4+
#include "bitcoin/privkey.h"
45

56
struct seckey {
67
union {
8+
struct privkey k;
79
unsigned char u8[32];
810
beint64_t be64[4];
911
} u;

test/test_onion.c

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "onion_key.h"
33
#include "secp256k1.h"
44
#include "secp256k1_ecdh.h"
5+
#include "version.h"
56
#include <openssl/hmac.h>
67
#include <openssl/evp.h>
78
#include <openssl/aes.h>
@@ -15,6 +16,9 @@
1516
#include <ccan/mem/mem.h>
1617
#include <ccan/crypto/sha256/sha256.h>
1718
#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>
1822

1923
/*
2024
* The client knows the server's public key S (which has corresponding
@@ -581,51 +585,102 @@ bool peel_onion(struct onion *onion,
581585
sizeof(onion->hop[0]), enckey, pad_iv);
582586
}
583587

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+
584609
int main(int argc, char *argv[])
585610
{
586611
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];
591612
struct onion onion;
613+
bool generate = false, decode = false;
592614

593615
assert(EVP_CIPHER_iv_length(EVP_aes_128_ctr()) == sizeof(struct iv));
594616

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);
610631

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+
}
614648

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;
617657
struct enckey enckey;
618658
struct iv pad_iv;
619659

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]);
621667

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);
626676
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+
629684
secp256k1_context_destroy(ctx);
630685
return 0;
631686
}

0 commit comments

Comments
 (0)