libsignal_service/
master_key.rs

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