mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
sphinx: Working onion wrapping with filler cancellation
This commit is contained in:
parent
bc74e49534
commit
96dc0238ba
@ -57,6 +57,14 @@ struct sphinx_path {
|
||||
|
||||
/* The individual hops on this route. */
|
||||
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)
|
||||
@ -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);
|
||||
sp->associated_data = tal_dup_talarr(sp, u8, associated_data);
|
||||
sp->session_key = NULL;
|
||||
sp->rendezvous_id = NULL;
|
||||
sp->hops = tal_arr(sp, struct sphinx_hop, 0);
|
||||
return sp;
|
||||
}
|
||||
@ -259,6 +268,36 @@ static bool generate_header_padding(void *dst, size_t dstlen,
|
||||
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,
|
||||
const struct secret *sharedsecret,
|
||||
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);
|
||||
}
|
||||
|
||||
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(
|
||||
const tal_t *ctx,
|
||||
struct sphinx_path *sp,
|
||||
@ -402,6 +474,8 @@ struct onionpacket *create_onionpacket(
|
||||
u8 nexthmac[HMAC_SIZE];
|
||||
struct hop_params *params;
|
||||
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) {
|
||||
tal_free(packet);
|
||||
@ -435,6 +509,11 @@ struct onionpacket *create_onionpacket(
|
||||
|
||||
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--) {
|
||||
memcpy(sp->hops[i].hmac, nexthmac, HMAC_SIZE);
|
||||
generate_key_set(¶ms[i].secret, &keys);
|
||||
|
Loading…
Reference in New Issue
Block a user