3
3
use ln:: peers:: { chacha, hkdf} ;
4
4
use util:: byte_utils;
5
5
6
+ type SymmetricKey = [ u8 ; 32 ] ;
7
+ const MESSAGE_LENGTH_HEADER_SIZE : usize = 2 ;
8
+ const TAGGED_MESSAGE_LENGTH_HEADER_SIZE : usize = MESSAGE_LENGTH_HEADER_SIZE + chacha:: TAG_SIZE ;
9
+
6
10
/// Returned after a successful handshake to encrypt and decrypt communication with peer nodes.
7
11
/// It should not normally be manually instantiated.
8
12
/// Automatically handles key rotation.
9
13
/// For decryption, it is recommended to call `decrypt_message_stream` for automatic buffering.
10
14
pub struct Conduit {
11
- pub ( crate ) sending_key : [ u8 ; 32 ] ,
12
- pub ( crate ) receiving_key : [ u8 ; 32 ] ,
15
+ pub ( crate ) sending_key : SymmetricKey ,
16
+ pub ( crate ) receiving_key : SymmetricKey ,
13
17
14
- pub ( crate ) sending_chaining_key : [ u8 ; 32 ] ,
15
- pub ( crate ) receiving_chaining_key : [ u8 ; 32 ] ,
18
+ pub ( crate ) sending_chaining_key : SymmetricKey ,
19
+ pub ( crate ) receiving_chaining_key : SymmetricKey ,
16
20
17
21
pub ( crate ) receiving_nonce : u32 ,
18
22
pub ( crate ) sending_nonce : u32 ,
@@ -26,12 +30,12 @@ impl Conduit {
26
30
let length = buffer. len ( ) as u16 ;
27
31
let length_bytes = byte_utils:: be16_to_array ( length) ;
28
32
29
- let mut ciphertext = vec ! [ 0u8 ; 18 + length as usize + 16 ] ;
33
+ let mut ciphertext = vec ! [ 0u8 ; TAGGED_MESSAGE_LENGTH_HEADER_SIZE + length as usize + chacha :: TAG_SIZE ] ;
30
34
31
- ciphertext[ 0 ..18 ] . copy_from_slice ( & chacha:: encrypt ( & self . sending_key , self . sending_nonce as u64 , & [ 0 ; 0 ] , & length_bytes) ) ;
35
+ ciphertext[ 0 ..TAGGED_MESSAGE_LENGTH_HEADER_SIZE ] . copy_from_slice ( & chacha:: encrypt ( & self . sending_key , self . sending_nonce as u64 , & [ 0 ; 0 ] , & length_bytes) ) ;
32
36
self . increment_sending_nonce ( ) ;
33
37
34
- ciphertext[ 18 ..] . copy_from_slice ( & chacha:: encrypt ( & self . sending_key , self . sending_nonce as u64 , & [ 0 ; 0 ] , buffer) ) ;
38
+ ciphertext[ TAGGED_MESSAGE_LENGTH_HEADER_SIZE ..] . copy_from_slice ( & chacha:: encrypt ( & self . sending_key , self . sending_nonce as u64 , & [ 0 ; 0 ] , buffer) ) ;
35
39
self . increment_sending_nonce ( ) ;
36
40
37
41
ciphertext
@@ -42,8 +46,11 @@ impl Conduit {
42
46
read_buffer. extend_from_slice ( data) ;
43
47
}
44
48
45
- /// Add newly received data from the peer node to the buffer and decrypt all possible messages
46
- pub fn decrypt_message_stream ( & mut self , new_data : Option < & [ u8 ] > ) -> Vec < Vec < u8 > > {
49
+ /// Decrypt a single message. If data containing more than one message has been received,
50
+ /// only the first message will be returned, and the rest stored in the internal buffer.
51
+ /// If a message pending in the buffer still hasn't been decrypted, that message will be
52
+ /// returned in lieu of anything new, even if new data is provided.
53
+ pub fn decrypt_single_message ( & mut self , new_data : Option < & [ u8 ] > ) -> Option < Vec < u8 > > {
47
54
let mut read_buffer = if let Some ( buffer) = self . read_buffer . take ( ) {
48
55
buffer
49
56
} else {
@@ -54,45 +61,32 @@ impl Conduit {
54
61
read_buffer. extend_from_slice ( data) ;
55
62
}
56
63
57
- let mut messages = Vec :: new ( ) ;
58
-
59
- loop {
60
- // todo: find way that won't require cloning the entire buffer
61
- let ( current_message, offset) = self . decrypt ( & read_buffer[ ..] ) ;
62
- if offset == 0 {
63
- break ;
64
- }
65
-
66
- read_buffer. drain ( 0 ..offset) ;
67
-
68
- if let Some ( message) = current_message {
69
- messages. push ( message) ;
70
- } else {
71
- break ;
72
- }
64
+ let ( current_message, offset) = self . decrypt ( & read_buffer[ ..] ) ;
65
+ if offset == 0 {
66
+ return None ;
73
67
}
74
68
75
- messages
69
+ read_buffer. drain ( 0 ..offset) ;
70
+ current_message
76
71
}
77
72
78
- /// Decrypt a single message. Buffer is an undelimited amount of bytes
79
- pub ( crate ) fn decrypt ( & mut self , buffer : & [ u8 ] ) -> ( Option < Vec < u8 > > , usize ) { // the response slice should have the same lifetime as the argument. It's the slice data is read from
80
- if buffer. len ( ) < 18 {
73
+ fn decrypt ( & mut self , buffer : & [ u8 ] ) -> ( Option < Vec < u8 > > , usize ) { // the response slice should have the same lifetime as the argument. It's the slice data is read from
74
+ if buffer. len ( ) < TAGGED_MESSAGE_LENGTH_HEADER_SIZE {
81
75
return ( None , 0 ) ;
82
76
}
83
77
84
- let encrypted_length = & buffer[ 0 ..18 ] ; // todo: abort if too short
78
+ let encrypted_length = & buffer[ 0 ..TAGGED_MESSAGE_LENGTH_HEADER_SIZE ] ; // todo: abort if too short
85
79
let length_vec = chacha:: decrypt ( & self . receiving_key , self . receiving_nonce as u64 , & [ 0 ; 0 ] , encrypted_length) . unwrap ( ) ;
86
- let mut length_bytes = [ 0u8 ; 2 ] ;
80
+ let mut length_bytes = [ 0u8 ; MESSAGE_LENGTH_HEADER_SIZE ] ;
87
81
length_bytes. copy_from_slice ( length_vec. as_slice ( ) ) ;
88
82
let message_length = byte_utils:: slice_to_be16 ( & length_bytes) as usize ;
89
83
90
- let message_end_index = message_length + 18 + 16 ; // todo: abort if too short
84
+ let message_end_index = message_length + TAGGED_MESSAGE_LENGTH_HEADER_SIZE + chacha :: TAG_SIZE ; // todo: abort if too short
91
85
if buffer. len ( ) < message_end_index {
92
86
return ( None , 0 ) ;
93
87
}
94
88
95
- let encrypted_message = & buffer[ 18 ..message_end_index] ;
89
+ let encrypted_message = & buffer[ TAGGED_MESSAGE_LENGTH_HEADER_SIZE ..message_end_index] ;
96
90
97
91
self . increment_receiving_nonce ( ) ;
98
92
@@ -111,15 +105,15 @@ impl Conduit {
111
105
Self :: increment_nonce ( & mut self . receiving_nonce , & mut self . receiving_chaining_key , & mut self . receiving_key ) ;
112
106
}
113
107
114
- fn increment_nonce ( nonce : & mut u32 , chaining_key : & mut [ u8 ; 32 ] , key : & mut [ u8 ; 32 ] ) {
108
+ fn increment_nonce ( nonce : & mut u32 , chaining_key : & mut SymmetricKey , key : & mut SymmetricKey ) {
115
109
* nonce += 1 ;
116
110
if * nonce == 1000 {
117
111
Self :: rotate_key ( chaining_key, key) ;
118
112
* nonce = 0 ;
119
113
}
120
114
}
121
115
122
- fn rotate_key ( chaining_key : & mut [ u8 ; 32 ] , key : & mut [ u8 ; 32 ] ) {
116
+ fn rotate_key ( chaining_key : & mut SymmetricKey , key : & mut SymmetricKey ) {
123
117
let ( new_chaining_key, new_key) = hkdf:: derive ( chaining_key, key) ;
124
118
chaining_key. copy_from_slice ( & new_chaining_key) ;
125
119
key. copy_from_slice ( & new_key) ;
@@ -132,6 +126,7 @@ mod tests {
132
126
use ln:: peers:: conduit:: Conduit ;
133
127
134
128
#[ test]
129
+ /// Based on RFC test vectors: https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#message-encryption-tests
135
130
fn test_chaining ( ) {
136
131
let chaining_key_vec = hex:: decode ( "919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01" ) . unwrap ( ) ;
137
132
let mut chaining_key = [ 0u8 ; 32 ] ;
@@ -182,9 +177,7 @@ mod tests {
182
177
183
178
for _ in 0 ..1002 {
184
179
let encrypted_message = encrypted_messages. remove ( 0 ) ;
185
- let mut decrypted_messages = remote_peer. decrypt_message_stream ( Some ( & encrypted_message) ) ;
186
- assert_eq ! ( decrypted_messages. len( ) , 1 ) ;
187
- let decrypted_message = decrypted_messages. remove ( 0 ) ;
180
+ let decrypted_message = remote_peer. decrypt_single_message ( Some ( & encrypted_message) ) . unwrap ( ) ;
188
181
assert_eq ! ( decrypted_message, hex:: decode( "68656c6c6f" ) . unwrap( ) ) ;
189
182
}
190
183
}
0 commit comments