bitwarden_crypto/enc_string/
mod.rs

1//! Encrypted string types
2//!
3//! [EncString] and [UnsignedSharedKey] are Bitwarden specific primitive that represents a
4//! encrypted string. They are are used together with the [KeyDecryptable][crate::KeyDecryptable]
5//! and [KeyEncryptable][crate::KeyEncryptable] traits to encrypt and decrypt data using
6//! [SymmetricCryptoKey][crate::SymmetricCryptoKey] and
7//! [AsymmetricCryptoKey][crate::AsymmetricCryptoKey]s.
8
9mod asymmetric;
10mod symmetric;
11
12pub use asymmetric::UnsignedSharedKey;
13use bitwarden_encoding::B64;
14pub use symmetric::EncString;
15
16use crate::error::{EncStringParseError, Result};
17
18fn check_length(buf: &[u8], expected: usize) -> Result<()> {
19    if buf.len() < expected {
20        return Err(EncStringParseError::InvalidLength {
21            expected,
22            got: buf.len(),
23        }
24        .into());
25    }
26    Ok(())
27}
28
29fn from_b64_vec(s: &str) -> Result<Vec<u8>> {
30    Ok(B64::try_from(s)
31        .map_err(EncStringParseError::InvalidBase64)?
32        .as_bytes()
33        .to_vec())
34}
35
36fn from_b64<const N: usize>(s: &str) -> Result<[u8; N]> {
37    Ok(from_b64_vec(s)?
38        .try_into()
39        .map_err(|e: Vec<_>| EncStringParseError::InvalidLength {
40            expected: N,
41            got: e.len(),
42        })?)
43}
44
45fn split_enc_string(s: &str) -> (&str, Vec<&str>) {
46    let header_parts: Vec<_> = s.split('.').collect();
47
48    if header_parts.len() == 2 {
49        (header_parts[0], header_parts[1].split('|').collect())
50    } else {
51        // Support legacy format with no header
52        let parts: Vec<_> = s.split('|').collect();
53        if parts.len() == 3 {
54            ("1", parts) // Aes128Cbc_HmacSha256_B64
55        } else {
56            ("0", parts) // Aes256Cbc_B64
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_check_length_less_than_expected() {
67        let buf = [1, 2, 3];
68        let expected = 5;
69        let result = check_length(&buf, expected);
70        assert!(result.is_err());
71    }
72
73    #[test]
74    fn test_check_length_equal_to_expected() {
75        let buf = [1, 2, 3, 4, 5];
76        let expected = 5;
77        let result = check_length(&buf, expected);
78        assert!(result.is_ok());
79    }
80
81    #[test]
82    fn test_check_length_greater_than_expected() {
83        let buf = [1, 2, 3, 4, 5, 6];
84        let expected = 5;
85        let result = check_length(&buf, expected);
86        assert!(result.is_ok());
87    }
88
89    #[test]
90    fn test_split_enc_string_new_format() {
91        let s = "2.abc|def|ghi";
92        let (header, parts) = split_enc_string(s);
93        assert_eq!(header, "2");
94        assert_eq!(parts, vec!["abc", "def", "ghi"]);
95    }
96
97    #[test]
98    fn test_split_enc_string_old_format_three_parts() {
99        let s = "abc|def|ghi";
100        let (header, parts) = split_enc_string(s);
101        assert_eq!(header, "1");
102        assert_eq!(parts, vec!["abc", "def", "ghi"]);
103    }
104
105    #[test]
106    fn test_split_enc_string_old_format_fewer_parts() {
107        let s = "abc|def";
108        let (header, parts) = split_enc_string(s);
109        assert_eq!(header, "0");
110        assert_eq!(parts, vec!["abc", "def"]);
111    }
112}