Skip to content

Commit eb6a371

Browse files
committed
build scaffold for handshake module substitution support
1 parent 3c9e8c9 commit eb6a371

File tree

10 files changed

+744
-1
lines changed

10 files changed

+744
-1
lines changed

lightning/src/ln/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod channelmanager;
1313
pub mod channelmonitor;
1414
pub mod msgs;
1515
pub mod router;
16+
pub mod peers;
1617
pub mod peer_handler;
1718
pub mod chan_utils;
1819
pub mod features;
@@ -27,7 +28,8 @@ mod onion_utils;
2728
mod wire;
2829

2930
#[cfg(test)]
30-
#[macro_use] mod functional_test_utils;
31+
#[macro_use]
32+
mod functional_test_utils;
3133
#[cfg(test)]
3234
mod functional_tests;
3335
#[cfg(test)]

lightning/src/ln/peers/chacha.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use util::chacha20poly1305rfc::ChaCha20Poly1305RFC;
2+
3+
pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8]) -> Vec<u8> {
4+
let mut nonce_bytes = [0; 12];
5+
nonce_bytes[4..].copy_from_slice(&nonce.to_le_bytes());
6+
7+
let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce_bytes, associated_data);
8+
let mut ciphertext = vec![0u8; plaintext.len()];
9+
let mut authentication_tag = [0u8; 16];
10+
chacha.encrypt(plaintext, &mut ciphertext, &mut authentication_tag);
11+
12+
let mut tagged_ciphertext = ciphertext;
13+
tagged_ciphertext.extend_from_slice(&authentication_tag);
14+
tagged_ciphertext
15+
}
16+
17+
18+
pub fn decrypt(key: &[u8], nonce: u64, associated_data: &[u8], tagged_ciphertext: &[u8]) -> Result<Vec<u8>, String> {
19+
let mut nonce_bytes = [0; 12];
20+
nonce_bytes[4..].copy_from_slice(&nonce.to_le_bytes());
21+
22+
let length = tagged_ciphertext.len();
23+
let ciphertext = &tagged_ciphertext[0..length - 16];
24+
let authentication_tag = &tagged_ciphertext[length - 16..length];
25+
26+
let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce_bytes, associated_data);
27+
let mut plaintext = vec![0u8; length - 16];
28+
let success = chacha.decrypt(ciphertext, &mut plaintext, authentication_tag);
29+
if success {
30+
Ok(plaintext.to_vec())
31+
} else {
32+
Err("invalid hmac".to_string())
33+
}
34+
}

lightning/src/ln/peers/conduit.rs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
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+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
pub struct ActOne(
2+
pub(super) [u8; 50]
3+
);
4+
5+
pub struct ActTwo(
6+
pub(super) [u8; 50]
7+
);
8+
9+
pub struct ActThree(
10+
pub(super) [u8; 66]
11+
);
12+
13+
pub enum Act {
14+
One(ActOne),
15+
Two(ActTwo),
16+
Three(ActThree),
17+
}
18+
19+
impl Act {
20+
pub fn serialize(&self) -> Vec<u8> {
21+
match self {
22+
Act::One(act) => {
23+
act.0.to_vec()
24+
}
25+
Act::Two(act) => {
26+
act.0.to_vec()
27+
}
28+
Act::Three(act) => {
29+
act.0.to_vec()
30+
}
31+
}
32+
}
33+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use bitcoin_hashes::{Hash, HashEngine};
2+
use bitcoin_hashes::sha256::Hash as Sha256;
3+
4+
pub(crate) struct HandshakeHash {
5+
pub(super) value: [u8; 32]
6+
}
7+
8+
impl HandshakeHash {
9+
pub(super) fn new(first_input: &[u8]) -> Self {
10+
let mut hash = Self {
11+
value: [0; 32]
12+
};
13+
let mut sha = Sha256::engine();
14+
sha.input(first_input);
15+
hash.value = Sha256::from_engine(sha).into_inner();
16+
hash
17+
}
18+
19+
pub(super) fn update(&mut self, input: &[u8]) {
20+
let mut sha = Sha256::engine();
21+
sha.input(self.value.as_ref());
22+
sha.input(input);
23+
self.value = Sha256::from_engine(sha).into_inner();
24+
}
25+
}

0 commit comments

Comments
 (0)