@ -20,7 +20,6 @@
# define BLINDING_FACTOR_SIZE 32
# define BLINDING_FACTOR_SIZE 32
# define NUM_STREAM_BYTES (2*ROUTING_INFO_SIZE)
# define ONION_REPLY_SIZE 256
# define ONION_REPLY_SIZE 256
# define RHO_KEYTYPE "rho"
# define RHO_KEYTYPE "rho"
@ -131,7 +130,7 @@ u8 *serialize_onionpacket(
const tal_t * ctx ,
const tal_t * ctx ,
const struct onionpacket * m )
const struct onionpacket * m )
{
{
u8 * dst = tal_arr ( ctx , u8 , TOTAL_PACKET_SIZE ( ROUTING_INFO_SIZE ) ) ;
u8 * dst = tal_arr ( ctx , u8 , TOTAL_PACKET_SIZE ( tal_bytelen ( m - > routinginfo ) ) ) ;
u8 der [ PUBKEY_CMPR_LEN ] ;
u8 der [ PUBKEY_CMPR_LEN ] ;
int p = 0 ;
int p = 0 ;
@ -139,35 +138,48 @@ u8 *serialize_onionpacket(
pubkey_to_der ( der , & m - > ephemeralkey ) ;
pubkey_to_der ( der , & m - > ephemeralkey ) ;
write_buffer ( dst , & m - > version , 1 , & p ) ;
write_buffer ( dst , & m - > version , 1 , & p ) ;
write_buffer ( dst , der , sizeof ( der ) , & p ) ;
write_buffer ( dst , der , sizeof ( der ) , & p ) ;
write_buffer ( dst , m - > routinginfo , ROUTING_INFO_SIZE , & p ) ;
write_buffer ( dst , m - > routinginfo , tal_bytelen ( m - > routinginfo ) , & p ) ;
write_buffer ( dst , m - > hmac . bytes , sizeof ( m - > hmac . bytes ) , & p ) ;
write_buffer ( dst , m - > hmac . bytes , sizeof ( m - > hmac . bytes ) , & p ) ;
return dst ;
return dst ;
}
}
enum onion_wire parse_onionpacket ( const u8 * src ,
struct onionpacket * parse_onionpacket ( const tal_t * ctx ,
const size_t srclen ,
const u8 * src ,
struct onionpacket * dest )
const size_t srclen ,
enum onion_wire * failcode )
{
{
struct onionpacket * dest = tal ( ctx , struct onionpacket ) ;
const u8 * cursor = src ;
const u8 * cursor = src ;
size_t max = srclen ;
size_t max = srclen ;
/* FIXME: Allow parsing other sizes! */
assert ( srclen = = TOTAL_PACKET_SIZE ( ROUTING_INFO_SIZE ) ) ;
assert ( srclen = = TOTAL_PACKET_SIZE ( ROUTING_INFO_SIZE ) ) ;
dest - > version = fromwire_u8 ( & cursor , & max ) ;
dest - > version = fromwire_u8 ( & cursor , & max ) ;
if ( dest - > version ! = 0x00 ) {
if ( dest - > version ! = 0x00 ) {
// FIXME add logging
// FIXME add logging
return WIRE_INVALID_ONION_VERSION ;
* failcode = WIRE_INVALID_ONION_VERSION ;
return tal_free ( dest ) ;
}
}
fromwire_pubkey ( & cursor , & max , & dest - > ephemeralkey ) ;
fromwire_pubkey ( & cursor , & max , & dest - > ephemeralkey ) ;
if ( cursor = = NULL ) {
if ( cursor = = NULL ) {
return WIRE_INVALID_ONION_KEY ;
* failcode = WIRE_INVALID_ONION_KEY ;
return tal_free ( dest ) ;
}
}
fromwire_u8_array ( & cursor , & max , dest - > routinginfo , ROUTING_INFO_SIZE ) ;
/* If max underflows, this returns NULL and fromwire fails. */
dest - > routinginfo = fromwire_tal_arrn ( dest , & cursor , & max ,
max - HMAC_SIZE ) ;
fromwire_hmac ( & cursor , & max , & dest - > hmac ) ;
fromwire_hmac ( & cursor , & max , & dest - > hmac ) ;
assert ( max = = 0 ) ;
assert ( max = = 0 ) ;
return 0 ;
if ( cursor = = NULL ) {
* failcode = WIRE_INVALID_REALM ;
return tal_free ( dest ) ;
}
return dest ;
}
}
/*
/*
@ -248,12 +260,13 @@ static void compute_packet_hmac(const struct onionpacket *packet,
struct hmac * hmac )
struct hmac * hmac )
{
{
compute_hmac ( mukey ,
compute_hmac ( mukey ,
packet - > routinginfo , ROUTING_INFO_SIZE ,
packet - > routinginfo , tal_bytelen ( packet - > routinginfo ) ,
assocdata , assocdatalen ,
assocdata , assocdatalen ,
hmac ) ;
hmac ) ;
}
}
static void generate_header_padding ( void * dst , size_t dstlen ,
static void generate_header_padding ( void * dst , size_t dstlen ,
size_t fixed_size ,
const struct sphinx_path * path ,
const struct sphinx_path * path ,
struct hop_params * params )
struct hop_params * params )
{
{
@ -269,12 +282,12 @@ static void generate_header_padding(void *dst, size_t dstlen,
fillerSize = 0 ;
fillerSize = 0 ;
for ( int j = 0 ; j < i ; j + + )
for ( int j = 0 ; j < i ; j + + )
fillerSize + = sphinx_hop_size ( & path - > hops [ j ] ) ;
fillerSize + = sphinx_hop_size ( & path - > hops [ j ] ) ;
fillerStart = ROUTING_INFO_SIZE - fillerSize ;
fillerStart = fixed_size - fillerSize ;
/* The filler will dangle off of the end by the current
/* The filler will dangle off of the end by the current
* hop - size , we ' ll make sure to copy it into the correct
* hop - size , we ' ll make sure to copy it into the correct
* position in the next step . */
* position in the next step . */
fillerEnd = ROUTING_INFO_SIZE + sphinx_hop_size ( & path - > hops [ i ] ) ;
fillerEnd = fixed_size + sphinx_hop_size ( & path - > hops [ i ] ) ;
/* Apply the cipher-stream to the part of the filler that'll
/* Apply the cipher-stream to the part of the filler that'll
* be added by this hop */
* be added by this hop */
@ -284,6 +297,7 @@ static void generate_header_padding(void *dst, size_t dstlen,
}
}
static void generate_prefill ( void * dst , size_t dstlen ,
static void generate_prefill ( void * dst , size_t dstlen ,
size_t fixed_size ,
const struct sphinx_path * path ,
const struct sphinx_path * path ,
struct hop_params * params )
struct hop_params * params )
{
{
@ -299,7 +313,7 @@ static void generate_prefill(void *dst, size_t dstlen,
fillerSize = 0 ;
fillerSize = 0 ;
for ( int j = 0 ; j < i ; j + + )
for ( int j = 0 ; j < i ; j + + )
fillerSize + = sphinx_hop_size ( & path - > hops [ j ] ) ;
fillerSize + = sphinx_hop_size ( & path - > hops [ j ] ) ;
fillerStart = ROUTING_INFO_SIZE - fillerSize - dstlen ;
fillerStart = fixed_size - fillerSize - dstlen ;
/* Apply the cipher-stream to the part of the filler that'll
/* Apply the cipher-stream to the part of the filler that'll
* be added by this hop */
* be added by this hop */
@ -444,21 +458,23 @@ static void sphinx_prefill_stream_xor(u8 *dst, size_t dstlen,
}
}
static void sphinx_prefill ( u8 * routinginfo , const struct sphinx_path * sp ,
static void sphinx_prefill ( u8 * routinginfo , const struct sphinx_path * sp ,
size_t prefill_size , struct hop_params * params )
size_t prefill_size , struct hop_params * params ,
size_t fixed_size )
{
{
int num_hops = tal_count ( sp - > hops ) ;
int num_hops = tal_count ( sp - > hops ) ;
size_t fillerSize = sphinx_path_payloads_size ( sp ) -
size_t fillerSize = sphinx_path_payloads_size ( sp ) -
sphinx_hop_size ( & sp - > hops [ num_hops - 1 ] ) ;
sphinx_hop_size ( & sp - > hops [ num_hops - 1 ] ) ;
size_t last_hop_size = sphinx_hop_size ( & sp - > hops [ num_hops - 1 ] ) ;
size_t last_hop_size = sphinx_hop_size ( & sp - > hops [ num_hops - 1 ] ) ;
int prefill_offset =
int prefill_offset =
ROUTING_INFO_SIZE - fillerSize - last_hop_size - prefill_size ;
fixed_size - fillerSize - last_hop_size - prefill_size ;
struct secret shared_secret ;
struct secret shared_secret ;
/* Generate the prefill stream, which cancels out the layers of
/* Generate the prefill stream, which cancels out the layers of
* encryption that will be applied while wrapping the onion . This
* encryption that will be applied while wrapping the onion . This
* leaves the middle , unused , section with all 0x00 bytes after
* leaves the middle , unused , section with all 0x00 bytes after
* encrypting . */
* encrypting . */
generate_prefill ( routinginfo + prefill_offset , prefill_size , sp , params ) ;
generate_prefill ( routinginfo + prefill_offset , prefill_size ,
fixed_size , sp , params ) ;
/* Now fill in the obfuscation stream, which can be regenerated by the
/* Now fill in the obfuscation stream, which can be regenerated by the
* node processing this onion . */
* node processing this onion . */
@ -469,6 +485,7 @@ static void sphinx_prefill(u8 *routinginfo, const struct sphinx_path *sp,
struct onionpacket * create_onionpacket (
struct onionpacket * create_onionpacket (
const tal_t * ctx ,
const tal_t * ctx ,
struct sphinx_path * sp ,
struct sphinx_path * sp ,
size_t fixed_size ,
struct secret * * path_secrets
struct secret * * path_secrets
)
)
{
{
@ -476,20 +493,21 @@ struct onionpacket *create_onionpacket(
int i , num_hops = tal_count ( sp - > hops ) ;
int i , num_hops = tal_count ( sp - > hops ) ;
size_t fillerSize = sphinx_path_payloads_size ( sp ) -
size_t fillerSize = sphinx_path_payloads_size ( sp ) -
sphinx_hop_size ( & sp - > hops [ num_hops - 1 ] ) ;
sphinx_hop_size ( & sp - > hops [ num_hops - 1 ] ) ;
u8 filler [ fillerSize ] ;
u8 * filler ;
struct keyset keys ;
struct keyset keys ;
struct secret padkey ;
struct secret padkey ;
struct hmac nexthmac ;
struct hmac nexthmac ;
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 payloads_size = sphinx_path_payloads_size ( sp ) ;
size_t max_prefill = ROUTING_INFO_SIZE - payloads_size ;
size_t max_prefill = fixed_size - payloads_size ;
if ( sphinx_path_payloads_size ( sp ) > ROUTING_INFO_SIZE ) {
if ( sphinx_path_payloads_size ( sp ) > fixed_size ) {
tal_free ( packet ) ;
tal_free ( packet ) ;
tal_free ( secrets ) ;
tal_free ( secrets ) ;
return NULL ;
return NULL ;
}
}
packet - > routinginfo = tal_arr ( packet , u8 , fixed_size ) ;
if ( sp - > session_key = = NULL ) {
if ( sp - > session_key = = NULL ) {
sp - > session_key = tal ( sp , struct secret ) ;
sp - > session_key = tal ( sp , struct secret ) ;
@ -513,14 +531,16 @@ struct onionpacket *create_onionpacket(
/* Note that this is just hop_payloads: the rest of the packet is
/* Note that this is just hop_payloads: the rest of the packet is
* overwritten below or above anyway . */
* overwritten below or above anyway . */
subkey_from_hmac ( " pad " , sp - > session_key , & padkey ) ;
subkey_from_hmac ( " pad " , sp - > session_key , & padkey ) ;
generate_cipher_stream ( packet - > routinginfo , & padkey , ROUTING_INFO_SIZE ) ;
generate_cipher_stream ( packet - > routinginfo , & padkey , fixed_size ) ;
generate_header_padding ( filler , sizeof ( filler ) , sp , params ) ;
filler = tal_arr ( tmpctx , u8 , fillerSize ) ;
generate_header_padding ( filler , tal_bytelen ( filler ) , fixed_size , sp , params ) ;
if ( sp - > rendezvous_id ! = NULL )
if ( sp - > rendezvous_id ! = NULL )
/* FIXME: Fuzz this or expose to the caller to hide encoded
/* FIXME: Fuzz this or expose to the caller to hide encoded
* route length . */
* route length . */
sphinx_prefill ( packet - > routinginfo , sp , max_prefill , params ) ;
sphinx_prefill ( packet - > routinginfo , sp , max_prefill , params ,
fixed_size ) ;
for ( i = num_hops - 1 ; i > = 0 ; i - - ) {
for ( i = num_hops - 1 ; i > = 0 ; i - - ) {
sp - > hops [ i ] . hmac = nexthmac ;
sp - > hops [ i ] . hmac = nexthmac ;
@ -529,13 +549,13 @@ struct onionpacket *create_onionpacket(
/* Rightshift mix-header by FRAME_SIZE */
/* Rightshift mix-header by FRAME_SIZE */
size_t shiftSize = sphinx_hop_size ( & sp - > hops [ i ] ) ;
size_t shiftSize = sphinx_hop_size ( & sp - > hops [ i ] ) ;
memmove ( packet - > routinginfo + shiftSize , packet - > routinginfo ,
memmove ( packet - > routinginfo + shiftSize , packet - > routinginfo ,
ROUTING_INFO_SIZE - shiftSize ) ;
fixed_size - shiftSize ) ;
sphinx_write_frame ( packet - > routinginfo , & sp - > hops [ i ] ) ;
sphinx_write_frame ( packet - > routinginfo , & sp - > hops [ i ] ) ;
xor_cipher_stream ( packet - > routinginfo , & keys . rho ,
xor_cipher_stream ( packet - > routinginfo , & keys . rho ,
ROUTING_INFO_SIZE ) ;
fixed_size ) ;
if ( i = = num_hops - 1 ) {
if ( i = = num_hops - 1 ) {
memcpy ( packet - > routinginfo + ROUTING_INFO_SIZE - fillerSize , filler , fillerSize ) ;
memcpy ( packet - > routinginfo + fixed_size - fillerSize , filler , fillerSize ) ;
}
}
compute_packet_hmac ( packet , sp - > associated_data , tal_bytelen ( sp - > associated_data ) , & keys . mu ,
compute_packet_hmac ( packet , sp - > associated_data , tal_bytelen ( sp - > associated_data ) , & keys . mu ,
@ -573,7 +593,7 @@ struct route_step *process_onionpacket(
struct hmac hmac ;
struct hmac hmac ;
struct keyset keys ;
struct keyset keys ;
u8 blind [ BLINDING_FACTOR_SIZE ] ;
u8 blind [ BLINDING_FACTOR_SIZE ] ;
u8 paddedheader [ 2 * ROUTING_INFO_SIZE ] ;
u8 * paddedheader ;
size_t payload_size ;
size_t payload_size ;
bigsize_t shift_size ;
bigsize_t shift_size ;
bool valid ;
bool valid ;
@ -591,15 +611,17 @@ struct route_step *process_onionpacket(
}
}
//FIXME:store seen secrets to avoid replay attacks
//FIXME:store seen secrets to avoid replay attacks
memset ( paddedheader , 0 , sizeof ( paddedheader ) ) ;
paddedheader = tal_arrz ( step , u8 , tal_bytelen ( msg - > routinginfo ) * 2 ) ;
memcpy ( paddedheader , msg - > routinginfo , ROUTING_INFO_SIZE ) ;
memcpy ( paddedheader , msg - > routinginfo , tal_bytelen ( msg - > routinginfo ) ) ;
xor_cipher_stream ( paddedheader , & keys . rho , sizeof ( paddedheader ) ) ;
xor_cipher_stream ( paddedheader , & keys . rho , tal_bytelen ( paddedheader ) ) ;
compute_blinding_factor ( & msg - > ephemeralkey , shared_secret , blind ) ;
compute_blinding_factor ( & msg - > ephemeralkey , shared_secret , blind ) ;
if ( ! blind_group_element ( & step - > next - > ephemeralkey , & msg - > ephemeralkey , blind ) )
if ( ! blind_group_element ( & step - > next - > ephemeralkey , & msg - > ephemeralkey , blind ) )
return tal_free ( step ) ;
return tal_free ( step ) ;
payload_size = onion_payload_length ( paddedheader , ROUTING_INFO_SIZE , has_realm ,
payload_size = onion_payload_length ( paddedheader ,
tal_bytelen ( msg - > routinginfo ) ,
has_realm ,
& valid , NULL ) ;
& valid , NULL ) ;
/* Can't decode? Treat it as terminal. */
/* Can't decode? Treat it as terminal. */
@ -607,7 +629,7 @@ struct route_step *process_onionpacket(
shift_size = payload_size ;
shift_size = payload_size ;
memset ( step - > next - > hmac . bytes , 0 , sizeof ( step - > next - > hmac . bytes ) ) ;
memset ( step - > next - > hmac . bytes , 0 , sizeof ( step - > next - > hmac . bytes ) ) ;
} else {
} else {
assert ( payload_size < = ROUTING_INFO_SIZE - HMAC_SIZE ) ;
assert ( payload_size < = tal_bytelen ( msg - > routinginfo ) - HMAC_SIZE ) ;
/* Copy hmac */
/* Copy hmac */
shift_size = payload_size + HMAC_SIZE ;
shift_size = payload_size + HMAC_SIZE ;
memcpy ( step - > next - > hmac . bytes ,
memcpy ( step - > next - > hmac . bytes ,
@ -616,8 +638,10 @@ struct route_step *process_onionpacket(
step - > raw_payload = tal_dup_arr ( step , u8 , paddedheader , payload_size , 0 ) ;
step - > raw_payload = tal_dup_arr ( step , u8 , paddedheader , payload_size , 0 ) ;
/* Left shift the current payload out and make the remainder the new onion */
/* Left shift the current payload out and make the remainder the new onion */
memcpy ( & step - > next - > routinginfo , paddedheader + shift_size ,
step - > next - > routinginfo = tal_dup_arr ( step - > next ,
ROUTING_INFO_SIZE ) ;
u8 ,
paddedheader + shift_size ,
tal_bytelen ( msg - > routinginfo ) , 0 ) ;
if ( memeqzero ( step - > next - > hmac . bytes , sizeof ( step - > next - > hmac . bytes ) ) ) {
if ( memeqzero ( step - > next - > hmac . bytes , sizeof ( step - > next - > hmac . bytes ) ) ) {
step - > nextcase = ONION_END ;
step - > nextcase = ONION_END ;
@ -625,6 +649,7 @@ struct route_step *process_onionpacket(
step - > nextcase = ONION_FORWARD ;
step - > nextcase = ONION_FORWARD ;
}
}
tal_free ( paddedheader ) ;
return step ;
return step ;
}
}
@ -775,7 +800,7 @@ struct onionpacket *sphinx_decompress(const tal_t *ctx,
/* Decompress routinginfo by copying the unmodified prefix, setting
/* Decompress routinginfo by copying the unmodified prefix, setting
* the compressed suffix to 0x00 bytes and then xoring the obfuscation
* the compressed suffix to 0x00 bytes and then xoring the obfuscation
* stream in place . */
* stream in place . */
memset ( res - > routinginfo , 0 , ROUTING_INFO_SIZE ) ;
res - > routinginfo = tal_arrz ( res , u8 , ROUTING_INFO_SIZE ) ;
memcpy ( res - > routinginfo , src - > routinginfo , srclen ) ;
memcpy ( res - > routinginfo , src - > routinginfo , srclen ) ;
sphinx_prefill_stream_xor ( res - > routinginfo + srclen , prefill_size ,
sphinx_prefill_stream_xor ( res - > routinginfo + srclen , prefill_size ,
shared_secret ) ;
shared_secret ) ;