|
@ -57,6 +57,14 @@ struct sphinx_path { |
|
|
|
|
|
|
|
|
/* The individual hops on this route. */ |
|
|
/* The individual hops on this route. */ |
|
|
struct sphinx_hop *hops; |
|
|
struct sphinx_hop *hops; |
|
|
|
|
|
|
|
|
|
|
|
/* If this is a rendez-vous onion, then the following node_id tells us
|
|
|
|
|
|
* which node will be processing this onion and decompressing the |
|
|
|
|
|
* onion. It is used to generate the prefill obfuscation stream to |
|
|
|
|
|
* hide the fact that the onion was compressed from the next |
|
|
|
|
|
* node. NULL if this is not a rendez-vous onion, and shouldn't be |
|
|
|
|
|
* compressible. */ |
|
|
|
|
|
struct pubkey *rendezvous_id; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct sphinx_path *sphinx_path_new(const tal_t *ctx, const u8 *associated_data) |
|
|
struct sphinx_path *sphinx_path_new(const tal_t *ctx, const u8 *associated_data) |
|
@ -64,6 +72,7 @@ struct sphinx_path *sphinx_path_new(const tal_t *ctx, const u8 *associated_data) |
|
|
struct sphinx_path *sp = tal(ctx, struct sphinx_path); |
|
|
struct sphinx_path *sp = tal(ctx, struct sphinx_path); |
|
|
sp->associated_data = tal_dup_talarr(sp, u8, associated_data); |
|
|
sp->associated_data = tal_dup_talarr(sp, u8, associated_data); |
|
|
sp->session_key = NULL; |
|
|
sp->session_key = NULL; |
|
|
|
|
|
sp->rendezvous_id = NULL; |
|
|
sp->hops = tal_arr(sp, struct sphinx_hop, 0); |
|
|
sp->hops = tal_arr(sp, struct sphinx_hop, 0); |
|
|
return sp; |
|
|
return sp; |
|
|
} |
|
|
} |
|
@ -259,6 +268,36 @@ static bool generate_header_padding(void *dst, size_t dstlen, |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool generate_prefill(void *dst, size_t dstlen, |
|
|
|
|
|
const struct sphinx_path *path, |
|
|
|
|
|
struct hop_params *params) |
|
|
|
|
|
{ |
|
|
|
|
|
u8 stream[2 * ROUTING_INFO_SIZE]; |
|
|
|
|
|
u8 key[KEY_LEN]; |
|
|
|
|
|
size_t fillerStart, fillerSize; |
|
|
|
|
|
|
|
|
|
|
|
memset(dst, 0, dstlen); |
|
|
|
|
|
for (int i = 0; i < tal_count(path->hops); i++) { |
|
|
|
|
|
if (!generate_key(&key, RHO_KEYTYPE, strlen(RHO_KEYTYPE), |
|
|
|
|
|
¶ms[i].secret)) |
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
generate_cipher_stream(stream, key, sizeof(stream)); |
|
|
|
|
|
|
|
|
|
|
|
/* Sum up how many bytes have been used by previous hops,
|
|
|
|
|
|
* that gives us the start in the stream */ |
|
|
|
|
|
fillerSize = 0; |
|
|
|
|
|
for (int j = 0; j < i; j++) |
|
|
|
|
|
fillerSize += sphinx_hop_size(&path->hops[j]); |
|
|
|
|
|
fillerStart = ROUTING_INFO_SIZE - fillerSize - dstlen; |
|
|
|
|
|
|
|
|
|
|
|
/* Apply the cipher-stream to the part of the filler that'll
|
|
|
|
|
|
* be added by this hop */ |
|
|
|
|
|
xorbytes(dst, dst, stream + fillerStart, dstlen); |
|
|
|
|
|
} |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void compute_blinding_factor(const struct pubkey *key, |
|
|
static void compute_blinding_factor(const struct pubkey *key, |
|
|
const struct secret *sharedsecret, |
|
|
const struct secret *sharedsecret, |
|
|
u8 res[BLINDING_FACTOR_SIZE]) |
|
|
u8 res[BLINDING_FACTOR_SIZE]) |
|
@ -386,6 +425,39 @@ static void sphinx_write_frame(u8 *dest, const struct sphinx_hop *hop) |
|
|
memcpy(dest + tal_bytelen(hop->raw_payload), hop->hmac, HMAC_SIZE); |
|
|
memcpy(dest + tal_bytelen(hop->raw_payload), hop->hmac, HMAC_SIZE); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void sphinx_prefill_stream_xor(u8 *dst, size_t dstlen, |
|
|
|
|
|
const struct secret *shared_secret) |
|
|
|
|
|
{ |
|
|
|
|
|
u8 padkey[KEY_LEN]; |
|
|
|
|
|
generate_key(padkey, "prefill", 7, shared_secret); |
|
|
|
|
|
xor_cipher_stream(dst, padkey, dstlen); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void sphinx_prefill(u8 *routinginfo, const struct sphinx_path *sp, |
|
|
|
|
|
size_t prefill_size, struct hop_params *params) |
|
|
|
|
|
{ |
|
|
|
|
|
int num_hops = tal_count(sp->hops); |
|
|
|
|
|
size_t fillerSize = sphinx_path_payloads_size(sp) - |
|
|
|
|
|
sphinx_hop_size(&sp->hops[num_hops - 1]); |
|
|
|
|
|
size_t last_hop_size = sphinx_hop_size(&sp->hops[num_hops - 1]); |
|
|
|
|
|
int prefill_offset = |
|
|
|
|
|
ROUTING_INFO_SIZE - fillerSize - last_hop_size - prefill_size; |
|
|
|
|
|
u8 prefill[prefill_size]; |
|
|
|
|
|
struct secret shared_secret; |
|
|
|
|
|
|
|
|
|
|
|
/* Generate the prefill stream, which cancels out the layers of
|
|
|
|
|
|
* encryption that will be applied while wrapping the onion. This |
|
|
|
|
|
* leaves the middle, unused, section with all 0x00 bytes after |
|
|
|
|
|
* encrypting. */ |
|
|
|
|
|
generate_prefill(prefill, prefill_size, sp, params); |
|
|
|
|
|
memcpy(routinginfo + prefill_offset, prefill, prefill_size); |
|
|
|
|
|
|
|
|
|
|
|
/* Now fill in the obfuscation stream, which can be regenerated by the
|
|
|
|
|
|
* node processing this onion. */ |
|
|
|
|
|
create_shared_secret(&shared_secret, sp->rendezvous_id, sp->session_key); |
|
|
|
|
|
sphinx_prefill_stream_xor(routinginfo + prefill_offset, prefill_size, &shared_secret); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
struct onionpacket *create_onionpacket( |
|
|
struct onionpacket *create_onionpacket( |
|
|
const tal_t *ctx, |
|
|
const tal_t *ctx, |
|
|
struct sphinx_path *sp, |
|
|
struct sphinx_path *sp, |
|
@ -402,6 +474,8 @@ struct onionpacket *create_onionpacket( |
|
|
u8 nexthmac[HMAC_SIZE]; |
|
|
u8 nexthmac[HMAC_SIZE]; |
|
|
struct hop_params *params; |
|
|
struct hop_params *params; |
|
|
struct secret *secrets = tal_arr(ctx, struct secret, num_hops); |
|
|
struct secret *secrets = tal_arr(ctx, struct secret, num_hops); |
|
|
|
|
|
size_t payloads_size = sphinx_path_payloads_size(sp); |
|
|
|
|
|
size_t max_prefill = ROUTING_INFO_SIZE - payloads_size; |
|
|
|
|
|
|
|
|
if (sphinx_path_payloads_size(sp) > ROUTING_INFO_SIZE) { |
|
|
if (sphinx_path_payloads_size(sp) > ROUTING_INFO_SIZE) { |
|
|
tal_free(packet); |
|
|
tal_free(packet); |
|
@ -435,6 +509,11 @@ struct onionpacket *create_onionpacket( |
|
|
|
|
|
|
|
|
generate_header_padding(filler, sizeof(filler), sp, params); |
|
|
generate_header_padding(filler, sizeof(filler), sp, params); |
|
|
|
|
|
|
|
|
|
|
|
if (sp->rendezvous_id != NULL) |
|
|
|
|
|
/* FIXME: Fuzz this or expose to the caller to hide encoded
|
|
|
|
|
|
* route length. */ |
|
|
|
|
|
sphinx_prefill(packet->routinginfo, sp, max_prefill, params); |
|
|
|
|
|
|
|
|
for (i = num_hops - 1; i >= 0; i--) { |
|
|
for (i = num_hops - 1; i >= 0; i--) { |
|
|
memcpy(sp->hops[i].hmac, nexthmac, HMAC_SIZE); |
|
|
memcpy(sp->hops[i].hmac, nexthmac, HMAC_SIZE); |
|
|
generate_key_set(¶ms[i].secret, &keys); |
|
|
generate_key_set(¶ms[i].secret, &keys); |
|
|