bs_gl_client/
export.rs

1//! Utilities to work with export/backup files.
2use anyhow::{anyhow, Context, Error};
3use bytes::{Buf, Bytes, BytesMut};
4use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, KeyInit};
5use lightning_signer::bitcoin::{
6    secp256k1::{ecdh::SharedSecret, PublicKey, Secp256k1, SecretKey},
7    Network,
8};
9use std::io::Read;
10
11const VERSION: u8 = 0x01;
12/// Version byte, node ID, nonce, tag
13const HEADER_LEN: usize = 1 + 33 + 12 + 16;
14
15pub fn decrypt_with_seed(enc: BytesMut, seed: &SecretKey) -> Result<Bytes, Error> {
16    // Derive the nodeidkey from the seed.
17    use lightning_signer::signer::derive::{key_derive, KeyDerivationStyle};
18
19    let secp = Secp256k1::default();
20    let d = key_derive(KeyDerivationStyle::Native, Network::Bitcoin);
21    let (_, node_secret) = d.node_keys(&seed.secret_bytes(), &secp);
22
23    decrypt(enc, &node_secret)
24}
25
26pub fn decrypt(mut enc: BytesMut, privkey: &SecretKey) -> Result<Bytes, Error> {
27    let mut r = enc.clone().reader();
28    // Start by reading the header
29    let mut version = [0u8; 1];
30    r.read_exact(&mut version)?;
31
32    if VERSION != version[0] {
33        return Err(anyhow!(
34            "Backup version {} is not supported by this client version {}",
35            version[0],
36            VERSION
37        ));
38    }
39
40    let mut ephkey = [0u8; 33];
41    r.read_exact(&mut ephkey)?;
42
43    let mut nonce = [0u8; 12];
44    r.read_exact(&mut nonce)?;
45
46    let mut tag = [0u8; 16];
47    r.read_exact(&mut tag)?;
48
49    let secp = Secp256k1::default();
50    let ephkey = PublicKey::from_slice(&ephkey).context("loading ephemeral key")?;
51    let node_id = privkey.public_key(&secp);
52
53    let shared_secret = SharedSecret::new(&ephkey, &privkey);
54    enc.advance(HEADER_LEN);
55
56    let cipher = ChaCha20Poly1305::new(&shared_secret.secret_bytes().into());
57
58    cipher
59        .decrypt_in_place_detached(&nonce.into(), &node_id.serialize(), &mut enc, &tag.into())
60        .map_err(|e| anyhow!("Error decrypting: {}", e))?;
61
62    Ok(enc.clone().into())
63}