openmls/treesync/node/
encryption_keys.rs

1use std::fmt::Debug;
2
3use openmls_traits::{
4    crypto::OpenMlsCrypto,
5    random::OpenMlsRand,
6    storage::{StorageProvider as StorageProviderTrait, CURRENT_VERSION},
7    types::{Ciphersuite, HpkeCiphertext, HpkeKeyPair},
8};
9use serde::{Deserialize, Serialize};
10use tls_codec::{TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize, VLBytes};
11
12use crate::{
13    ciphersuite::{hpke, HpkePrivateKey, HpkePublicKey, Secret},
14    error::LibraryError,
15    storage::{OpenMlsProvider, StorageProvider},
16};
17
18/// [`EncryptionKey`] contains an HPKE public key that allows the encryption of
19/// path secrets in MLS commits.
20#[derive(
21    Debug,
22    Clone,
23    Serialize,
24    Deserialize,
25    TlsSerialize,
26    TlsDeserialize,
27    TlsDeserializeBytes,
28    TlsSize,
29    PartialEq,
30    Eq,
31    Hash,
32)]
33pub struct EncryptionKey {
34    key: HpkePublicKey,
35}
36
37impl EncryptionKey {
38    /// Return the internal [`HpkePublicKey`].
39    pub(crate) fn key(&self) -> &HpkePublicKey {
40        &self.key
41    }
42
43    /// Return the internal [`HpkePublicKey`] as slice.
44    pub(crate) fn as_slice(&self) -> &[u8] {
45        self.key.as_slice()
46    }
47
48    /// Encrypt to this HPKE public key.
49    pub(crate) fn encrypt(
50        &self,
51        crypto: &impl OpenMlsCrypto,
52        ciphersuite: Ciphersuite,
53        context: &[u8],
54        plaintext: &[u8],
55    ) -> Result<HpkeCiphertext, LibraryError> {
56        hpke::encrypt_with_label(
57            self.as_slice(),
58            "UpdatePathNode",
59            context,
60            plaintext,
61            ciphersuite,
62            crypto,
63        )
64        .map_err(|_| LibraryError::custom("Encryption failed. A serialization issue really"))
65    }
66}
67
68impl From<Vec<u8>> for EncryptionKey {
69    fn from(key: Vec<u8>) -> Self {
70        Self { key: key.into() }
71    }
72}
73
74#[derive(
75    Clone, Serialize, Deserialize, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
76)]
77#[cfg_attr(any(test, feature = "test-utils"), derive(PartialEq, Eq))]
78pub struct EncryptionPrivateKey {
79    key: HpkePrivateKey,
80}
81
82impl Debug for EncryptionPrivateKey {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        let mut ds = f.debug_struct("EncryptionPrivateKey");
85
86        #[cfg(feature = "crypto-debug")]
87        ds.field("key", &self.key);
88        #[cfg(not(feature = "crypto-debug"))]
89        ds.field("key", &"***");
90
91        ds.finish()
92    }
93}
94
95impl From<Vec<u8>> for EncryptionPrivateKey {
96    fn from(key: Vec<u8>) -> Self {
97        Self { key: key.into() }
98    }
99}
100
101impl From<HpkePrivateKey> for EncryptionPrivateKey {
102    fn from(key: HpkePrivateKey) -> Self {
103        Self { key }
104    }
105}
106
107impl EncryptionPrivateKey {
108    /// Decrypt a given `HpkeCiphertext` using this [`EncryptionPrivateKey`] and
109    /// `group_context`.
110    ///
111    /// Returns the decrypted [`Secret`]. Returns an error if the decryption was
112    /// unsuccessful.
113    pub(crate) fn decrypt(
114        &self,
115        crypto: &impl OpenMlsCrypto,
116        ciphersuite: Ciphersuite,
117        ciphertext: &HpkeCiphertext,
118        group_context: &[u8],
119    ) -> Result<Secret, hpke::Error> {
120        // ValSem203: Path secrets must decrypt correctly
121        hpke::decrypt_with_label(
122            &self.key,
123            "UpdatePathNode",
124            group_context,
125            ciphertext,
126            ciphersuite,
127            crypto,
128        )
129        .map(|secret_bytes| Secret::from_slice(&secret_bytes))
130    }
131}
132
133#[cfg(any(test, feature = "test-utils"))]
134impl EncryptionPrivateKey {
135    pub(crate) fn key(&self) -> &HpkePrivateKey {
136        &self.key
137    }
138}
139
140impl From<HpkePublicKey> for EncryptionKey {
141    fn from(key: HpkePublicKey) -> Self {
142        Self { key }
143    }
144}
145
146#[derive(
147    Debug, Clone, Serialize, Deserialize, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
148)]
149#[cfg_attr(any(test, feature = "test-utils"), derive(PartialEq, Eq))]
150pub(crate) struct EncryptionKeyPair {
151    public_key: EncryptionKey,
152    private_key: EncryptionPrivateKey,
153}
154
155impl EncryptionKeyPair {
156    /// Write the [`EncryptionKeyPair`] to the store of the `provider`.
157    ///
158    /// This must only be used for encryption key pairs that are generated for
159    /// update leaf nodes. All other encryption key pairs are stored as part
160    /// of the key package or the epoch encryption key pairs.
161    pub(crate) fn write<Storage: StorageProvider>(
162        &self,
163        store: &Storage,
164    ) -> Result<(), Storage::Error> {
165        store.write_encryption_key_pair(self.public_key(), self)
166    }
167
168    /// Read the [`EncryptionKeyPair`] from the key store of the `provider`. This
169    /// function is meant to read standalone keypairs, not ones that are
170    /// already in use with an MLS group.
171    ///
172    /// This must only be used for encryption key pairs that are generated for
173    /// update leaf nodes. All other encryption key pairs are stored as part
174    /// of the key package or the epoch encryption key pairs.
175    ///
176    /// Returns `None` if the keypair cannot be read from the store.
177    pub(crate) fn read(
178        provider: &impl OpenMlsProvider,
179        encryption_key: &EncryptionKey,
180    ) -> Option<EncryptionKeyPair> {
181        provider
182            .storage()
183            .encryption_key_pair(encryption_key)
184            .ok()
185            .flatten()
186    }
187
188    /// Delete the [`EncryptionKeyPair`] from the store of the `provider`.
189    ///
190    /// This must only be used for encryption key pairs that are generated for
191    /// update leaf nodes. All other encryption key pairs are stored as part
192    /// of the key package or the epoch encryption key pairs.
193    pub(crate) fn delete<Storage: StorageProviderTrait<CURRENT_VERSION>>(
194        &self,
195        store: &Storage,
196    ) -> Result<(), Storage::Error> {
197        store.delete_encryption_key_pair(self.public_key())
198    }
199
200    pub(crate) fn public_key(&self) -> &EncryptionKey {
201        &self.public_key
202    }
203
204    pub(crate) fn private_key(&self) -> &EncryptionPrivateKey {
205        &self.private_key
206    }
207
208    pub(crate) fn random(
209        rand: &impl OpenMlsRand,
210        crypto: &impl OpenMlsCrypto,
211        ciphersuite: Ciphersuite,
212    ) -> Result<Self, LibraryError> {
213        let ikm =
214            Secret::random(ciphersuite, rand).map_err(LibraryError::unexpected_crypto_error)?;
215        Ok(crypto
216            .derive_hpke_keypair(ciphersuite.hpke_config(), ikm.as_slice())
217            .map_err(LibraryError::unexpected_crypto_error)?
218            .into())
219    }
220}
221
222#[cfg(feature = "test-utils")]
223pub mod test_utils {
224    use super::*;
225
226    pub fn read_keys_from_key_store(
227        provider: &impl OpenMlsProvider,
228        encryption_key: &EncryptionKey,
229    ) -> HpkeKeyPair {
230        let keys = EncryptionKeyPair::read(provider, encryption_key).unwrap();
231
232        HpkeKeyPair {
233            private: keys.private_key.key,
234            public: keys.public_key.key.as_slice().to_vec(),
235        }
236    }
237
238    pub fn write_keys_from_key_store(provider: &impl OpenMlsProvider, encryption_key: HpkeKeyPair) {
239        let keypair = EncryptionKeyPair::from(encryption_key);
240
241        keypair.write(provider.storage()).unwrap();
242    }
243}
244
245#[cfg(test)]
246impl EncryptionKeyPair {
247    /// Build a key pair from raw bytes for testing.
248    pub(crate) fn from_raw(public_key: Vec<u8>, private_key: Vec<u8>) -> Self {
249        Self {
250            public_key: EncryptionKey {
251                key: public_key.into(),
252            },
253            private_key: EncryptionPrivateKey {
254                key: private_key.into(),
255            },
256        }
257    }
258}
259
260impl From<(HpkePublicKey, HpkePrivateKey)> for EncryptionKeyPair {
261    fn from((public_key, private_key): (HpkePublicKey, HpkePrivateKey)) -> Self {
262        Self {
263            public_key: public_key.into(),
264            private_key: private_key.into(),
265        }
266    }
267}
268
269impl From<HpkeKeyPair> for EncryptionKeyPair {
270    fn from(hpke_keypair: HpkeKeyPair) -> Self {
271        let public_bytes: VLBytes = hpke_keypair.public.into();
272        let private_bytes = hpke_keypair.private;
273        Self {
274            public_key: public_bytes.into(),
275            private_key: private_bytes.into(),
276        }
277    }
278}
279
280impl From<(EncryptionKey, EncryptionPrivateKey)> for EncryptionKeyPair {
281    fn from((public_key, private_key): (EncryptionKey, EncryptionPrivateKey)) -> Self {
282        Self {
283            public_key,
284            private_key,
285        }
286    }
287}