bitcoin_encrypted_backup/
lib.rs

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