use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine};
use bitcoin::secp256k1::PublicKey;
use crate::ln::types::ChannelId;
use crate::sign::PeerStorageKey;
use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC;
use crate::prelude::*;
pub struct DecryptedOurPeerStorage {
data: Vec<u8>,
}
impl DecryptedOurPeerStorage {
pub fn new(data: Vec<u8>) -> Self {
Self { data }
}
pub fn into_vec(self) -> Vec<u8> {
self.data
}
pub fn encrypt(self, key: &PeerStorageKey, random_bytes: &[u8; 32]) -> EncryptedOurPeerStorage {
let mut data = self.data;
let plaintext_len = data.len();
let nonce = derive_nonce(key, random_bytes);
let mut chacha = ChaCha20Poly1305RFC::new(&key.inner, &nonce, b"");
let mut tag = [0; 16];
chacha.encrypt_full_message_in_place(&mut data[0..plaintext_len], &mut tag);
data.extend_from_slice(&tag);
data.extend_from_slice(random_bytes);
EncryptedOurPeerStorage { cipher: data }
}
}
pub struct EncryptedOurPeerStorage {
cipher: Vec<u8>,
}
impl EncryptedOurPeerStorage {
const MIN_CIPHERTEXT_LEN: usize = 32 + 16;
pub fn new(cipher: Vec<u8>) -> Result<Self, ()> {
if cipher.len() < Self::MIN_CIPHERTEXT_LEN {
return Err(());
}
return Ok(Self { cipher });
}
pub fn into_vec(self) -> Vec<u8> {
self.cipher
}
pub fn decrypt(self, key: &PeerStorageKey) -> Result<DecryptedOurPeerStorage, ()> {
let mut cipher = self.cipher;
let cyphertext_len = cipher.len();
if cipher.len() < Self::MIN_CIPHERTEXT_LEN {
return Err(());
}
let (data_mut, random_bytes) = cipher.split_at_mut(cyphertext_len - 32);
let (encrypted_data, tag) = data_mut.split_at_mut(data_mut.len() - 16);
let nonce = derive_nonce(key, random_bytes);
let mut chacha = ChaCha20Poly1305RFC::new(&key.inner, &nonce, b"");
if chacha.check_decrypt_in_place(encrypted_data, tag).is_err() {
return Err(());
}
cipher.truncate(cyphertext_len - 16 - 32);
Ok(DecryptedOurPeerStorage { data: cipher })
}
}
fn derive_nonce(key: &PeerStorageKey, random_bytes: &[u8]) -> [u8; 12] {
let key_hash = Sha256::hash(&key.inner);
let mut hmac = HmacEngine::<Sha256>::new(key_hash.as_byte_array());
hmac.input(&random_bytes);
let mut nonce = [0u8; 12];
nonce[4..].copy_from_slice(&Hmac::from_engine(hmac).to_byte_array()[0..8]);
nonce
}
pub(crate) struct PeerStorageMonitorHolder {
pub(crate) channel_id: ChannelId,
pub(crate) counterparty_node_id: PublicKey,
pub(crate) min_seen_secret: u64,
pub(crate) monitor_bytes: Vec<u8>,
}
impl_writeable_tlv_based!(PeerStorageMonitorHolder, {
(0, channel_id, required),
(2, counterparty_node_id, required),
(4, min_seen_secret, required),
(6, monitor_bytes, required_vec),
});
#[cfg(test)]
mod tests {
use crate::ln::our_peer_storage::{derive_nonce, DecryptedOurPeerStorage};
use crate::sign::PeerStorageKey;
#[test]
fn test_peer_storage_encryption_decryption() {
let key1 = PeerStorageKey { inner: [0u8; 32] };
let key2 = PeerStorageKey { inner: [1u8; 32] };
let random_bytes1 = [200; 32];
let random_bytes2 = [201; 32];
let decrypted_ops = DecryptedOurPeerStorage::new(vec![42u8; 32]);
let decrypted_ops_res: DecryptedOurPeerStorage =
decrypted_ops.encrypt(&key1, &random_bytes1).decrypt(&key1).unwrap();
assert_eq!(decrypted_ops_res.into_vec(), vec![42u8; 32]);
let decrypted_ops_wrong_key = DecryptedOurPeerStorage::new(vec![42u8; 32]);
let decrypted_ops_wrong_key_res =
decrypted_ops_wrong_key.encrypt(&key2, &random_bytes2).decrypt(&key1);
assert!(decrypted_ops_wrong_key_res.is_err());
let nonce = derive_nonce(&key1, &random_bytes1);
let nonce_happy_path = derive_nonce(&key1, &random_bytes1);
assert_eq!(nonce, nonce_happy_path);
let nonce_diff_random_bytes = derive_nonce(&key1, &random_bytes2);
let nonce_diff_key = derive_nonce(&key2, &random_bytes1);
let nonce_diff_key_random_bytes = derive_nonce(&key2, &random_bytes2);
assert_ne!(nonce, nonce_diff_random_bytes);
assert_ne!(nonce, nonce_diff_key);
assert_ne!(nonce, nonce_diff_key_random_bytes);
}
}