Skip to content

Commit 7abc134

Browse files
committed
fixup: Add OurPeerStorage for serialized Peer Storage backups
1 parent 28aff94 commit 7abc134

File tree

1 file changed

+56
-29
lines changed

1 file changed

+56
-29
lines changed

lightning/src/ln/our_peer_storage.rs

+56-29
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
// You may not use this file except in accordance with one or both of these
88
// licenses.
99

10-
//! `OurPeerStorage` enables versioned storage of serialized channel data.
11-
//! It supports encryption and decryption to maintain data integrity and security during
12-
//! transmission.
10+
//! `OurPeerStorage` enables storage of encrypted serialized channel data.
11+
//! It provides encryption and decryption of data to maintain data integrity and
12+
//! security during transmission.
1313
//!
14+
1415
use bitcoin::hashes::sha256::Hash as Sha256;
1516
use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine};
1617

@@ -19,14 +20,15 @@ use crate::sign::PeerStorageKey;
1920
use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC;
2021
use crate::prelude::*;
2122

22-
/// [`OurPeerStorage`] is used to store channel information that allows for the creation of a
23+
/// [`OurPeerStorage`] is used to store encrypted channel information that allows for the creation of a
2324
/// `peer_storage` backup.
2425
///
2526
/// This structure is designed to serialize channel data for backup and supports encryption
26-
/// and decryption using `ChaCha20Poly1305RFC` to ensure data integrity and security during exchange or storage.
27+
/// and decryption using `ChaCha20Poly1305RFC` for transmission.
2728
///
2829
/// # Key Methods
29-
/// - [`OurPeerStorage::create_from_data`]: Returns an encrypted [`OurPeerStorage`] instance created from the provided data.
30+
/// - [`OurPeerStorage::new`]: Returns [`OurPeerStorage`] with the given encrypted_data.
31+
/// - [`OurPeerStorage::create_from_data`]: Returns [`OurPeerStorage`] created from encrypting the provided data.
3032
/// - [`OurPeerStorage::decrypt_our_peer_storage`]: Decrypts the [`OurPeerStorage::encrypted_data`] using the key and returns decrypted data.
3133
///
3234
/// ## Example
@@ -45,6 +47,8 @@ pub struct OurPeerStorage {
4547

4648
impl OurPeerStorage {
4749
/// Creates a new [`OurPeerStorage`] with given encrypted_data.
50+
/// Returns an error if the `encrypted_data` is less than the
51+
/// appropriate length.
4852
pub fn new(encrypted_data: Vec<u8>) -> Result<Self, ()> {
4953
// Length of tag + Length of random_bytes
5054
const MIN_CYPHERTEXT_LEN: usize = 16 + 32;
@@ -61,39 +65,26 @@ impl OurPeerStorage {
6165
self.encrypted_data
6266
}
6367

64-
/// Nonce for encryption and decryption: Hmac(Sha256(key) + random_bytes).
65-
fn derive_nonce(key: &PeerStorageKey, random_bytes: &[u8]) -> [u8; 12] {
66-
let key_hash = Sha256::const_hash(&key.inner);
67-
68-
let mut hmac = HmacEngine::<Sha256>::new(key_hash.as_byte_array());
69-
hmac.input(&random_bytes);
70-
let mut nonce = [0u8; 12];
71-
// First 4 bytes of the nonce should be 0.
72-
nonce[4..].copy_from_slice(&Hmac::from_engine(hmac).to_byte_array()[0..8]);
73-
74-
nonce
75-
}
76-
77-
/// Creates a serialised representation of [`OurPeerStorage`] from the given `ser_channels` data.
68+
/// Returns [`OurPeerStorage`] with encrypted `ser_channels`.
7869
///
7970
/// This function takes a `key` (for encryption), `ser_channels` data
80-
/// (serialised channel information) and random_bytes (to derive nonce for encryption) and returns a serialised
81-
/// [`OurPeerStorage`] as a `Vec<u8>`.
71+
/// (serialised channel information) and random_bytes (to derive nonce for encryption) and returns a
72+
/// [`OurPeerStorage`] with encrypted data inside.
8273
///
8374
/// The resulting serialised data is intended to be directly used for transmission to the peers.
8475
pub fn create_from_data(
8576
key: PeerStorageKey, mut ser_channels: Vec<u8>, random_bytes: [u8; 32],
8677
) -> OurPeerStorage {
8778
let plaintext_len = ser_channels.len();
88-
let nonce = OurPeerStorage::derive_nonce(&key, &random_bytes);
79+
let nonce = derive_nonce(&key, &random_bytes);
8980

9081
let mut chacha = ChaCha20Poly1305RFC::new(&key.inner, &nonce, b"");
9182
let mut tag = [0; 16];
9283
chacha.encrypt_full_message_in_place(&mut ser_channels[0..plaintext_len], &mut tag);
9384

9485
ser_channels.extend_from_slice(&tag);
9586

96-
// Append `random_bytes` in front of the encrypted_blob.
87+
// Prepend `random_bytes` in front of the encrypted_blob.
9788
ser_channels.splice(0..0, random_bytes);
9889
Self { encrypted_data: ser_channels }
9990
}
@@ -107,7 +98,7 @@ impl OurPeerStorage {
10798
let (data_mut, tag) = self.encrypted_data.split_at_mut(cyphertext_len - 16);
10899
let (random_bytes, encrypted_data) = data_mut.split_at_mut(32);
109100

110-
let nonce = OurPeerStorage::derive_nonce(&key, random_bytes);
101+
let nonce = derive_nonce(&key, random_bytes);
111102

112103
let mut chacha = ChaCha20Poly1305RFC::new(&key.inner, &nonce, b"");
113104

@@ -122,18 +113,54 @@ impl OurPeerStorage {
122113
}
123114
}
124115

116+
/// Nonce for encryption and decryption: Hmac(Sha256(key) + random_bytes).
117+
fn derive_nonce(key: &PeerStorageKey, random_bytes: &[u8]) -> [u8; 12] {
118+
let key_hash = Sha256::const_hash(&key.inner);
119+
120+
let mut hmac = HmacEngine::<Sha256>::new(key_hash.as_byte_array());
121+
hmac.input(&random_bytes);
122+
let mut nonce = [0u8; 12];
123+
// First 4 bytes of the nonce should be 0.
124+
nonce[4..].copy_from_slice(&Hmac::from_engine(hmac).to_byte_array()[0..8]);
125+
126+
nonce
127+
}
128+
125129
#[cfg(test)]
126130
mod tests {
127-
use crate::ln::our_peer_storage::OurPeerStorage;
131+
use crate::ln::our_peer_storage::{derive_nonce, OurPeerStorage};
128132
use crate::sign::PeerStorageKey;
129133

130134
#[test]
131135
fn test_peer_storage_encryption_decryption() {
132-
let key = PeerStorageKey { inner: [0u8; 32] };
136+
let key1 = PeerStorageKey { inner: [0u8; 32] };
137+
let key2 = PeerStorageKey { inner: [1u8; 32] };
138+
let random_bytes1 = [200; 32];
139+
let random_bytes2 = [201; 32];
133140

141+
// Happy Path
134142
let our_peer_storage =
135-
OurPeerStorage::create_from_data(key.clone(), vec![42u8; 32], [200; 32]);
136-
let decrypted_data = our_peer_storage.decrypt_our_peer_storage(key).unwrap();
143+
OurPeerStorage::create_from_data(key1.clone(), vec![42u8; 32], random_bytes1);
144+
let decrypted_data = our_peer_storage.decrypt_our_peer_storage(key1.clone()).unwrap();
137145
assert_eq!(decrypted_data, vec![42u8; 32]);
146+
147+
// Changing Key
148+
let our_peer_storage_wrong_key =
149+
OurPeerStorage::create_from_data(key1.clone(), vec![42u8; 32], random_bytes1);
150+
let decrypted_data_wrong_key = our_peer_storage_wrong_key.decrypt_our_peer_storage(key2);
151+
assert!(decrypted_data_wrong_key.is_err());
152+
153+
// Nonce derivation happy path
154+
let nonce = derive_nonce(&key1, &random_bytes1);
155+
let nonce_happy_path = derive_nonce(&key1, &random_bytes1);
156+
assert_eq!(nonce, nonce_happy_path);
157+
158+
// Nonce derivation with different `random_bytes` & `key`
159+
let nonce_diff_random_bytes = derive_nonce(&key1, &random_bytes2);
160+
let nonce_diff_key = derive_nonce(&key2, &random_bytes1);
161+
let nonce_diff_key_random_bytes = derive_nonce(&key2, &random_bytes2);
162+
assert_ne!(nonce, nonce_diff_random_bytes);
163+
assert_ne!(nonce, nonce_diff_key);
164+
assert_ne!(nonce, nonce_diff_key_random_bytes);
138165
}
139166
}

0 commit comments

Comments
 (0)