Browse Source

sphinx: Onion reply wrapping and unwrapping

Signed-off-by: Christian Decker <decker.christian@gmail.com>
ppa-0.6.1
Christian Decker 8 years ago
committed by Rusty Russell
parent
commit
bc0039e8c0
  1. 90
      lightningd/sphinx.c
  2. 39
      lightningd/sphinx.h

90
lightningd/sphinx.c

@ -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);
}

39
lightningd/sphinx.h

@ -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 */

Loading…
Cancel
Save