Browse Source

sphinx: Treat compressed onions as a standalone struct

Expands the interface to play with onions a bit more. Potentially a bit
slower due to allocations, but that's a small price to pay. It also allows us
to avoid serializing a compressed onion to `u8*` if we process it right away.
travis-debug
Christian Decker 5 years ago
committed by Rusty Russell
parent
commit
e79cda8c9a
  1. 102
      common/sphinx.c
  2. 27
      common/sphinx.h
  3. 4
      devtools/onion.c

102
common/sphinx.c

@ -786,26 +786,96 @@ u8 *unwrap_onionreply(const tal_t *ctx,
return final;
}
u8 *sphinx_decompress(const tal_t *ctx, const u8 *compressed,
struct secret *shared_secret)
struct onionpacket *sphinx_decompress(const tal_t *ctx,
const struct sphinx_compressed_onion *src,
const struct secret *shared_secret)
{
size_t compressedlen = tal_bytelen(compressed);
size_t prefill_size = TOTAL_PACKET_SIZE - compressedlen;
u8 *dst;
struct onionpacket *res = tal(ctx, struct onionpacket);
size_t srclen = tal_bytelen(src->routinginfo);
size_t prefill_size = ROUTING_INFO_SIZE - srclen;
res->version = src->version;
res->ephemeralkey = src->ephemeralkey;
memcpy(res->mac, src->mac, HMAC_SIZE);
/* Decompress routinginfo by copying the unmodified prefix, setting
* the compressed suffix to 0x00 bytes and then xoring the obfuscation
* stream in place. */
memset(res->routinginfo, 0, ROUTING_INFO_SIZE);
memcpy(res->routinginfo, src->routinginfo, srclen);
sphinx_prefill_stream_xor(res->routinginfo + srclen, prefill_size,
shared_secret);
return res;
}
struct sphinx_compressed_onion *
sphinx_compress(const tal_t *ctx, const struct onionpacket *packet,
const struct sphinx_path *path)
{
struct sphinx_compressed_onion *res;
size_t payloads_size = sphinx_path_payloads_size(path);
/* We can't compress an onion that doesn't have a rendez-vous node. */
if (path->rendezvous_id)
return NULL;
res = tal(ctx, struct sphinx_compressed_onion);
res->version = packet->version;
res->ephemeralkey = packet->ephemeralkey;
memcpy(res->mac, packet->mac, HMAC_SIZE);
res->routinginfo = tal_arr(res, u8, payloads_size);
memcpy(res->routinginfo, packet->routinginfo, payloads_size);
return res;
}
u8 *sphinx_compressed_onion_serialize(const tal_t *ctx, const struct sphinx_compressed_onion *onion)
{
size_t routelen = tal_bytelen(onion->routinginfo);
size_t len = VERSION_SIZE + PUBKEY_SIZE + routelen + HMAC_SIZE;
u8 *dst = tal_arr(ctx, u8, len);
u8 der[PUBKEY_CMPR_LEN];
int p = 0;
pubkey_to_der(der, &onion->ephemeralkey);
write_buffer(dst, &onion->version, VERSION_SIZE, &p);
write_buffer(dst, der, PUBKEY_SIZE, &p);
write_buffer(dst, onion->routinginfo, routelen, &p);
write_buffer(dst, onion->mac, HMAC_SIZE, &p);
assert(p == len);
return dst;
}
struct sphinx_compressed_onion *
sphinx_compressed_onion_deserialize(const tal_t *ctx, const u8 *src)
{
size_t srclen = tal_bytelen(src);
size_t routelen = srclen - VERSION_SIZE - PUBKEY_SIZE - HMAC_SIZE;
struct sphinx_compressed_onion *dst =
tal(ctx, struct sphinx_compressed_onion);
int p = 0;
u8 ephkey[PUBKEY_SIZE];
assert(srclen <= TOTAL_PACKET_SIZE);
assert(prefill_size >= 0);
assert(compressedlen >= VERSION_SIZE + PUBKEY_SIZE + HMAC_SIZE);
dst = tal_arrz(ctx, u8, TOTAL_PACKET_SIZE);
write_buffer(
dst, compressed,
VERSION_SIZE + PUBKEY_SIZE + ROUTING_INFO_SIZE - prefill_size, &p);
read_buffer(&dst->version, src, 1, &p);
if (dst->version != 0x00)
return tal_free(dst);
read_buffer(ephkey, src, PUBKEY_SIZE, &p);
if (!pubkey_from_der(ephkey, PUBKEY_SIZE, &dst->ephemeralkey)) {
return tal_free(dst);
}
/* We can just XOR here since we initialized the array with zeros. */
sphinx_prefill_stream_xor(dst + p, prefill_size, shared_secret);
p += prefill_size;
dst->routinginfo = tal_arr(dst, u8, routelen);
read_buffer(dst->routinginfo, src, routelen, &p);
read_buffer(&dst->mac, src, HMAC_SIZE, &p);
assert(p == srclen);
write_buffer(dst, compressed + compressedlen - HMAC_SIZE, HMAC_SIZE,
&p);
return dst;
}

27
common/sphinx.h

@ -30,6 +30,14 @@ struct onionpacket {
u8 routinginfo[ROUTING_INFO_SIZE];
};
struct sphinx_compressed_onion {
u8 version;
struct pubkey ephemeralkey;
u8 *routinginfo;
u8 mac[HMAC_SIZE];
};
enum route_next_case {
ONION_END = 0,
ONION_FORWARD = 1,
@ -250,8 +258,9 @@ bool sphinx_path_set_rendezvous(struct sphinx_path *sp,
* Given a compressed onion expand it by re-generating the prefiller and
* inserting it in the appropriate place.
*/
u8 *sphinx_decompress(const tal_t *ctx, const u8 *compressed,
struct secret *shared_secret);
struct onionpacket *sphinx_decompress(const tal_t *ctx,
const struct sphinx_compressed_onion *src,
const struct secret *shared_secret);
/**
* Use ECDH to generate a shared secret from a privkey and a pubkey.
@ -264,6 +273,20 @@ bool sphinx_create_shared_secret(struct secret *privkey,
const struct pubkey *pubkey,
const struct secret *secret);
/**
* Given a compressible onionpacket, return the compressed version.
*/
struct sphinx_compressed_onion *
sphinx_compress(const tal_t *ctx, const struct onionpacket *packet,
const struct sphinx_path *path);
u8 *sphinx_compressed_onion_serialize(
const tal_t *ctx, const struct sphinx_compressed_onion *onion);
struct sphinx_compressed_onion *
sphinx_compressed_onion_deserialize(const tal_t *ctx, const u8 *src);
#if DEVELOPER
/* Override to force us to reject valid onion packets */
extern bool dev_fail_process_onionpacket;

4
devtools/onion.c

@ -294,9 +294,11 @@ static void decompress(char *hexprivkey, char *hexonion)
{
struct privkey rendezvous_key;
size_t onionlen = hex_data_size(strlen(hexonion));
u8 *compressed, *decompressed;
u8 *compressed;
struct pubkey ephkey;
struct secret shared_secret;
struct onionpacket *onion;
struct sphinx_compressed_onion *tinyonion;
if (!hex_decode(hexprivkey, strlen(hexprivkey), &rendezvous_key, sizeof(rendezvous_key)))
errx(1, "Invalid private key hex '%s'", hexprivkey);

Loading…
Cancel
Save