bitcoin_encrypted_backup/
ll.rs

1#[cfg(feature = "miniscript_12_0")]
2pub use mscript_12_0 as miniscript;
3#[cfg(feature = "miniscript_12_3_5")]
4pub use mscript_12_3_5 as miniscript;
5
6extern crate alloc;
7use alloc::collections::BTreeSet;
8use alloc::{vec, vec::Vec};
9
10use aes_gcm::{
11    aead::{Aead, KeyInit},
12    Aes256Gcm, Key, Nonce,
13};
14use miniscript::bitcoin::{
15    self,
16    bip32::{ChildNumber, DerivationPath},
17    hashes::{sha256, Hash, HashEngine},
18    secp256k1, VarInt,
19};
20#[cfg(feature = "rand")]
21use rand::{rngs::OsRng, TryRngCore};
22
23use crate::{descriptor::bip341_nums, Encryption, Version};
24
25const DECRYPTION_SECRET: &str = "BEB_BACKUP_DECRYPTION_SECRET";
26const INDIVIDUAL_SECRET: &str = "BEB_BACKUP_INDIVIDUAL_SECRET";
27const MAGIC: &str = "BEB";
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum Error {
31    KeyCount,
32    DerivPathCount,
33    DerivPathLength,
34    DerivPathEmpty,
35    DataLength,
36    Encrypt,
37    Decrypt,
38    Corrupted,
39    Version,
40    Magic,
41    VarInt,
42    WrongKey,
43    IndividualSecretsEmpty,
44    IndividualSecretsLength,
45    CypherTextEmpty,
46    CypherTextLength,
47    ContentMetadata,
48    Encryption,
49    OffsetOverflow,
50    EmptyBytes,
51    Increment,
52    ContentMetadataEmpty,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
56pub enum Content {
57    None,
58    Bip380,
59    Bip388,
60    Bip329,
61    BIP(u16),
62    Proprietary(Vec<u8>),
63    Unknown,
64}
65
66/// Encode content metadata, 3 variants:
67/// - <LENGTH == 0> => None
68/// - <LENGTH == 2><BIP_NUMBER> => encoding format defined in BIP<BIP_NUMBER>
69/// - <LENGTH > 2> => proprietary
70impl From<Content> for Vec<u8> {
71    fn from(value: Content) -> Self {
72        match value {
73            Content::None => [0].into(),
74            Content::Proprietary(mut data) => {
75                assert!(data.len() > 2);
76                assert!(data.len() < u8::MAX as usize);
77                let mut content = vec![data.len() as u8];
78                content.append(&mut data);
79                content
80            }
81            Content::Unknown => unimplemented!(),
82            c => {
83                let mut content = vec![2];
84                let bip_number = match c {
85                    Content::Bip380 => 380u16.to_be_bytes(),
86                    Content::Bip388 => 388u16.to_be_bytes(),
87                    Content::Bip329 => 329u16.to_be_bytes(),
88                    Content::BIP(bip) => bip.to_be_bytes(),
89                    _ => unreachable!(),
90                };
91                content.append(&mut bip_number.to_vec());
92                content
93            }
94        }
95    }
96}
97
98pub fn parse_content_metadata(bytes: &[u8]) -> Result<(usize, Content), Error> {
99    let len = bytes.len();
100    if len == 0 {
101        Err(Error::ContentMetadataEmpty)?
102    }
103    let data_len = bytes[0];
104    match data_len {
105        0 => Ok((1, Content::None)),
106        1 => Err(Error::ContentMetadata),
107        2 => {
108            if bytes.len() < 3 {
109                return Err(Error::ContentMetadata);
110            }
111            let bip_number = u16::from_be_bytes(bytes[1..3].try_into().expect("len ok"));
112            match bip_number {
113                380 => Ok((3, Content::Bip380)),
114                388 => Ok((3, Content::Bip388)),
115                329 => Ok((3, Content::Bip329)),
116                bip_number => Ok((3, Content::BIP(bip_number))),
117            }
118        }
119        len => {
120            let end = (len as usize + 1).min(bytes.len());
121            let data = &bytes[1..end].to_vec();
122            Ok((end, Content::Proprietary(data.to_vec())))
123        }
124    }
125}
126
127impl Content {
128    pub fn is_known(&self) -> bool {
129        match self {
130            Content::None | Content::Unknown | Content::Proprietary(_) => false,
131            Content::Bip380 | Content::Bip388 | Content::Bip329 | Content::BIP(_) => true,
132        }
133    }
134}
135
136pub fn xor(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
137    let mut out = [0; 32];
138    for i in 0..32 {
139        out[i] = a[i] ^ b[i];
140    }
141    out
142}
143
144#[cfg(feature = "rand")]
145pub fn nonce() -> [u8; 12] {
146    let mut rng = OsRng;
147    let mut nonce = [0u8; 12];
148    rng.try_fill_bytes(&mut nonce)
149        .expect("os rng must not fail");
150    nonce
151}
152
153pub fn decryption_secret(keys: &[[u8; 33]]) -> sha256::Hash {
154    let mut engine = sha256::HashEngine::default();
155    engine.input(DECRYPTION_SECRET.as_bytes());
156    keys.iter().for_each(|k| engine.input(k));
157    sha256::Hash::from_engine(engine)
158}
159
160pub fn individual_secret(secret: &sha256::Hash, key: &[u8; 33]) -> [u8; 32] {
161    let mut engine = sha256::HashEngine::default();
162    engine.input(INDIVIDUAL_SECRET.as_bytes());
163    engine.input(key);
164    let si = sha256::Hash::from_engine(engine);
165    xor(secret.as_byte_array(), si.as_byte_array())
166}
167
168pub fn individual_secrets(secret: &sha256::Hash, keys: &[[u8; 33]]) -> Vec<[u8; 32]> {
169    keys.iter()
170        .map(|k| individual_secret(secret, k))
171        .collect::<Vec<_>>()
172}
173
174pub fn inner_encrypt(
175    secret: sha256::Hash,
176    mut data: Vec<u8>,
177    #[cfg(not(feature = "rand"))] nonce: [u8; 12],
178) -> Result<([u8; 12], Vec<u8>), Error> {
179    #[cfg(feature = "rand")]
180    let nonce = nonce();
181
182    #[allow(deprecated)]
183    let key = Key::<Aes256Gcm>::from_slice(secret.as_byte_array());
184    let cipher = Aes256Gcm::new(key);
185
186    let mut plaintext = vec![];
187    plaintext.append(&mut data);
188
189    cipher
190        .encrypt(&Nonce::from(nonce), plaintext.as_slice())
191        .map(|c| (nonce, c))
192        .map_err(|_| Error::Encrypt)
193}
194
195/// Encode following this format:
196/// <LENGTH><DERIVATION_PATH_1><DERIVATION_PATH_2><..><DERIVATION_PATH_N>
197pub fn encode_derivation_paths(derivation_paths: Vec<DerivationPath>) -> Result<Vec<u8>, Error> {
198    if derivation_paths.len() > u8::MAX as usize {
199        return Err(Error::DerivPathLength);
200    }
201    let mut encoded_paths = vec![derivation_paths.len() as u8];
202    for path in derivation_paths {
203        let childs = path.to_u32_vec();
204        let len = childs.len();
205        if len > u8::MAX as usize {
206            return Err(Error::DerivPathLength);
207        }
208        encoded_paths.push(len as u8);
209        for c in childs {
210            encoded_paths.append(&mut c.to_be_bytes().to_vec());
211        }
212    }
213    Ok(encoded_paths)
214}
215
216/// Encode following this format:
217/// <LENGTH><INDIVIDUAL_SECRET_1><INDIVIDUAL_SECRET_2><..><INDIVIDUAL_SECRET_N>
218pub fn encode_individual_secrets(individual_secrets: &[[u8; 32]]) -> Result<Vec<u8>, Error> {
219    let individual_secrets: BTreeSet<_> = individual_secrets.iter().collect();
220    if individual_secrets.len() > u8::MAX as usize {
221        return Err(Error::IndividualSecretsLength);
222    } else if individual_secrets.is_empty() {
223        return Err(Error::IndividualSecretsEmpty);
224    }
225    let len = individual_secrets.len() as u8;
226    let mut out = Vec::with_capacity(1 + (individual_secrets.len() * 32));
227    out.push(len);
228    for is in individual_secrets {
229        out.append(&mut is.to_vec());
230    }
231    Ok(out)
232}
233
234/// Encode following this format:
235/// <NONCE><LENGTH><CYPHERTEXT>
236pub fn encode_encrypted_payload(nonce: [u8; 12], cyphertext: &[u8]) -> Result<Vec<u8>, Error> {
237    if cyphertext.is_empty() {
238        return Err(Error::CypherTextEmpty);
239    }
240    let mut out = Vec::new();
241    out.append(&mut nonce.as_slice().to_vec());
242    let mut var_int = bitcoin::consensus::serialize(&bitcoin::VarInt(cyphertext.len() as u64));
243    out.append(&mut var_int);
244    out.append(&mut cyphertext.to_vec());
245
246    Ok(out)
247}
248
249/// Encode following this format
250/// <MAGIC><VERSION><DERIVATION_PATHS><INDIVIDUAL_SECRETS><ENCRYPTION><ENCRYPTED_PAYLOAD>
251/// NOTE: payload that will fail to decode can be encoded with this function, for instance with an
252/// invalid version, the inputs args must be sanitized by the caller.
253pub fn encode_v1(
254    version: u8,
255    mut derivation_paths: Vec<u8>,
256    mut individual_secrets: Vec<u8>,
257    encryption: u8,
258    mut encrypted_payload: Vec<u8>,
259) -> Vec<u8> {
260    // <MAGIC>
261    let mut out = MAGIC.as_bytes().to_vec();
262    // <VERSION>
263    out.push(version);
264    // <DERIVATION_PATHS>
265    out.append(&mut derivation_paths);
266    // <INDIVIDUAL_SECRETS>
267    out.append(&mut individual_secrets);
268    // <ENCRYPTION>
269    out.push(encryption);
270    // <ENCRYPTED_PAYLOAD>
271    out.append(&mut encrypted_payload);
272    out
273}
274
275pub fn check_offset(offset: usize, bytes: &[u8]) -> Result<(), Error> {
276    if bytes.len() <= offset {
277        Err(Error::Corrupted)
278    } else {
279        Ok(())
280    }
281}
282
283pub fn check_offset_lookahead(offset: usize, bytes: &[u8], lookahead: usize) -> Result<(), Error> {
284    let target = offset
285        .checked_add(lookahead)
286        .ok_or(Error::Increment)?
287        .checked_sub(1)
288        .ok_or(Error::Increment)?;
289    if bytes.len() <= target {
290        Err(Error::Corrupted)
291    } else {
292        Ok(())
293    }
294}
295
296pub fn init_offset(bytes: &[u8], value: usize) -> Result<usize, Error> {
297    check_offset(value, bytes)?;
298    Ok(value)
299}
300
301pub fn increment_offset(bytes: &[u8], offset: usize, incr: usize) -> Result<usize, Error> {
302    check_offset(offset + incr, bytes)?;
303    offset.checked_add(incr).ok_or(Error::OffsetOverflow)
304}
305
306/// Expects a payload following this format:
307/// <MAGIC><VERSION><..>
308pub fn decode_version(bytes: &[u8]) -> Result<u8, Error> {
309    // <MAGIC>
310    let offset = init_offset(bytes, parse_magic_byte(bytes)?)?;
311    // <VERSION>
312    let (_, version) = parse_version(&bytes[offset..])?;
313    Ok(version)
314}
315
316/// Expects a payload following this format:
317/// <MAGIC><VERSION><DERIVATION_PATHS><..>
318pub fn decode_derivation_paths(bytes: &[u8]) -> Result<Vec<DerivationPath>, Error> {
319    // <MAGIC>
320    let mut offset = init_offset(bytes, parse_magic_byte(bytes)?)?;
321    // <VERSION>
322    let (incr, _) = parse_version(&bytes[offset..])?;
323    offset = increment_offset(bytes, offset, incr)?;
324    // <DERIVATION_PATHS>
325    let (_, derivation_paths) = parse_derivation_paths(&bytes[offset..])?;
326    Ok(derivation_paths)
327}
328
329/// Expects a payload following this format:
330/// <MAGIC><VERSION><DERIVATION_PATHS><INDIVIDUAL_SECRETS><ENCRYPTION><ENCRYPTED_PAYLOAD><..>
331#[allow(clippy::type_complexity)]
332pub fn decode_v1(
333    bytes: &[u8],
334) -> Result<
335    (
336        Vec<DerivationPath>, /* derivation_paths */
337        Vec<[u8; 32]>,       /* individual_secrets */
338        u8,                  /* encryption_type */
339        [u8; 12],            /* nonce */
340        Vec<u8>,             /* cyphertext */
341    ),
342    Error,
343> {
344    // <MAGIC>
345    let mut offset = init_offset(bytes, parse_magic_byte(bytes)?)?;
346    // <VERSION>
347    let (incr, _) = parse_version(&bytes[offset..])?;
348    offset = increment_offset(bytes, offset, incr)?;
349    // <DERIVATION_PATHS>
350    let (incr, derivation_paths) = parse_derivation_paths(&bytes[offset..])?;
351    offset = increment_offset(bytes, offset, incr)?;
352    // <INDIVIDUAL_SECRETS>
353    let (incr, individual_secrets) = parse_individual_secrets(&bytes[offset..])?;
354    offset = increment_offset(bytes, offset, incr)?;
355    // <ENCRYPTION>
356    let (incr, encryption_type) = parse_encryption(&bytes[offset..])?;
357    offset = increment_offset(bytes, offset, incr)?;
358    // <ENCRYPTED_PAYLOAD>
359    let (nonce, cyphertext) = parse_encrypted_payload(&bytes[offset..])?;
360
361    Ok((
362        derivation_paths,
363        individual_secrets,
364        encryption_type,
365        nonce,
366        cyphertext,
367    ))
368}
369
370pub fn encrypt_aes_gcm_256_v1(
371    derivation_paths: Vec<DerivationPath>,
372    content_metadata: Content,
373    keys: Vec<secp256k1::PublicKey>,
374    data: &[u8],
375    #[cfg(not(feature = "rand"))] nonce: [u8; 12],
376) -> Result<Vec<u8>, Error> {
377    // drop duplicates keys and sort out bip341 nums
378    let keys = keys
379        .into_iter()
380        .filter(|k| *k != bip341_nums())
381        .collect::<BTreeSet<_>>();
382
383    // drop duplicates derivation paths
384    let derivation_paths = derivation_paths
385        .into_iter()
386        .collect::<BTreeSet<_>>()
387        .into_iter()
388        .collect::<Vec<_>>();
389
390    if keys.len() > u8::MAX as usize || keys.is_empty() {
391        return Err(Error::KeyCount);
392    }
393    if derivation_paths.len() > u8::MAX as usize {
394        return Err(Error::DerivPathCount);
395    }
396    // NOTE:  RFC5116 define the max length of the plaintext to 2^36 - 31
397    // but for convenience we limit it to u32::MAX in order to not exceed
398    // usize::MAX on 32 bits architectures
399    // https://datatracker.ietf.org/doc/html/rfc5116#section-5.1
400    if data.len() > u32::MAX as usize {
401        return Err(Error::DataLength);
402    }
403    if data.is_empty() {
404        return Err(Error::DataLength);
405    }
406
407    let content_metadata: Vec<u8> = content_metadata.into();
408    if content_metadata.is_empty() {
409        return Err(Error::ContentMetadata);
410    }
411
412    let mut raw_keys = keys.into_iter().map(|k| k.serialize()).collect::<Vec<_>>();
413    raw_keys.sort();
414
415    let secret = decryption_secret(&raw_keys);
416    let individual_secrets =
417        encode_individual_secrets(&individual_secrets(&secret, raw_keys.as_slice()))?;
418    let derivation_paths = encode_derivation_paths(derivation_paths)?;
419
420    // <PAYLOAD> = <CONTENT_METADATA><DATA>
421    let mut payload = content_metadata;
422    payload.append(&mut data.to_vec());
423
424    let (nonce, cyphertext) = inner_encrypt(
425        secret,
426        payload.to_vec(),
427        #[cfg(not(feature = "rand"))]
428        nonce,
429    )?;
430    let encrypted_payload = encode_encrypted_payload(nonce, cyphertext.as_slice())?;
431
432    Ok(encode_v1(
433        Version::V1.into(),
434        derivation_paths,
435        individual_secrets,
436        Encryption::AesGcm256.into(),
437        encrypted_payload,
438    ))
439}
440
441pub fn try_decrypt_aes_gcm_256(
442    cyphertext: &[u8],
443    secret: &[u8; 32],
444    nonce: [u8; 12],
445) -> Option<Vec<u8>> {
446    let nonce = Nonce::from(nonce);
447
448    #[allow(deprecated)]
449    let key = Key::<Aes256Gcm>::from_slice(secret);
450    let cipher = Aes256Gcm::new(key);
451
452    cipher.decrypt(&nonce, cyphertext).ok()
453}
454
455pub fn decrypt_aes_gcm_256_v1(
456    key: secp256k1::PublicKey,
457    individual_secrets: &Vec<[u8; 32]>,
458    cyphertext: Vec<u8>,
459    nonce: [u8; 12],
460) -> Result<(Content, Vec<u8>), Error> {
461    let raw_key = key.serialize();
462
463    let mut engine = sha256::HashEngine::default();
464    engine.input(INDIVIDUAL_SECRET.as_bytes());
465    engine.input(&raw_key);
466    let si = sha256::Hash::from_engine(engine);
467
468    for ci in individual_secrets {
469        let secret = xor(si.as_byte_array(), ci);
470        if let Some(out) = try_decrypt_aes_gcm_256(&cyphertext, &secret, nonce) {
471            let mut offset = init_offset(&out, 0)?;
472            // <CONTENT_METADATA>
473            let (incr, content) = parse_content_metadata(&out)?;
474            // <DECRYPTED_PAYLOAD>
475            offset = increment_offset(&out, offset, incr)?;
476            let out = out[offset..].to_vec();
477            return Ok((content, out));
478        }
479    }
480
481    Err(Error::WrongKey)
482}
483
484pub fn parse_magic_byte(bytes: &[u8]) -> Result<usize /* offset */, Error> {
485    let magic = MAGIC.as_bytes();
486
487    if bytes.len() < magic.len() || &bytes[..magic.len()] != magic {
488        return Err(Error::Magic);
489    }
490    Ok(magic.len())
491}
492
493pub fn parse_version(bytes: &[u8]) -> Result<(usize, u8), Error> {
494    if bytes.is_empty() {
495        return Err(Error::Version);
496    }
497    let version = bytes[0];
498    if version > Version::max().into() {
499        return Err(Error::Version);
500    }
501    Ok((1, version))
502}
503
504pub fn parse_encryption(bytes: &[u8]) -> Result<(usize, u8), Error> {
505    if bytes.is_empty() {
506        return Err(Error::Encryption);
507    }
508    let encryption = bytes[0];
509    Ok((1, encryption))
510}
511
512/// Expects to parse a payload of the form:
513/// <COUNT>
514/// <CHILD_COUNT><CHILD><..><CHILD>
515/// <..>
516/// <CHILD_COUNT><CHILD><..><CHILD>
517/// <..>
518pub fn parse_derivation_paths(
519    bytes: &[u8],
520) -> Result<(usize /* offset */, Vec<DerivationPath>), Error> {
521    let mut offset = init_offset(bytes, 0).map_err(|_| Error::DerivPathEmpty)?;
522    let mut derivation_paths = BTreeSet::new();
523
524    // <COUNT>
525    let count = bytes[0];
526
527    if count != 0 {
528        offset = increment_offset(bytes, offset, 1)?;
529        for _ in 0..count {
530            check_offset(offset, bytes)?;
531            // <CHILD_COUNT>
532            let child_count = bytes[offset];
533            if child_count == 0 {
534                return Err(Error::DerivPathEmpty);
535            } else {
536                let mut childs = vec![];
537                offset += 1;
538                for _ in 0..child_count {
539                    check_offset_lookahead(offset, bytes, 4)?;
540                    // <CHILD>
541                    let raw_child: [u8; 4] =
542                        bytes[offset..(offset + 4)].try_into().expect("verified");
543                    let child = u32::from_be_bytes(raw_child);
544                    let child = ChildNumber::from(child);
545                    childs.push(child);
546                    offset += 4;
547                }
548                derivation_paths.insert(DerivationPath::from(childs));
549            }
550        }
551    } else {
552        offset += 1;
553    }
554
555    let derivation_paths = derivation_paths.into_iter().collect();
556
557    Ok((offset, derivation_paths))
558}
559
560/// Expects to parse a payload of the form:
561/// <COUNT>
562/// <INDIVIDUAL_SECRET>
563/// <..>
564/// <INDIVIDUAL_SECRET>
565/// <..>
566pub fn parse_individual_secrets(
567    bytes: &[u8],
568) -> Result<(usize /* offset */, Vec<[u8; 32]>), Error> {
569    if bytes.is_empty() {
570        return Err(Error::EmptyBytes);
571    }
572    // <COUNT>
573    let count = bytes[0];
574    if count < 1 {
575        return Err(Error::IndividualSecretsEmpty);
576    }
577    let mut offset = init_offset(bytes, 1)?;
578
579    let mut individual_secrets = BTreeSet::new();
580    for _ in 0..count {
581        check_offset_lookahead(offset, bytes, 32)?;
582        // <INDIVIDUAL_SECRET>
583        let secret: [u8; 32] = bytes[offset..offset + 32]
584            .try_into()
585            .map_err(|_| Error::Corrupted)?;
586        individual_secrets.insert(secret);
587        offset += 32;
588    }
589
590    let individual_secrets = individual_secrets.into_iter().collect();
591    Ok((offset, individual_secrets))
592}
593
594/// Expects to parse a payload of the form:
595/// <NONCE><LENGTH><CYPHERTEXT>
596/// <..>
597pub fn parse_encrypted_payload(
598    bytes: &[u8],
599) -> Result<([u8; 12] /* nonce */, Vec<u8> /* cyphertext */), Error> {
600    let mut offset = init_offset(bytes, 0)?;
601    // <NONCE>
602    check_offset_lookahead(offset, bytes, 12)?;
603    let nonce: [u8; 12] = bytes[offset..offset + 12].try_into().expect("checked");
604    offset = increment_offset(bytes, offset, 12)?;
605    // <LENGTH>
606    let (VarInt(data_len), incr) =
607        bitcoin::consensus::deserialize_partial(&bytes[offset..]).map_err(|_| Error::VarInt)?;
608    // FIXME: in 32bit systems usize is 32 bits
609    let data_len = data_len as usize;
610    offset = increment_offset(bytes, offset, incr)?;
611    // <CYPHERTEXT>
612    check_offset_lookahead(offset, bytes, data_len)?;
613    let cyphertext = bytes[offset..offset + data_len].to_vec();
614    Ok((nonce, cyphertext))
615}
616
617#[cfg(all(test, feature = "rand"))]
618mod tests {
619    use alloc::string::{String, ToString};
620    use core::str::FromStr;
621    use miniscript::bitcoin::XOnlyPublicKey;
622    use rand::random;
623
624    use super::*;
625
626    fn pk1() -> secp256k1::PublicKey {
627        secp256k1::PublicKey::from_str(
628            "02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
629        )
630        .unwrap()
631    }
632
633    fn pk2() -> secp256k1::PublicKey {
634        secp256k1::PublicKey::from_str(
635            "0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07",
636        )
637        .unwrap()
638    }
639
640    fn pk3() -> secp256k1::PublicKey {
641        secp256k1::PublicKey::from_str(
642            "0384526253c27c7aef56c7b71a5cd25bebb000000a437826defc5b2568bde81f07",
643        )
644        .unwrap()
645    }
646
647    #[test]
648    fn test_fuzz_catch_1() {
649        // NOTE: the bug was in check_offset_lookahead() where substract 1 to 0 panics
650        let bytes = [
651            66, 73, 80, 88, 88, 88, 88, 0, 0, 1, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
652            48, 48, 48, 48, 48, 207, 207, 207, 207, 207, 207, 48, 48, 48, 48, 48, 48, 48, 48, 48,
653            32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 185, 185, 0, 88, 0, 0, 185, 185,
654        ];
655        let _ = decode_v1(&bytes);
656    }
657
658    #[test]
659    fn test_nonce() {
660        let nonce_1 = nonce();
661        let nonce_2 = nonce();
662        assert_ne!(nonce_1, nonce_2);
663    }
664
665    #[test]
666    fn test_check_offset() {
667        let res = check_offset(1, &[0x00]);
668        assert!(res.is_err());
669        check_offset(1, &[0x00, 0x00]).unwrap();
670    }
671
672    #[test]
673    fn test_check_offset_look_ahead() {
674        let res = check_offset_lookahead(0, &[0x00; 2], 3);
675        assert!(res.is_err());
676        check_offset_lookahead(0, &[0x00; 2], 2).unwrap();
677    }
678
679    #[test]
680    fn test_init_offset() {
681        let res = init_offset(&[0x00], 1);
682        assert!(res.is_err());
683        init_offset(&[0x00], 0).unwrap();
684    }
685
686    #[test]
687    fn test_increment_offset() {
688        let res = increment_offset(&[0x00], 0, 1);
689        assert!(res.is_err());
690        increment_offset(&[0x00; 2], 0, 1).unwrap();
691    }
692
693    #[test]
694    fn test_parse_magic() {
695        let magic = "BEB".as_bytes();
696        assert_eq!(MAGIC, "BEB");
697        let offset = parse_magic_byte(magic).unwrap();
698        assert_eq!(offset, magic.len());
699        let res = parse_magic_byte("BOBt s".as_bytes());
700        assert_eq!(res, Err(Error::Magic));
701        let _ = parse_magic_byte(MAGIC.as_bytes()).unwrap();
702    }
703
704    #[test]
705    fn test_parse_version() {
706        let (_, v) = parse_version(&[0x00]).unwrap();
707        assert_eq!(v, 0x00);
708        let (_, v) = parse_version(&[0x01]).unwrap();
709        assert_eq!(v, 0x01);
710        let res = parse_version(&[]);
711        assert_eq!(res, Err(Error::Version));
712        let res = parse_version(&[0x02]);
713        assert_eq!(res, Err(Error::Version));
714    }
715
716    #[test]
717    pub fn test_parse_encryption() {
718        let (l, e) = parse_encryption(&[0]).unwrap();
719        assert_eq!(l, 1);
720        assert_eq!(e, 0);
721        let (l, e) = parse_encryption(&[0, 2]).unwrap();
722        assert_eq!(l, 1);
723        assert_eq!(e, 0);
724        let (l, e) = parse_encryption(&[2, 0]).unwrap();
725        assert_eq!(l, 1);
726        assert_eq!(e, 2);
727        let failed = parse_encryption(&[]).unwrap_err();
728        assert_eq!(failed, Error::Encryption)
729    }
730
731    #[test]
732    pub fn test_parse_derivation_path() {
733        // single deriv path
734        let (_, p) = parse_derivation_paths(&[0x01, 0x01, 0x00, 0x00, 0x00, 0x01]).unwrap();
735        assert_eq!(p.len(), 1);
736
737        // child number must be encoded on 4 bytes
738        let p = parse_derivation_paths(&[0x01, 0x01, 0x00]).unwrap_err();
739        assert_eq!(p, Error::Corrupted);
740        let p = parse_derivation_paths(&[0x01, 0x01, 0x00, 0x00]).unwrap_err();
741        assert_eq!(p, Error::Corrupted);
742        let p = parse_derivation_paths(&[0x01, 0x01, 0x00, 0x00, 0x00]).unwrap_err();
743        assert_eq!(p, Error::Corrupted);
744
745        // empty childs
746        let p = parse_derivation_paths(&[0x01, 0x00]).unwrap_err();
747        assert_eq!(p, Error::DerivPathEmpty);
748    }
749
750    #[test]
751    pub fn test_parse_individual_secrets() {
752        // empty bytes
753        let fail = parse_individual_secrets(&[]).unwrap_err();
754        assert_eq!(fail, Error::EmptyBytes);
755
756        // empty vector
757        let fail = parse_individual_secrets(&[0x00]).unwrap_err();
758        assert_eq!(fail, Error::IndividualSecretsEmpty);
759
760        let is1 = [1u8; 32].to_vec();
761        let is2 = [2u8; 32].to_vec();
762
763        // single secret
764        let mut bytes = vec![0x01];
765        bytes.append(&mut is1.clone());
766        let (_, is) = parse_individual_secrets(&bytes).unwrap();
767        assert_eq!(is[0].to_vec(), is1);
768
769        // multiple secrets
770        let mut bytes = vec![0x02];
771        bytes.append(&mut is1.clone());
772        bytes.append(&mut is2.clone());
773        let (_, is) = parse_individual_secrets(&bytes).unwrap();
774        assert_eq!(is[0].to_vec(), is1);
775        assert_eq!(is[1].to_vec(), is2);
776    }
777
778    #[test]
779    fn test_parse_content() {
780        // empty bytes must fail
781        assert!(parse_content_metadata(&[]).is_err());
782        // None
783        let (_, c) = parse_content_metadata(&[0]).unwrap();
784        assert_eq!(c, Content::None);
785        // len == 1 fails
786        assert!(parse_content_metadata(&[1, 0]).is_err());
787        // BIP380
788        let (_, c) = parse_content_metadata(&[2, 0x01, 0x7c]).unwrap();
789        assert_eq!(c, Content::Bip380);
790        // BIP388
791        let (_, c) = parse_content_metadata(&[2, 0x01, 0x84]).unwrap();
792        assert_eq!(c, Content::Bip388);
793        // BIP329
794        let (_, c) = parse_content_metadata(&[2, 0x01, 0x49]).unwrap();
795        assert_eq!(c, Content::Bip329);
796        // Arbitrary BIPs
797        let (_, c) = parse_content_metadata(&[2, 0xFF, 0xFF]).unwrap();
798        assert_eq!(c, Content::BIP(u16::MAX));
799        let (_, c) = parse_content_metadata(&[2, 0, 0]).unwrap();
800        assert_eq!(c, Content::BIP(0));
801        // Proprietary
802        let (_, c) = parse_content_metadata(&[3, 0, 0, 0]).unwrap();
803        assert_eq!(c, Content::Proprietary(vec![0, 0, 0]));
804    }
805
806    #[test]
807    fn test_serialize_content() {
808        // Proprietary
809        let mut c = Content::Proprietary(vec![0, 0, 0]);
810        let mut serialized: Vec<u8> = c.into();
811        assert_eq!(serialized, vec![3, 0, 0, 0]);
812        // BIP 380
813        c = Content::Bip380;
814        serialized = c.into();
815        assert_eq!(serialized, vec![0x02, 0x01, 0x7C]);
816        c = Content::BIP(380);
817        serialized = c.into();
818        assert_eq!(serialized, vec![0x02, 0x01, 0x7C]);
819        // BIP 388
820        c = Content::Bip388;
821        serialized = c.into();
822        assert_eq!(serialized, vec![0x02, 0x01, 0x84]);
823        c = Content::BIP(388);
824        serialized = c.into();
825        assert_eq!(serialized, vec![0x02, 0x01, 0x84]);
826        // BIP 329
827        c = Content::Bip329;
828        serialized = c.into();
829        assert_eq!(serialized, vec![0x02, 0x01, 0x49]);
830        c = Content::BIP(329);
831        serialized = c.into();
832        assert_eq!(serialized, vec![0x02, 0x01, 0x49]);
833    }
834
835    #[test]
836    fn test_content_is_known() {
837        let mut c = Content::None;
838        assert!(!c.is_known());
839        c = Content::Unknown;
840        assert!(!c.is_known());
841        c = Content::Proprietary(vec![0, 0, 0]);
842        assert!(!c.is_known());
843        c = Content::Bip380;
844        assert!(c.is_known());
845        c = Content::Bip388;
846        assert!(c.is_known());
847        c = Content::Bip329;
848        assert!(c.is_known());
849        c = Content::BIP(0);
850        assert!(c.is_known());
851    }
852
853    #[test]
854    fn test_simple_encode_decode_encrypted_payload() {
855        let bytes = encode_encrypted_payload([3; 12], &[1, 2, 3, 4]).unwrap();
856        let mut expected = [3; 12].to_vec();
857        expected.append(&mut [4, 1, 2, 3, 4].to_vec());
858        assert_eq!(bytes, expected);
859        let (nonce, cyphertext) = parse_encrypted_payload(&bytes).unwrap();
860        assert_eq!([3u8; 12], nonce);
861        assert_eq!([1, 2, 3, 4].to_vec(), cyphertext);
862    }
863
864    #[test]
865    fn test_encode_empty_encrypted_payload() {
866        let res = encode_encrypted_payload([3; 12], &[]);
867        assert_eq!(res, Err(Error::CypherTextEmpty));
868    }
869
870    #[test]
871    fn test_encode_decode_derivation_paths() {
872        let bytes = encode_derivation_paths(vec![
873            DerivationPath::from_str("0/1h/2/3h").unwrap(),
874            DerivationPath::from_str("84'/0'/0'/2'").unwrap(),
875        ])
876        .unwrap();
877        let expected = vec![
878            2, 4, 0, 0, 0, 0, 128, 0, 0, 1, 0, 0, 0, 2, 128, 0, 0, 3, 4, 128, 0, 0, 84, 128, 0, 0,
879            0, 128, 0, 0, 0, 128, 0, 0, 2,
880        ];
881        assert_eq!(expected, bytes);
882        let (offset, paths) = parse_derivation_paths(&bytes).unwrap();
883        assert_eq!(offset, 35);
884        assert_eq!(
885            paths,
886            vec![
887                DerivationPath::from_str("0/1h/2/3h").unwrap(),
888                DerivationPath::from_str("84'/0'/0'/2'").unwrap(),
889            ]
890        );
891    }
892
893    #[test]
894    fn test_decode_deriv_path_sorted() {
895        let bytes = encode_derivation_paths(vec![
896            DerivationPath::from_str("84'/0'/0'/2'").unwrap(),
897            DerivationPath::from_str("0/1h/2/3h").unwrap(),
898        ])
899        .unwrap();
900        let (_, paths) = parse_derivation_paths(&bytes).unwrap();
901        assert_eq!(
902            paths,
903            // NOTE: order of derivation paths is reverted here as during parsing they are stored
904            // in an BTreeSet in order to avoid duplicates
905            vec![
906                DerivationPath::from_str("0/1h/2/3h").unwrap(),
907                DerivationPath::from_str("84'/0'/0'/2'").unwrap(),
908            ]
909        );
910    }
911
912    #[test]
913    fn test_decode_deriv_path_no_duplicates() {
914        let bytes = encode_derivation_paths(vec![
915            DerivationPath::from_str("0/1h/2/3h").unwrap(),
916            DerivationPath::from_str("84'/0'/0'/2'").unwrap(),
917            DerivationPath::from_str("84'/0'/0'/2'").unwrap(),
918        ])
919        .unwrap();
920        let (_, paths) = parse_derivation_paths(&bytes).unwrap();
921        assert_eq!(
922            paths,
923            vec![
924                DerivationPath::from_str("0/1h/2/3h").unwrap(),
925                DerivationPath::from_str("84'/0'/0'/2'").unwrap(),
926            ]
927        );
928    }
929
930    #[test]
931    fn test_decode_deriv_path_empty() {
932        let bytes = encode_derivation_paths(vec![]).unwrap();
933        assert_eq!(bytes, vec![0x00]);
934        let (_, paths) = parse_derivation_paths(&bytes).unwrap();
935        assert_eq!(paths, vec![]);
936    }
937
938    #[test]
939    fn test_encode_too_much_deriv_paths() {
940        let mut deriv_paths = vec![];
941        for _ in 0..256 {
942            deriv_paths.push(DerivationPath::from_str("0/1h/2/3h").unwrap());
943        }
944        assert_eq!(deriv_paths.len(), 256);
945        let res = encode_derivation_paths(deriv_paths);
946        assert_eq!(res, Err(Error::DerivPathLength));
947    }
948
949    #[test]
950    fn test_encode_too_long_deriv_paths() {
951        let mut deriv_path = vec![];
952        for _ in 0..256 {
953            deriv_path.push(ChildNumber::from_normal_idx(0).unwrap());
954        }
955        assert_eq!(deriv_path.len(), 256);
956        let res = encode_derivation_paths(vec![DerivationPath::from(deriv_path)]);
957        assert_eq!(res, Err(Error::DerivPathLength));
958    }
959
960    #[test]
961    fn test_encode_decode_encrypted_payload() {
962        let payloads = [
963            "test".as_bytes().to_vec(),
964            [1; 0x1FFF].to_vec(),
965            [2; 0x2FFFFFFF].to_vec(),
966        ];
967        for payload in payloads {
968            let bytes = encode_encrypted_payload([3; 12], &payload).unwrap();
969            let (nonce, cyphertext) = parse_encrypted_payload(&bytes).unwrap();
970            assert_eq!([3u8; 12], nonce);
971            assert_eq!(payload, cyphertext);
972        }
973    }
974
975    #[test]
976    fn test_encode_empty_individual_secrets() {
977        let res = encode_individual_secrets(&[]);
978        assert_eq!(res, Err(Error::IndividualSecretsEmpty));
979    }
980
981    #[test]
982    fn test_too_much_individual_secrets() {
983        let mut secrets = vec![];
984        let mut rng = OsRng;
985        for _ in 0..256 {
986            let mut secret = [0u8; 32];
987            rng.try_fill_bytes(&mut secret).unwrap();
988            secrets.push(secret);
989        }
990        let res = encode_individual_secrets(&secrets);
991        assert_eq!(res, Err(Error::IndividualSecretsLength));
992    }
993
994    #[test]
995    fn test_encode_decode_individual_secrets() {
996        let secrets = vec![[0; 32], [1; 32]];
997        let bytes = encode_individual_secrets(&secrets).unwrap();
998        let expected = vec![
999            2u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1000            0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1001            1, 1, 1, 1, 1, 1, 1, 1,
1002        ];
1003        assert_eq!(expected, bytes);
1004        let (_, decoded) = parse_individual_secrets(&bytes).unwrap();
1005        assert_eq!(secrets, decoded);
1006    }
1007
1008    #[test]
1009    fn test_encode_individual_secrets_no_duplicates() {
1010        let secrets = vec![[0; 32], [0; 32]];
1011        let bytes = encode_individual_secrets(&secrets).unwrap();
1012        let expected = vec![
1013            1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1014            0, 0, 0, 0, 0,
1015        ];
1016        assert_eq!(expected, bytes);
1017    }
1018
1019    #[test]
1020    fn test_decode_individual_secrets_no_duplicates() {
1021        let bytes = vec![
1022            2u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1023            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1024            0, 0, 0, 0, 0, 0, 0, 0,
1025        ];
1026        let (_, secrets) = parse_individual_secrets(&bytes).unwrap();
1027        assert_eq!(secrets.len(), 1);
1028    }
1029
1030    #[test]
1031    fn test_encode_decode_v1() {
1032        let bytes = encode_v1(
1033            0x01,
1034            encode_derivation_paths(vec![DerivationPath::from_str("8/9").unwrap()]).unwrap(),
1035            [0x01; 33].to_vec(),
1036            0x01,
1037            encode_encrypted_payload([0x04u8; 12], &[0x00]).unwrap(),
1038        );
1039        // <MAGIC>
1040        let mut expected = MAGIC.as_bytes().to_vec();
1041        // <VERSION>
1042        expected.append(&mut vec![0x01]);
1043        // <DERIVATION_PATHS>
1044        expected.append(&mut vec![
1045            0x01, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09,
1046        ]);
1047        // <INDIVIDUAL_SECRETS>
1048        expected.append(&mut [0x01; 33].to_vec());
1049        // <ENCRYPTION>
1050        expected.append(&mut vec![0x01]);
1051        // <ENCRYPTED_PAYLOAD>
1052        expected.append(&mut encode_encrypted_payload([0x04u8; 12], &[0x00]).unwrap());
1053        assert_eq!(bytes, expected);
1054        let version = decode_version(&bytes).unwrap();
1055        assert_eq!(version, 0x01);
1056        let derivs = decode_derivation_paths(&bytes).unwrap();
1057        assert_eq!(derivs, vec![DerivationPath::from_str("8/9").unwrap()]);
1058        let (derivs, secrets, encryption, nonce, cyphertext) = decode_v1(&bytes).unwrap();
1059        assert_eq!(derivs, vec![DerivationPath::from_str("8/9").unwrap()]);
1060        assert_eq!(secrets, vec![[0x01; 32]]);
1061        assert_eq!(encryption, 0x01);
1062        assert_eq!(nonce, [0x04u8; 12]);
1063        assert_eq!(cyphertext, vec![0x00]);
1064    }
1065
1066    #[test]
1067    fn test_encrypt_sanitizing() {
1068        // Empty keyvector must fail
1069        let keys = vec![];
1070        let data = "test".as_bytes().to_vec();
1071        let res = encrypt_aes_gcm_256_v1(vec![], Content::Bip380, keys, &data);
1072        assert_eq!(res, Err(Error::KeyCount));
1073
1074        // > 255 keys must fail
1075        let mut keys = BTreeSet::new();
1076        while keys.len() < 256 {
1077            let key: [u8; 32] = random();
1078            if let Ok(k) = XOnlyPublicKey::from_slice(&key) {
1079                let k = bitcoin::secp256k1::PublicKey::from_x_only_public_key(
1080                    k,
1081                    secp256k1::Parity::Odd,
1082                );
1083                keys.insert(k);
1084            }
1085        }
1086        let keys = keys.into_iter().collect::<Vec<_>>();
1087        let res = encrypt_aes_gcm_256_v1(vec![], Content::Bip380, keys, &data);
1088        assert_eq!(res, Err(Error::KeyCount));
1089
1090        // Empty payload must fail
1091        let keys = [pk1()].to_vec();
1092        let res = encrypt_aes_gcm_256_v1(vec![], Content::Bip380, keys, &[]);
1093        assert_eq!(res, Err(Error::DataLength));
1094
1095        // > 255 deriv path must fail
1096        let keys = [pk1()].to_vec();
1097        let mut deriv_paths = BTreeSet::new();
1098        while deriv_paths.len() < 256 {
1099            let raw_deriv: [u32; 4] = random();
1100            let childs: Vec<ChildNumber> =
1101                raw_deriv.iter().copied().map(ChildNumber::from).collect();
1102            let deriv: DerivationPath = childs.into();
1103            deriv_paths.insert(deriv);
1104        }
1105        let deriv_paths = deriv_paths.into_iter().collect();
1106        let res = encrypt_aes_gcm_256_v1(deriv_paths, Content::Bip380, keys, &data);
1107        assert_eq!(res, Err(Error::DerivPathCount));
1108    }
1109
1110    #[test]
1111    fn test_basic_encrypt_decrypt() {
1112        let keys = vec![pk2(), pk1()];
1113        let data = "test".as_bytes().to_vec();
1114        let bytes = encrypt_aes_gcm_256_v1(vec![], Content::None, keys, &data).unwrap();
1115
1116        let version = decode_version(&bytes).unwrap();
1117        assert_eq!(version, 1);
1118
1119        let deriv_paths = decode_derivation_paths(&bytes).unwrap();
1120        assert!(deriv_paths.is_empty());
1121
1122        let (_, individual_secrets, encryption_type, nonce, cyphertext) =
1123            decode_v1(&bytes).unwrap();
1124        assert_eq!(encryption_type, 0x01);
1125
1126        let (content, decrypted_1) =
1127            decrypt_aes_gcm_256_v1(pk1(), &individual_secrets, cyphertext.clone(), nonce).unwrap();
1128        assert_eq!(content, Content::None);
1129        assert_eq!(String::from_utf8(decrypted_1).unwrap(), "test".to_string());
1130        let (content, decrypted_2) =
1131            decrypt_aes_gcm_256_v1(pk2(), &individual_secrets, cyphertext.clone(), nonce).unwrap();
1132        assert_eq!(content, Content::None);
1133        assert_eq!(String::from_utf8(decrypted_2).unwrap(), "test".to_string());
1134        let decrypted_3 =
1135            decrypt_aes_gcm_256_v1(pk3(), &individual_secrets, cyphertext.clone(), nonce);
1136        assert!(decrypted_3.is_err());
1137    }
1138
1139    #[test]
1140    fn test_decrypt_wrong_secret() {
1141        let mut engine = sha256::HashEngine::default();
1142        engine.input("secret".as_bytes());
1143        let secret = sha256::Hash::from_engine(engine);
1144
1145        let mut engine = sha256::HashEngine::default();
1146        engine.input("wrong_secret".as_bytes());
1147        let wrong_secret = sha256::Hash::from_engine(engine);
1148
1149        let payload = "payload".as_bytes().to_vec();
1150        let (nonce, ciphertext) = inner_encrypt(secret, payload).unwrap();
1151        // decrypting with secret success
1152        let _ = try_decrypt_aes_gcm_256(&ciphertext, secret.as_byte_array(), nonce).unwrap();
1153        // decrypting with wrong secret fails
1154        let fails = try_decrypt_aes_gcm_256(&ciphertext, wrong_secret.as_byte_array(), nonce);
1155        assert!(fails.is_none());
1156    }
1157
1158    #[test]
1159    fn test_decrypt_wrong_nonce() {
1160        let mut engine = sha256::HashEngine::default();
1161        engine.input("secret".as_bytes());
1162        let secret = sha256::Hash::from_engine(engine);
1163
1164        let payload = "payload".as_bytes().to_vec();
1165        let (nonce, ciphertext) = inner_encrypt(secret, payload).unwrap();
1166        // decrypting with correct nonce success
1167        let _ = try_decrypt_aes_gcm_256(&ciphertext, secret.as_byte_array(), nonce).unwrap();
1168        // decrypting with wrong nonce fails
1169        let nonce = [0xF1; 12];
1170        let fails = try_decrypt_aes_gcm_256(&ciphertext, secret.as_byte_array(), nonce);
1171        assert!(fails.is_none());
1172    }
1173
1174    #[test]
1175    fn test_decrypt_corrupted_ciphertext_fails() {
1176        let mut engine = sha256::HashEngine::default();
1177        engine.input("secret".as_bytes());
1178        let secret = sha256::Hash::from_engine(engine);
1179
1180        let payload = "payload".as_bytes().to_vec();
1181        let (nonce, mut ciphertext) = inner_encrypt(secret, payload).unwrap();
1182        // decrypting with secret success
1183        let _ = try_decrypt_aes_gcm_256(&ciphertext, secret.as_byte_array(), nonce).unwrap();
1184
1185        // corrupting the ciphertext
1186        let offset = ciphertext.len() - 10;
1187        for i in offset..offset + 5 {
1188            *ciphertext.get_mut(i).unwrap() = 0;
1189        }
1190
1191        // decryption must then fails
1192        let fails = try_decrypt_aes_gcm_256(&ciphertext, secret.as_byte_array(), nonce);
1193        assert!(fails.is_none());
1194    }
1195}