1use aes_gcm_siv::aead::generic_array::GenericArray;
7use aes_gcm_siv::aead::Aead;
8use aes_gcm_siv::{Aes256GcmSiv, KeyInit};
9use partial_default::PartialDefault;
10use serde::{Deserialize, Serialize};
11
12use crate::common::constants::*;
13use crate::common::errors::*;
14use crate::common::serialization::ReservedByte;
15use crate::common::sho::*;
16use crate::common::simple_types::*;
17use crate::crypto::uid_encryption;
18use crate::{api, crypto};
19
20#[derive(Copy, Clone, Serialize, Deserialize, Default)]
21pub struct GroupMasterKey {
22 pub(crate) bytes: [u8; GROUP_MASTER_KEY_LEN],
23}
24
25#[derive(Copy, Clone, Serialize, Deserialize, PartialDefault)]
26pub struct GroupSecretParams {
27 reserved: ReservedByte,
28 master_key: GroupMasterKey,
29 group_id: GroupIdentifierBytes,
30 blob_key: AesKeyBytes,
31 pub(crate) uid_enc_key_pair: crypto::uid_encryption::KeyPair,
32 pub(crate) profile_key_enc_key_pair: crypto::profile_key_encryption::KeyPair,
33}
34
35impl AsRef<uid_encryption::KeyPair> for GroupSecretParams {
36 fn as_ref(&self) -> &uid_encryption::KeyPair {
37 &self.uid_enc_key_pair
38 }
39}
40
41#[derive(Copy, Clone, Serialize, Deserialize, PartialDefault)]
42pub struct GroupPublicParams {
43 reserved: ReservedByte,
44 group_id: GroupIdentifierBytes,
45 pub(crate) uid_enc_public_key: crypto::uid_encryption::PublicKey,
46 pub(crate) profile_key_enc_public_key: crypto::profile_key_encryption::PublicKey,
47}
48
49impl GroupMasterKey {
50 pub fn new(bytes: [u8; GROUP_MASTER_KEY_LEN]) -> Self {
51 GroupMasterKey { bytes }
52 }
53}
54
55const ENCRYPTED_BLOB_PADDING_LENGTH_SIZE: usize = std::mem::size_of::<u32>();
56
57impl GroupSecretParams {
58 pub fn generate(randomness: RandomnessBytes) -> Self {
59 let mut sho = Sho::new(
60 b"Signal_ZKGroup_20200424_Random_GroupSecretParams_Generate",
61 &randomness,
62 );
63 let master_key = GroupMasterKey::new(sho.squeeze_as_array());
64 GroupSecretParams::derive_from_master_key(master_key)
65 }
66
67 pub fn derive_from_master_key(master_key: GroupMasterKey) -> Self {
68 let mut sho = Sho::new(
69 b"Signal_ZKGroup_20200424_GroupMasterKey_GroupSecretParams_DeriveFromMasterKey",
70 &master_key.bytes,
71 );
72 let group_id: GroupIdentifierBytes = sho.squeeze_as_array();
73 let blob_key: AesKeyBytes = sho.squeeze_as_array();
74 let uid_enc_key_pair = crypto::uid_encryption::KeyPair::derive_from(sho.as_mut());
75 let profile_key_enc_key_pair =
76 crypto::profile_key_encryption::KeyPair::derive_from(sho.as_mut());
77
78 Self {
79 reserved: Default::default(),
80 master_key,
81 group_id,
82 blob_key,
83 uid_enc_key_pair,
84 profile_key_enc_key_pair,
85 }
86 }
87
88 pub fn get_master_key(&self) -> GroupMasterKey {
89 self.master_key
90 }
91
92 pub fn get_group_identifier(&self) -> GroupIdentifierBytes {
93 self.group_id
94 }
95
96 pub fn get_public_params(&self) -> GroupPublicParams {
97 GroupPublicParams {
98 reserved: Default::default(),
99 uid_enc_public_key: self.uid_enc_key_pair.public_key,
100 profile_key_enc_public_key: self.profile_key_enc_key_pair.public_key,
101 group_id: self.group_id,
102 }
103 }
104
105 pub fn encrypt_service_id(
106 &self,
107 service_id: libsignal_core::ServiceId,
108 ) -> api::groups::UuidCiphertext {
109 let uid = crypto::uid_struct::UidStruct::from_service_id(service_id);
110 self.encrypt_uid_struct(uid)
111 }
112
113 pub fn encrypt_uid_struct(
114 &self,
115 uid: crypto::uid_struct::UidStruct,
116 ) -> api::groups::UuidCiphertext {
117 let ciphertext = self.uid_enc_key_pair.encrypt(&uid);
118 api::groups::UuidCiphertext {
119 reserved: Default::default(),
120 ciphertext,
121 }
122 }
123
124 pub fn decrypt_service_id(
125 &self,
126 ciphertext: api::groups::UuidCiphertext,
127 ) -> Result<libsignal_core::ServiceId, ZkGroupVerificationFailure> {
128 crypto::uid_encryption::UidEncryptionDomain::decrypt(
129 &self.uid_enc_key_pair,
130 &ciphertext.ciphertext,
131 )
132 }
133
134 pub fn encrypt_profile_key(
135 &self,
136 profile_key: api::profiles::ProfileKey,
137 user_id: libsignal_core::Aci,
138 ) -> api::groups::ProfileKeyCiphertext {
139 self.encrypt_profile_key_bytes(profile_key.bytes, user_id)
140 }
141
142 pub fn encrypt_profile_key_bytes(
143 &self,
144 profile_key_bytes: ProfileKeyBytes,
145 user_id: libsignal_core::Aci,
146 ) -> api::groups::ProfileKeyCiphertext {
147 let profile_key = crypto::profile_key_struct::ProfileKeyStruct::new(
148 profile_key_bytes,
149 uuid::Uuid::from(user_id).into_bytes(),
150 );
151 let ciphertext = self.profile_key_enc_key_pair.encrypt(&profile_key);
152 api::groups::ProfileKeyCiphertext {
153 reserved: Default::default(),
154 ciphertext,
155 }
156 }
157
158 pub fn decrypt_profile_key(
159 &self,
160 ciphertext: api::groups::ProfileKeyCiphertext,
161 user_id: libsignal_core::Aci,
162 ) -> Result<api::profiles::ProfileKey, ZkGroupVerificationFailure> {
163 let profile_key_struct =
164 crypto::profile_key_encryption::ProfileKeyEncryptionDomain::decrypt(
165 &self.profile_key_enc_key_pair,
166 &ciphertext.ciphertext,
167 uuid::Uuid::from(user_id).into_bytes(),
168 )?;
169 Ok(api::profiles::ProfileKey {
170 bytes: profile_key_struct.bytes,
171 })
172 }
173
174 pub fn encrypt_blob(&self, randomness: RandomnessBytes, plaintext: &[u8]) -> Vec<u8> {
175 let mut sho = Sho::new(
176 b"Signal_ZKGroup_20200424_Random_GroupSecretParams_EncryptBlob",
177 &randomness,
178 );
179 let nonce_vec = sho.squeeze_as_array::<AESGCM_NONCE_LEN>();
180 let mut ciphertext_vec = self.encrypt_blob_aesgcmsiv(&self.blob_key, &nonce_vec, plaintext);
181 ciphertext_vec.extend(nonce_vec);
182 ciphertext_vec.extend([0u8]); ciphertext_vec
184 }
185
186 pub fn encrypt_blob_with_padding(
187 &self,
188 randomness: RandomnessBytes,
189 plaintext: &[u8],
190 padding_len: u32,
191 ) -> Vec<u8> {
192 let full_length =
193 ENCRYPTED_BLOB_PADDING_LENGTH_SIZE + plaintext.len() + padding_len as usize;
194 let mut padded_plaintext = Vec::with_capacity(full_length);
195 padded_plaintext.extend_from_slice(&padding_len.to_be_bytes());
196 padded_plaintext.extend_from_slice(plaintext);
197 padded_plaintext.resize(full_length, 0);
198 self.encrypt_blob(randomness, &padded_plaintext)
199 }
200
201 pub fn decrypt_blob(&self, ciphertext: &[u8]) -> Result<Vec<u8>, ZkGroupVerificationFailure> {
202 if ciphertext.len() < AESGCM_NONCE_LEN + 1 {
203 return Err(ZkGroupVerificationFailure);
205 }
206 let unreserved_len = ciphertext.len() - 1;
207 let nonce = &ciphertext[unreserved_len - AESGCM_NONCE_LEN..unreserved_len];
208 let ciphertext = &ciphertext[..unreserved_len - AESGCM_NONCE_LEN];
209 self.decrypt_blob_aesgcmsiv(&self.blob_key, nonce, ciphertext)
210 }
211
212 pub fn decrypt_blob_with_padding(
213 &self,
214 ciphertext: &[u8],
215 ) -> Result<Vec<u8>, ZkGroupVerificationFailure> {
216 let mut decrypted = self.decrypt_blob(ciphertext)?;
217
218 if decrypted.len() < ENCRYPTED_BLOB_PADDING_LENGTH_SIZE {
219 return Err(ZkGroupVerificationFailure);
220 }
221 let (padding_len_bytes, plaintext_plus_padding) =
222 decrypted.split_at(ENCRYPTED_BLOB_PADDING_LENGTH_SIZE);
223
224 let padding_len = u32::from_be_bytes(padding_len_bytes.try_into().expect("correct size"));
225 if plaintext_plus_padding.len() < padding_len as usize {
226 return Err(ZkGroupVerificationFailure);
227 }
228
229 decrypted.truncate(decrypted.len() - padding_len as usize);
230 decrypted.drain(..ENCRYPTED_BLOB_PADDING_LENGTH_SIZE);
231 Ok(decrypted)
232 }
233
234 fn encrypt_blob_aesgcmsiv(&self, key: &[u8], nonce: &[u8], plaintext: &[u8]) -> Vec<u8> {
235 let key = GenericArray::from_slice(key);
236 let aead_cipher = Aes256GcmSiv::new(key);
237 let nonce = GenericArray::from_slice(nonce);
238 aead_cipher
239 .encrypt(nonce, plaintext)
240 .expect("aead encrypt failure")
241 }
242
243 fn decrypt_blob_aesgcmsiv(
244 &self,
245 key: &[u8],
246 nonce: &[u8],
247 ciphertext: &[u8],
248 ) -> Result<Vec<u8>, ZkGroupVerificationFailure> {
249 if ciphertext.len() < AESGCM_TAG_LEN {
250 return Err(ZkGroupVerificationFailure);
252 }
253 let key = GenericArray::from_slice(key);
254 let aead_cipher = Aes256GcmSiv::new(key);
255 let nonce = GenericArray::from_slice(nonce);
256 match aead_cipher.decrypt(nonce, ciphertext) {
257 Ok(plaintext_vec) => Ok(plaintext_vec),
258 Err(_) => Err(ZkGroupVerificationFailure),
259 }
260 }
261}
262
263impl GroupPublicParams {
264 pub fn get_group_identifier(&self) -> GroupIdentifierBytes {
265 self.group_id
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn test_aesgcmsiv_vec1() {
275 let group_secret_params = GroupSecretParams::generate([0u8; RANDOMNESS_LEN]);
278
279 let plaintext_vec = vec![
280 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 0x00, 0x00, 0x00, 0x00,
283 ];
284
285 let key = [
286 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00,
289 ];
290
291 let nonce = [
292 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 ];
294
295 let ciphertext = [
296 0x4a, 0x6a, 0x9d, 0xb4, 0xc8, 0xc6, 0x54, 0x92, 0x01, 0xb9, 0xed, 0xb5, 0x30, 0x06,
297 0xcb, 0xa8, 0x21, 0xec, 0x9c, 0xf8, 0x50, 0x94, 0x8a, 0x7c, 0x86, 0xc6, 0x8a, 0xc7,
298 0x53, 0x9d, 0x02, 0x7f, 0xe8, 0x19, 0xe6, 0x3a, 0xbc, 0xd0, 0x20, 0xb0, 0x06, 0xa9,
299 0x76, 0x39, 0x76, 0x32, 0xeb, 0x5d,
300 ];
301
302 let calc_ciphertext =
303 group_secret_params.encrypt_blob_aesgcmsiv(&key, &nonce, &plaintext_vec);
304
305 assert!(calc_ciphertext[..ciphertext.len()] == ciphertext[..]);
306
307 let calc_plaintext = group_secret_params
308 .decrypt_blob_aesgcmsiv(&key, &nonce, &calc_ciphertext)
309 .unwrap();
310 assert!(calc_plaintext[..] == plaintext_vec[..]);
311 }
312
313 #[test]
314 fn test_aesgcmsiv_vec2() {
315 let group_secret_params = GroupSecretParams::generate([0u8; RANDOMNESS_LEN]);
318
319 let plaintext_vec = vec![
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x4d, 0xb9, 0x23, 0xdc, 0x79, 0x3e, 0xe6, 0x49, 0x7c, 0x76, 0xdc, 0xc0,
322 0x3a, 0x98, 0xe1, 0x08,
323 ];
324
325 let key = [
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00,
329 ];
330
331 let nonce = [
332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 ];
334
335 let ciphertext = [
336 0xf3, 0xf8, 0x0f, 0x2c, 0xf0, 0xcb, 0x2d, 0xd9, 0xc5, 0x98, 0x4f, 0xcd, 0xa9, 0x08,
337 0x45, 0x6c, 0xc5, 0x37, 0x70, 0x3b, 0x5b, 0xa7, 0x03, 0x24, 0xa6, 0x79, 0x3a, 0x7b,
338 0xf2, 0x18, 0xd3, 0xea, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 ];
341
342 let calc_ciphertext =
343 group_secret_params.encrypt_blob_aesgcmsiv(&key, &nonce, &plaintext_vec);
344
345 assert!(calc_ciphertext[..ciphertext.len()] == ciphertext[..]);
346
347 let calc_plaintext = group_secret_params
348 .decrypt_blob_aesgcmsiv(&key, &nonce, &calc_ciphertext)
349 .unwrap();
350 assert!(calc_plaintext[..] == plaintext_vec[..]);
351 }
352
353 #[test]
354 fn test_encrypt_with_padding() {
355 let group_secret_params = GroupSecretParams::generate([0u8; RANDOMNESS_LEN]);
356 let plaintext = b"secret team";
357
358 {
359 let expected_ciphertext_hex = "3798afe9c65ffb35a63b2c048b16f19dd50ee9acc33cc925667a9abad4d4c6f86675fa8e32243e0831203700";
360
361 let calc_ciphertext =
362 group_secret_params.encrypt_blob_with_padding([0u8; RANDOMNESS_LEN], plaintext, 0);
363 assert_eq!(hex::encode(&calc_ciphertext), expected_ciphertext_hex);
364
365 let calc_plaintext = group_secret_params
366 .decrypt_blob_with_padding(&calc_ciphertext)
367 .unwrap();
368 assert_eq!(calc_plaintext[..], plaintext[..]);
369 }
370
371 {
372 let expected_ciphertext_hex = "880a70e071b33f81e1219842c8514f34901abb734c191292ac325455d898da000484080099c620f86675fa8e32243e0831203700";
373
374 let calc_ciphertext =
375 group_secret_params.encrypt_blob_with_padding([0u8; RANDOMNESS_LEN], plaintext, 8);
376 assert_eq!(hex::encode(&calc_ciphertext), expected_ciphertext_hex);
377
378 let calc_plaintext = group_secret_params
379 .decrypt_blob_with_padding(&calc_ciphertext)
380 .unwrap();
381 assert_eq!(calc_plaintext[..], plaintext[..]);
382 }
383 }
384}