Skip to main content

libsignal_service/
master_key.rs

1use hmac::KeyInit as _;
2use rand::{CryptoRng, Rng};
3
4const MASTER_KEY_LEN: usize = 32;
5const STORAGE_KEY_LEN: usize = 32;
6
7#[derive(Debug, PartialEq)]
8pub struct MasterKey {
9    pub inner: [u8; MASTER_KEY_LEN],
10}
11
12impl MasterKey {
13    pub fn generate<R: Rng + CryptoRng>(csprng: &mut R) -> Self {
14        // Create random bytes
15        let mut inner = [0_u8; MASTER_KEY_LEN];
16        csprng.fill(&mut inner);
17        Self { inner }
18    }
19
20    pub fn from_slice(
21        slice: &[u8],
22    ) -> Result<Self, std::array::TryFromSliceError> {
23        let inner = slice.try_into()?;
24        Ok(Self { inner })
25    }
26}
27
28impl From<MasterKey> for Vec<u8> {
29    fn from(val: MasterKey) -> Self {
30        val.inner.to_vec()
31    }
32}
33
34#[derive(Debug, PartialEq)]
35pub struct StorageServiceKey {
36    pub inner: [u8; STORAGE_KEY_LEN],
37}
38
39impl StorageServiceKey {
40    pub fn from_master_key(master_key: &MasterKey) -> Self {
41        use hmac::{Hmac, Mac};
42        use sha2::Sha256;
43
44        type HmacSha256 = Hmac<Sha256>;
45        const KEY: &[u8] = b"Storage Service Encryption";
46
47        let mut mac = HmacSha256::new_from_slice(&master_key.inner).unwrap();
48        mac.update(KEY);
49        let result = mac.finalize();
50        let inner: [u8; STORAGE_KEY_LEN] = result.into_bytes().into();
51
52        Self { inner }
53    }
54
55    pub fn from_slice(
56        slice: &[u8],
57    ) -> Result<Self, std::array::TryFromSliceError> {
58        let inner = slice.try_into()?;
59        Ok(Self { inner })
60    }
61}
62
63impl From<StorageServiceKey> for Vec<u8> {
64    fn from(val: StorageServiceKey) -> Self {
65        val.inner.to_vec()
66    }
67}
68
69/// Storage trait for handling MasterKey and StorageKey.
70pub trait MasterKeyStore {
71    /// Fetch the master key from the store if it exists.
72    fn fetch_master_key(&self) -> Option<MasterKey>;
73
74    /// Fetch the storage service key from the store if it exists.
75    fn fetch_storage_service_key(&self) -> Option<StorageServiceKey>;
76
77    /// Save (or clear) the master key to the store.
78    fn store_master_key(&self, master_key: Option<&MasterKey>);
79
80    /// Save (or clear) the storage service key to the store.
81    fn store_storage_service_key(
82        &self,
83        storage_key: Option<&StorageServiceKey>,
84    );
85}
86
87mod tests {
88    #[test]
89    fn derive_storage_key_from_master_key() {
90        use super::{MasterKey, StorageServiceKey};
91        use base64::prelude::*;
92
93        // This test passed with actual 'masterKey' and 'storageKey' values taken
94        // from Signal Desktop v7.23.0 database at 2024-09-08 after linking it with Signal Andoid.
95
96        let master_key_bytes = BASE64_STANDARD
97            .decode("9hquLIIZmom8fHF7H8pbUAreawmPLEqli5ceJ94pFkU=")
98            .unwrap();
99        let storage_key_bytes = BASE64_STANDARD
100            .decode("QMgZ5RGTLFTr4u/J6nypaJX6DKDlSgMw8vmxU6gxnvI=")
101            .unwrap();
102        assert_eq!(master_key_bytes.len(), 32);
103        assert_eq!(storage_key_bytes.len(), 32);
104
105        let master_key = MasterKey::from_slice(&master_key_bytes).unwrap();
106        let storage_key = StorageServiceKey::from_master_key(&master_key);
107
108        assert_eq!(master_key.inner, master_key_bytes.as_slice());
109        assert_eq!(storage_key.inner, storage_key_bytes.as_slice());
110    }
111}