Skip to content

Commit bf0ce81

Browse files
committed
address some of Jeff's comments pertaining to message decryption, constants, and type definitions
1 parent 100e5a9 commit bf0ce81

File tree

4 files changed

+55
-70
lines changed

4 files changed

+55
-70
lines changed

lightning/src/ln/peer_handler.rs

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,15 @@ enum InitSyncTracker{
108108
}
109109

110110
enum PeerState {
111-
Handshake(PeerHandshake),
111+
Authenticating(PeerHandshake),
112112
Connected(Conduit),
113113
}
114114

115115
impl PeerState {
116116
fn is_ready_for_encryption(&self) -> bool {
117-
if let &PeerState::Connected(_) = self {
118-
true
119-
} else {
120-
false
117+
match self {
118+
&PeerState::Connected(_) => true,
119+
_ => false
121120
}
122121
}
123122
}
@@ -283,7 +282,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where
283282

284283
let mut peers = self.peers.lock().unwrap();
285284
if peers.peers.insert(descriptor, Peer {
286-
encryptor: PeerState::Handshake(handshake),
285+
encryptor: PeerState::Authenticating(handshake),
287286
outbound: true,
288287
their_node_id: Some(their_node_id.clone()),
289288
their_features: None,
@@ -318,7 +317,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where
318317

319318
let mut peers = self.peers.lock().unwrap();
320319
if peers.peers.insert(descriptor, Peer {
321-
encryptor: PeerState::Handshake(handshake),
320+
encryptor: PeerState::Authenticating(handshake),
322321
outbound: false,
323322
their_node_id: None,
324323
their_features: None,
@@ -469,9 +468,9 @@ impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where
469468
let mut conduit_option = None;
470469
let mut remote_pubkey_option = None;
471470

472-
if let &mut PeerState::Handshake(ref mut handshake) = &mut peer.encryptor {
471+
if let &mut PeerState::Authenticating(ref mut handshake) = &mut peer.encryptor {
473472
let (response, conduit, remote_pubkey) = handshake.process_act(&peer.pending_read_buffer, None).unwrap();
474-
peer.pending_read_buffer.drain(..); // we read it all
473+
peer.pending_read_buffer = Vec::new(); // empty the pending read buffer
475474

476475
if let Some(key) = remote_pubkey {
477476
remote_pubkey_option = Some(key);
@@ -531,18 +530,12 @@ impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where
531530
}
532531
}
533532

534-
let mut next_message_result = conduit.decrypt(&peer.pending_read_buffer);
535-
536-
let offset = next_message_result.1;
537-
if offset == 0 {
538-
// nothing got read
533+
let message_option = conduit.decrypt_single_message(Some(&peer.pending_read_buffer));
534+
let msg_data = if let Some(message) = message_option {
535+
message
536+
} else {
539537
break;
540-
}else{
541-
peer.pending_read_buffer.drain(0..offset);
542-
}
543-
544-
// something got read, so we definitely have a message
545-
let msg_data = next_message_result.0.unwrap();
538+
};
546539

547540
let mut reader = ::std::io::Cursor::new(&msg_data[..]);
548541
let message_result = wire::read(&mut reader);

lightning/src/ln/peers/chacha.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use util::byte_utils;
22
use util::chacha20poly1305rfc::ChaCha20Poly1305RFC;
33

4+
pub const TAG_SIZE: usize = 16;
5+
46
pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8]) -> Vec<u8> {
57
let mut nonce_bytes = [0; 12];
68
nonce_bytes[4..].copy_from_slice(&byte_utils::le64_to_array(nonce));
@@ -15,7 +17,6 @@ pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8])
1517
tagged_ciphertext
1618
}
1719

18-
1920
pub fn decrypt(key: &[u8], nonce: u64, associated_data: &[u8], tagged_ciphertext: &[u8]) -> Result<Vec<u8>, String> {
2021
let mut nonce_bytes = [0; 12];
2122
nonce_bytes[4..].copy_from_slice(&byte_utils::le64_to_array(nonce));

lightning/src/ln/peers/conduit.rs

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,20 @@
33
use ln::peers::{chacha, hkdf};
44
use util::byte_utils;
55

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+
610
/// Returned after a successful handshake to encrypt and decrypt communication with peer nodes.
711
/// It should not normally be manually instantiated.
812
/// Automatically handles key rotation.
913
/// For decryption, it is recommended to call `decrypt_message_stream` for automatic buffering.
1014
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,
1317

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,
1620

1721
pub(crate) receiving_nonce: u32,
1822
pub(crate) sending_nonce: u32,
@@ -26,12 +30,12 @@ impl Conduit {
2630
let length = buffer.len() as u16;
2731
let length_bytes = byte_utils::be16_to_array(length);
2832

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];
3034

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));
3236
self.increment_sending_nonce();
3337

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));
3539
self.increment_sending_nonce();
3640

3741
ciphertext
@@ -42,8 +46,11 @@ impl Conduit {
4246
read_buffer.extend_from_slice(data);
4347
}
4448

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>> {
4754
let mut read_buffer = if let Some(buffer) = self.read_buffer.take() {
4855
buffer
4956
} else {
@@ -54,45 +61,32 @@ impl Conduit {
5461
read_buffer.extend_from_slice(data);
5562
}
5663

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;
7367
}
7468

75-
messages
69+
read_buffer.drain(0..offset);
70+
current_message
7671
}
7772

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 {
8175
return (None, 0);
8276
}
8377

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
8579
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];
8781
length_bytes.copy_from_slice(length_vec.as_slice());
8882
let message_length = byte_utils::slice_to_be16(&length_bytes) as usize;
8983

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
9185
if buffer.len() < message_end_index {
9286
return (None, 0);
9387
}
9488

95-
let encrypted_message = &buffer[18..message_end_index];
89+
let encrypted_message = &buffer[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..message_end_index];
9690

9791
self.increment_receiving_nonce();
9892

@@ -111,15 +105,15 @@ impl Conduit {
111105
Self::increment_nonce(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key);
112106
}
113107

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) {
115109
*nonce += 1;
116110
if *nonce == 1000 {
117111
Self::rotate_key(chaining_key, key);
118112
*nonce = 0;
119113
}
120114
}
121115

122-
fn rotate_key(chaining_key: &mut [u8; 32], key: &mut [u8; 32]) {
116+
fn rotate_key(chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) {
123117
let (new_chaining_key, new_key) = hkdf::derive(chaining_key, key);
124118
chaining_key.copy_from_slice(&new_chaining_key);
125119
key.copy_from_slice(&new_key);
@@ -132,6 +126,7 @@ mod tests {
132126
use ln::peers::conduit::Conduit;
133127

134128
#[test]
129+
/// Based on RFC test vectors: https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#message-encryption-tests
135130
fn test_chaining() {
136131
let chaining_key_vec = hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap();
137132
let mut chaining_key = [0u8; 32];
@@ -182,9 +177,7 @@ mod tests {
182177

183178
for _ in 0..1002 {
184179
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();
188181
assert_eq!(decrypted_message, hex::decode("68656c6c6f").unwrap());
189182
}
190183
}

lightning/src/ln/peers/handshake/mod.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,12 @@ pub struct PeerHandshake {
3232
impl PeerHandshake {
3333
/// Instantiate a new handshake with a node identity secret key and an ephemeral private key
3434
pub fn new(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self {
35-
let handshake = PeerHandshake {
35+
Self {
3636
state: Some(HandshakeState::Blank),
3737
private_key: (*private_key).clone(),
3838
ephemeral_private_key: (*ephemeral_private_key).clone(),
3939
read_buffer: Vec::new(),
40-
};
41-
handshake
40+
}
4241
}
4342

4443
/// Make the handshake object inbound in anticipation of a peer's first handshake act
@@ -52,7 +51,6 @@ impl PeerHandshake {
5251
}
5352

5453
fn initialize_state(public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) {
55-
// do the proper initialization
5654
let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256";
5755
let prologue = b"lightning";
5856

@@ -66,7 +64,7 @@ impl PeerHandshake {
6664
let mut hash = HandshakeHash::new(initial_hash_preimage.as_slice());
6765
hash.update(&public_key.serialize());
6866

69-
(hash, chaining_key) // hash, chaining_key
67+
(hash, chaining_key)
7068
}
7169

7270
/// Process act dynamically
@@ -154,7 +152,7 @@ impl PeerHandshake {
154152
let (mut hash, chaining_key) = Self::initialize_state(&remote_public_key);
155153

156154
// serialize act one
157-
let (act_one, chaining_key, temporary_key) = self.calculate_act_message(
155+
let (act_one, chaining_key, temporary_key) = Self::calculate_act_message(
158156
&self.ephemeral_private_key,
159157
remote_public_key,
160158
chaining_key,
@@ -193,7 +191,7 @@ impl PeerHandshake {
193191
};
194192

195193
let mut hash = act_one_expectation.hash;
196-
let (remote_ephemeral_public_key, chaining_key, _) = self.process_act_message(
194+
let (remote_ephemeral_public_key, chaining_key, _) = Self::process_act_message(
197195
act.0,
198196
&self.private_key,
199197
act_one_expectation.chaining_key,
@@ -202,7 +200,7 @@ impl PeerHandshake {
202200

203201
let ephemeral_private_key = (*&self.ephemeral_private_key).clone();
204202

205-
let (act_two, chaining_key, temporary_key) = self.calculate_act_message(
203+
let (act_two, chaining_key, temporary_key) = Self::calculate_act_message(
206204
&ephemeral_private_key,
207205
&remote_ephemeral_public_key,
208206
chaining_key,
@@ -232,7 +230,7 @@ impl PeerHandshake {
232230
};
233231

234232
let mut hash = act_two_expectation.hash;
235-
let (remote_ephemeral_public_key, chaining_key, temporary_key) = self.process_act_message(
233+
let (remote_ephemeral_public_key, chaining_key, temporary_key) = Self::process_act_message(
236234
act.0,
237235
&act_two_expectation.ephemeral_private_key,
238236
act_two_expectation.chaining_key,
@@ -317,7 +315,7 @@ impl PeerHandshake {
317315
Ok((remote_pubkey, connected_peer))
318316
}
319317

320-
fn calculate_act_message(&self, local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], [u8; 32], [u8; 32]) {
318+
fn calculate_act_message(local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], [u8; 32], [u8; 32]) {
321319
let local_public_key = Self::private_key_to_public_key(local_private_key);
322320

323321
hash.update(&local_public_key.serialize());
@@ -335,7 +333,7 @@ impl PeerHandshake {
335333
(act, chaining_key, temporary_key)
336334
}
337335

338-
fn process_act_message(&self, act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> Result<(PublicKey, [u8; 32], [u8; 32]), String> {
336+
fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> Result<(PublicKey, [u8; 32], [u8; 32]), String> {
339337
let version = act_bytes[0];
340338
if version != 0 {
341339
return Err("unexpected version".to_string());

0 commit comments

Comments
 (0)