bitcoin_encrypted_backup/
lib.rs

1use std::str::FromStr;
2
3use descriptor::descr_to_dpks;
4
5pub use ll::Content;
6use miniscript::{
7    bitcoin::{bip32::DerivationPath, secp256k1},
8    Descriptor, DescriptorPublicKey,
9};
10
11#[cfg(all(feature = "miniscript_12_0", feature = "miniscript_12_3_5"))]
12compile_error!("A single miniscript version must be selected");
13
14#[cfg(not(any(feature = "miniscript_12_0", feature = "miniscript_12_3_5")))]
15compile_error!("A miniscript version must be selected with feature flag");
16#[cfg(feature = "tokio")]
17pub use tokio;
18
19#[cfg(feature = "miniscript_12_0")]
20pub use mscript_12_0 as miniscript;
21#[cfg(feature = "miniscript_12_3_5")]
22pub use mscript_12_3_5 as miniscript;
23
24use num_enum::{FromPrimitive, IntoPrimitive};
25
26pub mod descriptor;
27pub mod ll;
28#[cfg(feature = "devices")]
29pub mod signing_devices;
30
31pub trait ToPayload {
32    fn to_payload(&self) -> Result<Vec<u8>, Error>;
33    fn content_type(&self) -> Content;
34    fn derivation_paths(&self) -> Result<Vec<DerivationPath>, Error>;
35    fn keys(&self) -> Result<Vec<secp256k1::PublicKey>, Error>;
36}
37
38impl ToPayload for Vec<u8> {
39    fn to_payload(&self) -> Result<Vec<u8>, Error> {
40        Ok(self.clone())
41    }
42    fn content_type(&self) -> Content {
43        Content::Unknown
44    }
45    fn derivation_paths(&self) -> Result<Vec<DerivationPath>, Error> {
46        Ok(vec![])
47    }
48    fn keys(&self) -> Result<Vec<secp256k1::PublicKey>, Error> {
49        Ok(vec![])
50    }
51}
52
53impl ToPayload for Descriptor<DescriptorPublicKey> {
54    fn to_payload(&self) -> Result<Vec<u8>, Error> {
55        Ok(self.to_string().as_bytes().to_vec())
56    }
57
58    fn content_type(&self) -> Content {
59        Content::Bip380
60    }
61
62    fn derivation_paths(&self) -> Result<Vec<DerivationPath>, Error> {
63        let dpks = descr_to_dpks(self)?;
64        let (_, p) = descriptor::dpks_to_derivation_keys_paths(&dpks);
65        Ok(p)
66    }
67
68    fn keys(&self) -> Result<Vec<secp256k1::PublicKey>, Error> {
69        let dpks = descr_to_dpks(self)?;
70        let (k, _) = descriptor::dpks_to_derivation_keys_paths(&dpks);
71        Ok(k)
72    }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
76pub enum Decrypted {
77    Descriptor(Descriptor<DescriptorPublicKey>),
78    Policy,
79    Labels,
80    WalletBackup(Vec<u8>),
81    Raw(Vec<u8>),
82}
83
84#[derive(Debug, Clone)]
85pub enum Payload {
86    None,
87    Encrypt {
88        payload: Vec<u8>,
89    },
90    DecryptV1 {
91        cyphertext: Vec<u8>,
92        individual_secrets: Vec<[u8; 32]>,
93        nonce: [u8; 12],
94    },
95}
96
97impl Payload {
98    pub fn is_none(&self) -> bool {
99        matches!(self, Payload::None)
100    }
101}
102
103#[derive(Debug, Clone)]
104pub struct EncryptedBackup {
105    version: Version,
106    content: Content,
107    encryption: Encryption,
108    derivation_paths: Vec<DerivationPath>,
109    keys: Vec<secp256k1::PublicKey>,
110    payload: Payload,
111}
112
113impl Default for EncryptedBackup {
114    fn default() -> Self {
115        Self {
116            version: Version::V0,
117            content: Content::Unknown,
118            encryption: Encryption::AesGcm256,
119            derivation_paths: vec![],
120            keys: vec![],
121            payload: Payload::None,
122        }
123    }
124}
125
126impl EncryptedBackup {
127    pub fn new() -> Self {
128        Default::default()
129    }
130    pub fn get_derivation_paths(&self) -> Vec<DerivationPath> {
131        self.derivation_paths.clone()
132    }
133    pub fn get_keys(&self) -> Vec<secp256k1::PublicKey> {
134        self.keys.clone()
135    }
136    pub fn get_content(&self) -> Content {
137        self.content.clone()
138    }
139    pub fn get_version(&self) -> Version {
140        self.version
141    }
142    pub fn get_encryption(&self) -> Encryption {
143        self.encryption
144    }
145    pub fn set_keys(mut self, keys: Vec<secp256k1::PublicKey>) -> Self {
146        self.keys = keys;
147        self
148    }
149    pub fn set_version(mut self, version: Version) -> Self {
150        self.version = version;
151        self
152    }
153    pub fn set_content_type(mut self, content_type: Content) -> Self {
154        self.content = content_type;
155        self
156    }
157    pub fn set_encryption(mut self, encryption: Encryption) -> Self {
158        self.encryption = encryption;
159        self
160    }
161    pub fn set_derivation_paths(mut self, derivation_paths: Vec<DerivationPath>) -> Self {
162        self.derivation_paths = derivation_paths;
163        self
164    }
165    pub fn set_payload<T: ToPayload>(mut self, payload: &T) -> Result<Self, Error> {
166        self.payload = Payload::Encrypt {
167            payload: payload.to_payload()?,
168        };
169        if payload.content_type().is_known() {
170            self.content = payload.content_type();
171        };
172        self.derivation_paths
173            .append(&mut payload.derivation_paths()?);
174        self.keys.append(&mut payload.keys()?);
175        Ok(self)
176    }
177    pub fn encrypt(self) -> Result<Vec<u8>, Error> {
178        if self.content == Content::Unknown {
179            return Err(Error::UnknownContent);
180        }
181        if !self.encryption.is_defined() {
182            return Err(Error::EncryptionUndefined);
183        }
184        if !self.version.is_valid() {
185            return Err(Error::InvalidVersion);
186        }
187        let bytes = if let Payload::Encrypt { payload } = &self.payload {
188            payload.clone()
189        } else {
190            return Err(Error::WrongPayload);
191        };
192
193        match (self.encryption, self.version) {
194            (Encryption::AesGcm256, Version::V0 | Version::V1) => Ok(ll::encrypt_aes_gcm_256_v1(
195                self.derivation_paths,
196                self.content.clone(),
197                self.keys,
198                &bytes,
199            )?),
200            _ => Err(Error::NotImplemented),
201        }
202    }
203    pub fn set_encrypted_payload(mut self, bytes: &[u8]) -> Result<Self, Error> {
204        let version: Version = ll::decode_version(bytes).map(|v| v.into())?;
205        match version {
206            Version::V0 | Version::V1 => {
207                let (derivation_paths, individual_secrets, encryption_type, nonce, cyphertext) =
208                    ll::decode_v1(bytes)?;
209                self.derivation_paths = derivation_paths;
210                self.encryption = encryption_type.into();
211                self.payload = Payload::DecryptV1 {
212                    cyphertext,
213                    individual_secrets,
214                    nonce,
215                }
216            }
217            _ => return Err(Error::NotImplemented),
218        }
219        Ok(self)
220    }
221    pub fn extract(content: Content, bytes: Vec<u8>) -> Result<Decrypted, Error> {
222        match content {
223            Content::None | Content::Unknown => Ok(Decrypted::Raw(bytes)),
224            Content::Bip380 => {
225                let descr_str = String::from_utf8(bytes).map_err(|_| Error::Utf8)?;
226                let descriptor = Descriptor::<DescriptorPublicKey>::from_str(&descr_str)
227                    .map_err(|_| Error::Descriptor)?;
228                Ok(Decrypted::Descriptor(descriptor))
229            }
230            Content::BIP(_) | Content::Proprietary(_) | Content::Bip329 | Content::Bip388 => {
231                Err(Error::NotImplemented)
232            }
233        }
234    }
235    pub fn decrypt(&self) -> Result<Decrypted, Error> {
236        if self.keys.is_empty() {
237            return Err(Error::NoKey);
238        }
239        match self.version {
240            Version::V0 | Version::V1 => match &self.payload {
241                Payload::None | Payload::Encrypt { .. } => Err(Error::WrongPayload),
242                Payload::DecryptV1 {
243                    cyphertext,
244                    individual_secrets,
245                    nonce,
246                } => {
247                    for key in &self.keys {
248                        if let Ok((content, bytes)) = ll::decrypt_aes_gcm_256_v1(
249                            *key,
250                            &individual_secrets.clone(),
251                            cyphertext.clone(),
252                            *nonce,
253                        ) {
254                            return Self::extract(content, bytes);
255                        }
256                    }
257                    Err(Error::WrongKey)
258                }
259            },
260            Version::Unknown => Err(Error::UnknownVersion),
261        }
262    }
263}
264
265#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive, PartialEq, Eq)]
266#[repr(u8)]
267pub enum Encryption {
268    Undefined,
269    AesGcm256,
270    #[num_enum(default)]
271    Unknown = 0xFF,
272}
273
274impl Encryption {
275    pub fn is_defined(&self) -> bool {
276        match self {
277            Encryption::Undefined | Encryption::Unknown => false,
278            Encryption::AesGcm256 => true,
279        }
280    }
281}
282
283#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive, PartialEq, Eq)]
284#[repr(u8)]
285pub enum Version {
286    V0,
287    V1,
288    #[num_enum(default)]
289    Unknown = 0xFF,
290}
291
292impl Version {
293    fn max() -> Self {
294        Version::V1
295    }
296    pub fn is_valid(&self) -> bool {
297        match self {
298            Version::Unknown => false,
299            Version::V0 | Version::V1 => true,
300        }
301    }
302}
303
304#[derive(Debug, Clone, PartialEq, Eq)]
305pub enum Error {
306    Ll(ll::Error),
307    Utf8,
308    Descriptor,
309    NotImplemented,
310    UnknownContent,
311    EncryptionUndefined,
312    InvalidVersion,
313    WrongPayload,
314    UnknownVersion,
315    NoKey,
316    WrongKey,
317    DescriptorHasNoKeys,
318    String(Box<String>),
319}
320
321impl From<ll::Error> for Error {
322    fn from(value: ll::Error) -> Self {
323        Error::Ll(value)
324    }
325}
326
327#[cfg(test)]
328mod tests {
329    use miniscript::bitcoin;
330
331    use crate::descriptor::dpk_to_pk;
332
333    use super::*;
334
335    #[test]
336    fn test_simple_encrypted_descriptor() {
337        let descriptor = descriptor::tests::descr_1();
338        let backp = EncryptedBackup::new().set_payload(&descriptor).unwrap();
339        let keys = backp.get_keys();
340        let bytes = backp.encrypt().unwrap();
341        let restored = EncryptedBackup::new()
342            .set_encrypted_payload(&bytes)
343            .unwrap()
344            .set_keys(keys)
345            .decrypt()
346            .unwrap();
347        assert_eq!(restored, Decrypted::Descriptor(descriptor));
348    }
349
350    #[test]
351    fn test_encrypt_bytes() {
352        let payload = vec![0x00u8, 0x00, 0x00];
353        let mut backp = EncryptedBackup::new().set_payload(&payload).unwrap();
354        assert!(!backp.payload.is_none());
355
356        assert!(backp.get_keys().is_empty());
357        let pk1 = dpk_to_pk(&descriptor::tests::dpk_1());
358        backp = backp.set_keys(vec![pk1]);
359        let pks = backp.get_keys();
360        assert_eq!(pks.len(), 1);
361        assert_eq!(*pks.first().unwrap(), pk1);
362
363        assert!(backp.get_derivation_paths().is_empty());
364        let deriv = DerivationPath::from_str("0/0").unwrap();
365        backp = backp.set_derivation_paths(vec![deriv.clone()]);
366        assert_eq!(backp.get_derivation_paths(), vec![deriv]);
367
368        assert_eq!(backp.get_content(), Content::Unknown);
369        let fail = backp.clone().encrypt().unwrap_err();
370        assert_eq!(fail, Error::UnknownContent);
371        backp = backp.set_content_type(Content::None);
372        assert_eq!(backp.get_content(), Content::None);
373
374        assert_eq!(backp.get_encryption(), Encryption::AesGcm256);
375        backp = backp.set_encryption(Encryption::Undefined);
376        assert_eq!(backp.get_encryption(), Encryption::Undefined);
377        let fail = backp.clone().encrypt().unwrap_err();
378        assert_eq!(fail, Error::EncryptionUndefined);
379        backp = backp.set_encryption(Encryption::AesGcm256);
380        assert_eq!(backp.get_encryption(), Encryption::AesGcm256);
381
382        backp = backp.set_version(Version::Unknown);
383        let fail = backp.clone().encrypt().unwrap_err();
384        assert_eq!(fail, Error::InvalidVersion);
385        backp = backp.set_version(Version::V0);
386        assert_eq!(backp.get_version(), Version::V0);
387        backp = backp.set_version(Version::V1);
388        assert_eq!(backp.get_version(), Version::V1);
389
390        let bytes = backp.encrypt().unwrap();
391
392        let fail = EncryptedBackup::new()
393            .set_encrypted_payload(&bytes)
394            .unwrap()
395            .decrypt()
396            .unwrap_err();
397        assert_eq!(fail, Error::NoKey);
398
399        let w_key = bitcoin::secp256k1::PublicKey::from_slice(&[
400            4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85,
401            220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124,
402            149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195,
403            155, 51, 247, 123, 113, 60, 228, 188,
404        ])
405        .unwrap();
406        let fail = EncryptedBackup::new()
407            .set_encrypted_payload(&bytes)
408            .unwrap()
409            .set_keys(vec![w_key])
410            .decrypt()
411            .unwrap_err();
412        assert_eq!(fail, Error::WrongKey);
413
414        let restored = EncryptedBackup::new()
415            .set_encrypted_payload(&bytes)
416            .unwrap()
417            .set_keys(vec![pk1])
418            .decrypt()
419            .unwrap();
420        assert_eq!(restored, Decrypted::Raw(vec![0x00u8, 0x00, 0x00]));
421    }
422
423    pub fn dummy_encrypted_payload() -> Vec<u8> {
424        let key = dpk_to_pk(&descriptor::tests::dpk_1());
425        EncryptedBackup::new()
426            .set_payload(&vec![0x00])
427            .unwrap()
428            .set_keys(vec![key])
429            .set_content_type(Content::None)
430            .encrypt()
431            .unwrap()
432    }
433
434    #[test]
435    fn test_encrypt_wrong_payload() {
436        // No payload
437        let fail = EncryptedBackup::new()
438            .set_content_type(Content::None)
439            .encrypt()
440            .unwrap_err();
441        assert_eq!(fail, Error::WrongPayload);
442
443        let dummy_payload = dummy_encrypted_payload();
444
445        // wrong payload
446        let fail = EncryptedBackup::new()
447            .set_encrypted_payload(&dummy_payload)
448            .unwrap()
449            .set_content_type(Content::None)
450            .encrypt()
451            .unwrap_err();
452        assert_eq!(fail, Error::WrongPayload);
453    }
454
455    #[test]
456    fn test_decrypt_wrong_payload() {
457        let key = dpk_to_pk(&descriptor::tests::dpk_1());
458        // No payload
459        let fail = EncryptedBackup::new()
460            .set_keys(vec![key])
461            .decrypt()
462            .unwrap_err();
463        assert_eq!(fail, Error::WrongPayload);
464
465        // wrong payload
466        let fail = EncryptedBackup::new()
467            .set_keys(vec![key])
468            .set_payload(&vec![0x00])
469            .unwrap()
470            .decrypt()
471            .unwrap_err();
472        assert_eq!(fail, Error::WrongPayload);
473
474        let dummy = dummy_encrypted_payload();
475
476        // unknown version
477        let fail = EncryptedBackup::new()
478            .set_keys(vec![key])
479            .set_encrypted_payload(&dummy)
480            .unwrap()
481            .set_version(Version::Unknown)
482            .decrypt()
483            .unwrap_err();
484        assert_eq!(fail, Error::UnknownVersion);
485    }
486
487    #[test]
488    fn test_encryption_to_u8() {
489        let mut u: u8 = Encryption::AesGcm256.into();
490        assert_eq!(0x01, u);
491        u = Encryption::Undefined.into();
492        assert_eq!(0x00, u);
493        u = Encryption::Unknown.into();
494        assert_eq!(0xFF, u);
495    }
496
497    #[test]
498    fn test_u8_to_encryption() {
499        let mut e: Encryption = 0x00u8.into();
500        assert_eq!(e, Encryption::Undefined);
501        e = 0x01u8.into();
502        assert_eq!(e, Encryption::AesGcm256);
503
504        for i in 0x02..0xFFu8 {
505            e = i.into();
506            assert_eq!(e, Encryption::Unknown);
507        }
508    }
509
510    #[test]
511    fn test_version_to_u8() {
512        let mut u: u8 = Version::V0.into();
513        assert_eq!(0x00, u);
514        u = Version::V0.into();
515        assert_eq!(0x00, u);
516        u = Version::Unknown.into();
517        assert_eq!(0xFF, u);
518    }
519
520    #[test]
521    fn test_u8_to_version() {
522        let mut v: Version = 0x00u8.into();
523        assert_eq!(v, Version::V0);
524        v = 0x01u8.into();
525        assert_eq!(v, Version::V1);
526
527        for i in 0x02..0xFFu8 {
528            v = i.into();
529            assert_eq!(v, Version::Unknown);
530        }
531    }
532}