mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 23:24:27 +01:00
sphinx: Onion reply wrapping and unwrapping
Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
committed by
Rusty Russell
parent
e603dba14a
commit
bc0039e8c0
@@ -12,11 +12,13 @@
|
|||||||
|
|
||||||
#include <sodium/crypto_auth_hmacsha256.h>
|
#include <sodium/crypto_auth_hmacsha256.h>
|
||||||
#include <sodium/crypto_stream_chacha20.h>
|
#include <sodium/crypto_stream_chacha20.h>
|
||||||
|
#include <wire/wire.h>
|
||||||
|
|
||||||
#define BLINDING_FACTOR_SIZE 32
|
#define BLINDING_FACTOR_SIZE 32
|
||||||
#define SHARED_SECRET_SIZE 32
|
#define SHARED_SECRET_SIZE 32
|
||||||
#define NUM_STREAM_BYTES ((2 * NUM_MAX_HOPS + 2) * SECURITY_PARAMETER)
|
#define NUM_STREAM_BYTES ((2 * NUM_MAX_HOPS + 2) * SECURITY_PARAMETER)
|
||||||
#define KEY_LEN 32
|
#define KEY_LEN 32
|
||||||
|
#define ONION_REPLY_SIZE 128
|
||||||
|
|
||||||
struct hop_params {
|
struct hop_params {
|
||||||
u8 secret[SHARED_SECRET_SIZE];
|
u8 secret[SHARED_SECRET_SIZE];
|
||||||
@@ -494,3 +496,91 @@ struct route_step *process_onionpacket(
|
|||||||
|
|
||||||
return step;
|
return step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 *create_onionreply(tal_t *ctx, const u8 *shared_secret,
|
||||||
|
const u8 *failure_msg)
|
||||||
|
{
|
||||||
|
size_t msglen = tal_len(failure_msg);
|
||||||
|
size_t padlen = ONION_REPLY_SIZE - msglen;
|
||||||
|
u8 *reply = tal_arr(ctx, u8, 0), *payload = tal_arr(ctx, u8, 0);
|
||||||
|
u8 key[KEY_LEN];
|
||||||
|
u8 hmac[20];
|
||||||
|
|
||||||
|
towire_u16(&payload, msglen);
|
||||||
|
towire(&payload, failure_msg, msglen);
|
||||||
|
towire_u16(&payload, padlen);
|
||||||
|
towire_pad(&payload, padlen);
|
||||||
|
assert(tal_len(payload) == ONION_REPLY_SIZE + 4);
|
||||||
|
|
||||||
|
generate_key(key, "um", 2, shared_secret);
|
||||||
|
|
||||||
|
compute_hmac(hmac, payload, tal_len(payload), key, KEY_LEN);
|
||||||
|
towire(&reply, hmac, sizeof(hmac));
|
||||||
|
towire(&reply, payload, tal_len(payload));
|
||||||
|
tal_free(payload);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *wrap_onionreply(tal_t *ctx, const u8 *shared_secret, const u8 *reply)
|
||||||
|
{
|
||||||
|
u8 key[KEY_LEN];
|
||||||
|
size_t streamlen = tal_len(reply);
|
||||||
|
u8 stream[streamlen];
|
||||||
|
u8 *result = tal_arr(ctx, u8, streamlen);
|
||||||
|
generate_key(key, "ammag", 5, shared_secret);
|
||||||
|
generate_cipher_stream(stream, key, streamlen);
|
||||||
|
xorbytes(result, stream, reply, streamlen);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct onionreply *unwrap_onionreply(tal_t *ctx, u8 **shared_secrets,
|
||||||
|
const int numhops, const u8 *reply)
|
||||||
|
{
|
||||||
|
tal_t *tmpctx = tal_tmpctx(ctx);
|
||||||
|
struct onionreply *oreply = tal(tmpctx, struct onionreply);
|
||||||
|
u8 *msg = tal_arr(oreply, u8, tal_len(reply));
|
||||||
|
u8 key[KEY_LEN], hmac[20];
|
||||||
|
const u8 *cursor;
|
||||||
|
size_t max;
|
||||||
|
u16 msglen;
|
||||||
|
|
||||||
|
memcpy(msg, reply, tal_len(reply));
|
||||||
|
oreply->origin_index = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < numhops; i++) {
|
||||||
|
/* Since the encryption is just XORing with the cipher
|
||||||
|
* stream encryption is identical to decryption */
|
||||||
|
msg = wrap_onionreply(tmpctx, shared_secrets[i], msg);
|
||||||
|
|
||||||
|
/* Check if the HMAC matches, this means that this is
|
||||||
|
* the origin */
|
||||||
|
generate_key(key, "um", 2, shared_secrets[i]);
|
||||||
|
compute_hmac(hmac, msg + sizeof(hmac),
|
||||||
|
tal_len(msg) - sizeof(hmac), key, KEY_LEN);
|
||||||
|
if (memcmp(hmac, msg, sizeof(hmac)) == 0) {
|
||||||
|
oreply->origin_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oreply->origin_index == -1) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = msg + sizeof(hmac);
|
||||||
|
max = tal_len(msg) - sizeof(hmac);
|
||||||
|
msglen = fromwire_u16(&cursor, &max);
|
||||||
|
|
||||||
|
if (msglen > ONION_REPLY_SIZE) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
oreply->msg = tal_arr(oreply, u8, msglen);
|
||||||
|
fromwire(&cursor, &max, oreply->msg, msglen);
|
||||||
|
|
||||||
|
tal_steal(ctx, oreply);
|
||||||
|
tal_free(tmpctx);
|
||||||
|
return oreply;
|
||||||
|
fail:
|
||||||
|
return tal_free(tmpctx);
|
||||||
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ u8 *serialize_onionpacket(
|
|||||||
const struct onionpacket *packet);
|
const struct onionpacket *packet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parese_onionpacket - Parse an onionpacket from a buffer.
|
* parse_onionpacket - Parse an onionpacket from a buffer.
|
||||||
*
|
*
|
||||||
* @ctx: tal context to allocate from
|
* @ctx: tal context to allocate from
|
||||||
* @src: buffer to read the packet from
|
* @src: buffer to read the packet from
|
||||||
@@ -137,4 +137,41 @@ void pubkey_hash160(
|
|||||||
u8 *dst,
|
u8 *dst,
|
||||||
const struct pubkey *pubkey);
|
const struct pubkey *pubkey);
|
||||||
|
|
||||||
|
struct onionreply {
|
||||||
|
/* Node index in the path that is replying */
|
||||||
|
int origin_index;
|
||||||
|
u8 *msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create_onionreply - Format a failure message so we can return it
|
||||||
|
*
|
||||||
|
* @ctx: tal context to allocate from
|
||||||
|
* @shared_secret: The shared secret used in the forward direction, used for the
|
||||||
|
* HMAC
|
||||||
|
* @failure_msg: message (must support tal_len)
|
||||||
|
*/
|
||||||
|
u8 *create_onionreply(tal_t *ctx, const u8 *shared_secret, const u8 *failure_msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wrap_onionreply - Add another encryption layer to the reply.
|
||||||
|
*
|
||||||
|
* @ctx: tal context to allocate from
|
||||||
|
* @shared_secret: the shared secret associated with the HTLC, used for the
|
||||||
|
* encryption.
|
||||||
|
* @reply: the reply to wrap
|
||||||
|
*/
|
||||||
|
u8 *wrap_onionreply(tal_t *ctx, const u8 *shared_secret, const u8 *reply);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unwrap_onionreply - Remove layers, check integrity and parse reply
|
||||||
|
*
|
||||||
|
* @ctx: tal context to allocate from
|
||||||
|
* @shared_secrets: shared secrets from the forward path
|
||||||
|
* @numhops: path length and number of shared_secrets provided
|
||||||
|
* @reply: the incoming reply
|
||||||
|
*/
|
||||||
|
struct onionreply *unwrap_onionreply(tal_t *ctx, u8 **shared_secrets,
|
||||||
|
const int numhops, const u8 *reply);
|
||||||
|
|
||||||
#endif /* LIGHTNING_DAEMON_SPHINX_H */
|
#endif /* LIGHTNING_DAEMON_SPHINX_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user