1+ use ln:: peers:: { chacha, hkdf} ;
2+
3+ /// Returned after a successful handshake to encrypt and decrypt communication with peer nodes
4+ pub struct Conduit {
5+ pub ( crate ) sending_key : [ u8 ; 32 ] ,
6+ pub ( crate ) receiving_key : [ u8 ; 32 ] ,
7+
8+ pub ( crate ) sending_chaining_key : [ u8 ; 32 ] ,
9+ pub ( crate ) receiving_chaining_key : [ u8 ; 32 ] ,
10+
11+ pub ( crate ) receiving_nonce : u32 ,
12+ pub ( crate ) sending_nonce : u32 ,
13+
14+ pub ( super ) read_buffer : Option < Vec < u8 > > ,
15+ }
16+
17+ impl Conduit {
18+ pub fn encrypt ( & mut self , buffer : & [ u8 ] ) -> Vec < u8 > {
19+ let length = buffer. len ( ) as u16 ;
20+ let length_bytes = length. to_be_bytes ( ) ;
21+
22+ let encrypted_length = chacha:: encrypt ( & self . sending_key , self . sending_nonce as u64 , & [ 0 ; 0 ] , & length_bytes) ;
23+ self . increment_sending_nonce ( ) ;
24+
25+ let encrypted_message = chacha:: encrypt ( & self . sending_key , self . sending_nonce as u64 , & [ 0 ; 0 ] , buffer) ;
26+ self . increment_sending_nonce ( ) ;
27+
28+ let mut ciphertext = encrypted_length;
29+ ciphertext. extend_from_slice ( & encrypted_message) ;
30+ ciphertext
31+ }
32+
33+ pub ( super ) fn read ( & mut self , data : & [ u8 ] ) {
34+ let mut read_buffer = if let Some ( buffer) = self . read_buffer . take ( ) {
35+ buffer
36+ } else {
37+ Vec :: new ( )
38+ } ;
39+
40+ read_buffer. extend_from_slice ( data) ;
41+ self . read_buffer = Some ( read_buffer) ;
42+ }
43+
44+ /// Add newly received data from the peer node to the buffer and decrypt all possible messages
45+ pub fn decrypt_message_stream ( & mut self , new_data : Option < & [ u8 ] > ) -> Vec < Vec < u8 > > {
46+ let mut read_buffer = if let Some ( buffer) = self . read_buffer . take ( ) {
47+ buffer
48+ } else {
49+ Vec :: new ( )
50+ } ;
51+
52+ if let Some ( data) = new_data {
53+ read_buffer. extend_from_slice ( data) ;
54+ }
55+
56+ let mut messages = Vec :: new ( ) ;
57+
58+ loop {
59+ // todo: find way that won't require cloning the entire buffer
60+ let ( current_message, offset) = self . decrypt ( & read_buffer[ ..] ) ;
61+ if offset == 0 {
62+ break ;
63+ }
64+
65+ read_buffer. drain ( 0 ..offset) ;
66+
67+ if let Some ( message) = current_message {
68+ messages. push ( message) ;
69+ } else {
70+ break ;
71+ }
72+ }
73+
74+ self . read_buffer = Some ( read_buffer) ;
75+
76+ messages
77+ }
78+
79+ /// Decrypt a single message. Buffer is an undelimited amount of bytes
80+ 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
81+ if buffer. len ( ) < 18 {
82+ return ( None , 0 ) ;
83+ }
84+
85+ let encrypted_length = & buffer[ 0 ..18 ] ; // todo: abort if too short
86+ let length_vec = chacha:: decrypt ( & self . receiving_key , self . receiving_nonce as u64 , & [ 0 ; 0 ] , encrypted_length) . unwrap ( ) ;
87+ let mut length_bytes = [ 0u8 ; 2 ] ;
88+ length_bytes. copy_from_slice ( length_vec. as_slice ( ) ) ;
89+ let message_length = u16:: from_be_bytes ( length_bytes) as usize ;
90+
91+ let message_end_index = message_length + 18 ; // todo: abort if too short
92+ if buffer. len ( ) < message_end_index {
93+ return ( None , 0 ) ;
94+ }
95+
96+ let encrypted_message = & buffer[ 18 ..message_end_index] ;
97+
98+ self . increment_receiving_nonce ( ) ;
99+
100+ let message = chacha:: decrypt ( & self . receiving_key , self . receiving_nonce as u64 , & [ 0 ; 0 ] , encrypted_message) . unwrap ( ) ;
101+
102+ self . increment_receiving_nonce ( ) ;
103+
104+ ( Some ( message) , message_end_index)
105+ }
106+
107+ fn increment_sending_nonce ( & mut self ) {
108+ Self :: increment_nonce ( & mut self . sending_nonce , & mut self . sending_chaining_key , & mut self . sending_key ) ;
109+ }
110+
111+ fn increment_receiving_nonce ( & mut self ) {
112+ Self :: increment_nonce ( & mut self . receiving_nonce , & mut self . receiving_chaining_key , & mut self . receiving_key ) ;
113+ }
114+
115+ fn increment_nonce ( nonce : & mut u32 , chaining_key : & mut [ u8 ; 32 ] , key : & mut [ u8 ; 32 ] ) {
116+ * nonce += 1 ;
117+ if * nonce == 1000 {
118+ Self :: rotate_key ( chaining_key, key) ;
119+ * nonce = 0 ;
120+ }
121+ }
122+
123+ fn rotate_key ( chaining_key : & mut [ u8 ; 32 ] , key : & mut [ u8 ; 32 ] ) {
124+ let ( new_chaining_key, new_key) = hkdf:: derive ( chaining_key, key) ;
125+ chaining_key. copy_from_slice ( & new_chaining_key) ;
126+ key. copy_from_slice ( & new_key) ;
127+ }
128+ }
129+
130+ #[ cfg( test) ]
131+ mod tests {
132+ use ln:: peers:: conduit:: Conduit ;
133+
134+ #[ test]
135+ fn test_chaining ( ) {
136+ let chaining_key_vec = hex:: decode ( "919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01" ) . unwrap ( ) ;
137+ let mut chaining_key = [ 0u8 ; 32 ] ;
138+ chaining_key. copy_from_slice ( & chaining_key_vec) ;
139+
140+ let sending_key_vec = hex:: decode ( "969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9" ) . unwrap ( ) ;
141+ let mut sending_key = [ 0u8 ; 32 ] ;
142+ sending_key. copy_from_slice ( & sending_key_vec) ;
143+
144+ let receiving_key_vec = hex:: decode ( "bb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442" ) . unwrap ( ) ;
145+ let mut receiving_key = [ 0u8 ; 32 ] ;
146+ receiving_key. copy_from_slice ( & receiving_key_vec) ;
147+
148+ let mut connected_peer = Conduit {
149+ sending_key,
150+ receiving_key,
151+ sending_chaining_key : chaining_key,
152+ receiving_chaining_key : chaining_key,
153+ sending_nonce : 0 ,
154+ receiving_nonce : 0 ,
155+ read_buffer : None ,
156+ } ;
157+
158+ let message = hex:: decode ( "68656c6c6f" ) . unwrap ( ) ;
159+ let mut encrypted_messages: Vec < Vec < u8 > > = Vec :: new ( ) ;
160+
161+ for _ in 0 ..1002 {
162+ let encrypted_message = connected_peer. encrypt ( & message) ;
163+ encrypted_messages. push ( encrypted_message) ;
164+ }
165+
166+ assert_eq ! ( encrypted_messages[ 0 ] , hex:: decode( "cf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95" ) . unwrap( ) ) ;
167+ assert_eq ! ( encrypted_messages[ 1 ] , hex:: decode( "72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1" ) . unwrap( ) ) ;
168+ assert_eq ! ( encrypted_messages[ 500 ] , hex:: decode( "178cb9d7387190fa34db9c2d50027d21793c9bc2d40b1e14dcf30ebeeeb220f48364f7a4c68bf8" ) . unwrap( ) ) ;
169+ assert_eq ! ( encrypted_messages[ 501 ] , hex:: decode( "1b186c57d44eb6de4c057c49940d79bb838a145cb528d6e8fd26dbe50a60ca2c104b56b60e45bd" ) . unwrap( ) ) ;
170+ assert_eq ! ( encrypted_messages[ 1000 ] , hex:: decode( "4a2f3cc3b5e78ddb83dcb426d9863d9d9a723b0337c89dd0b005d89f8d3c05c52b76b29b740f09" ) . unwrap( ) ) ;
171+ assert_eq ! ( encrypted_messages[ 1001 ] , hex:: decode( "2ecd8c8a5629d0d02ab457a0fdd0f7b90a192cd46be5ecb6ca570bfc5e268338b1a16cf4ef2d36" ) . unwrap( ) ) ;
172+ }
173+ }
0 commit comments