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