1use std::pin::Pin;
2
3use bitwarden_encoding::B64;
4use coset::{CborSerializable, RegisteredLabelWithPrivate, iana::KeyOperation};
5use generic_array::GenericArray;
6use rand::Rng;
7#[cfg(test)]
8use rand::SeedableRng;
9#[cfg(test)]
10use rand_chacha::ChaChaRng;
11#[cfg(test)]
12use sha2::Digest;
13use subtle::{Choice, ConstantTimeEq};
14use typenum::U32;
15use zeroize::{Zeroize, ZeroizeOnDrop};
16
17use super::{key_encryptable::CryptoKey, key_id::KeyId};
18use crate::{BitwardenLegacyKeyBytes, ContentFormat, CoseKeyBytes, CryptoError, cose};
19
20#[derive(Debug, PartialEq)]
22pub enum SymmetricKeyAlgorithm {
23 Aes256CbcHmac,
25 XChaCha20Poly1305,
27}
28
29#[derive(ZeroizeOnDrop, Clone)]
33pub struct Aes256CbcKey {
34 pub(crate) enc_key: Pin<Box<GenericArray<u8, U32>>>,
36}
37
38impl ConstantTimeEq for Aes256CbcKey {
39 fn ct_eq(&self, other: &Self) -> Choice {
40 self.enc_key.ct_eq(&other.enc_key)
41 }
42}
43
44impl PartialEq for Aes256CbcKey {
45 fn eq(&self, other: &Self) -> bool {
46 self.ct_eq(other).into()
47 }
48}
49
50#[derive(ZeroizeOnDrop, Clone)]
53pub struct Aes256CbcHmacKey {
54 pub(crate) enc_key: Pin<Box<GenericArray<u8, U32>>>,
56 pub(crate) mac_key: Pin<Box<GenericArray<u8, U32>>>,
58}
59
60impl ConstantTimeEq for Aes256CbcHmacKey {
61 fn ct_eq(&self, other: &Self) -> Choice {
62 self.enc_key.ct_eq(&other.enc_key) & self.mac_key.ct_eq(&other.mac_key)
63 }
64}
65
66impl PartialEq for Aes256CbcHmacKey {
67 fn eq(&self, other: &Self) -> bool {
68 self.ct_eq(other).into()
69 }
70}
71
72#[derive(Zeroize, Clone)]
77pub struct XChaCha20Poly1305Key {
78 pub(crate) key_id: KeyId,
79 pub(crate) enc_key: Pin<Box<GenericArray<u8, U32>>>,
80 #[zeroize(skip)]
85 pub(crate) supported_operations: Vec<KeyOperation>,
86}
87
88impl XChaCha20Poly1305Key {
89 pub fn make() -> Self {
91 let mut rng = rand::thread_rng();
92 let mut enc_key = Box::pin(GenericArray::<u8, U32>::default());
93 rng.fill(enc_key.as_mut_slice());
94 let key_id = KeyId::make();
95
96 Self {
97 enc_key,
98 key_id,
99 supported_operations: vec![
100 KeyOperation::Decrypt,
101 KeyOperation::Encrypt,
102 KeyOperation::WrapKey,
103 KeyOperation::UnwrapKey,
104 ],
105 }
106 }
107
108 pub(crate) fn disable_key_operation(&mut self, op: KeyOperation) -> &mut Self {
109 self.supported_operations.retain(|k| *k != op);
110 self
111 }
112}
113
114impl ConstantTimeEq for XChaCha20Poly1305Key {
115 fn ct_eq(&self, other: &Self) -> Choice {
116 self.enc_key.ct_eq(&other.enc_key) & self.key_id.ct_eq(&other.key_id)
117 }
118}
119
120impl PartialEq for XChaCha20Poly1305Key {
121 fn eq(&self, other: &Self) -> bool {
122 self.ct_eq(other).into()
123 }
124}
125
126#[derive(ZeroizeOnDrop, Clone)]
128pub enum SymmetricCryptoKey {
129 #[allow(missing_docs)]
130 Aes256CbcKey(Aes256CbcKey),
131 #[allow(missing_docs)]
132 Aes256CbcHmacKey(Aes256CbcHmacKey),
133 XChaCha20Poly1305Key(XChaCha20Poly1305Key),
136}
137
138impl SymmetricCryptoKey {
139 const AES256_CBC_KEY_LEN: usize = 32;
141 const AES256_CBC_HMAC_KEY_LEN: usize = 64;
143
144 pub(crate) fn make_aes256_cbc_hmac_key_internal(
150 mut rng: impl rand::RngCore + rand::CryptoRng,
151 ) -> Self {
152 let mut enc_key = Box::pin(GenericArray::<u8, U32>::default());
153 let mut mac_key = Box::pin(GenericArray::<u8, U32>::default());
154
155 rng.fill(enc_key.as_mut_slice());
156 rng.fill(mac_key.as_mut_slice());
157
158 Self::Aes256CbcHmacKey(Aes256CbcHmacKey { enc_key, mac_key })
159 }
160
161 pub fn make(algorithm: SymmetricKeyAlgorithm) -> Self {
163 match algorithm {
164 SymmetricKeyAlgorithm::Aes256CbcHmac => Self::make_aes256_cbc_hmac_key(),
165 SymmetricKeyAlgorithm::XChaCha20Poly1305 => Self::make_xchacha20_poly1305_key(),
166 }
167 }
168
169 pub fn make_aes256_cbc_hmac_key() -> Self {
171 let rng = rand::thread_rng();
172 Self::make_aes256_cbc_hmac_key_internal(rng)
173 }
174
175 pub fn make_xchacha20_poly1305_key() -> Self {
177 let mut rng = rand::thread_rng();
178 let mut enc_key = Box::pin(GenericArray::<u8, U32>::default());
179 rng.fill(enc_key.as_mut_slice());
180 Self::XChaCha20Poly1305Key(XChaCha20Poly1305Key {
181 enc_key,
182 key_id: KeyId::make(),
183 supported_operations: vec![
184 KeyOperation::Decrypt,
185 KeyOperation::Encrypt,
186 KeyOperation::WrapKey,
187 KeyOperation::UnwrapKey,
188 ],
189 })
190 }
191
192 pub fn to_encoded(&self) -> BitwardenLegacyKeyBytes {
201 let encoded_key = self.to_encoded_raw();
202 match encoded_key {
203 EncodedSymmetricKey::BitwardenLegacyKey(_) => {
204 let encoded_key: Vec<u8> = encoded_key.into();
205 BitwardenLegacyKeyBytes::from(encoded_key)
206 }
207 EncodedSymmetricKey::CoseKey(_) => {
208 let mut encoded_key: Vec<u8> = encoded_key.into();
209 pad_key(&mut encoded_key, (Self::AES256_CBC_HMAC_KEY_LEN + 1) as u8); BitwardenLegacyKeyBytes::from(encoded_key)
211 }
212 }
213 }
214
215 #[cfg(test)]
218 pub fn generate_seeded_for_unit_tests(seed: &str) -> Self {
219 let mut seeded_rng = ChaChaRng::from_seed(sha2::Sha256::digest(seed.as_bytes()).into());
221 let mut enc_key = Box::pin(GenericArray::<u8, U32>::default());
222 let mut mac_key = Box::pin(GenericArray::<u8, U32>::default());
223
224 seeded_rng.fill(enc_key.as_mut_slice());
225 seeded_rng.fill(mac_key.as_mut_slice());
226
227 SymmetricCryptoKey::Aes256CbcHmacKey(Aes256CbcHmacKey { enc_key, mac_key })
228 }
229
230 pub(crate) fn to_encoded_raw(&self) -> EncodedSymmetricKey {
242 match self {
243 Self::Aes256CbcKey(key) => {
244 EncodedSymmetricKey::BitwardenLegacyKey(key.enc_key.to_vec().into())
245 }
246 Self::Aes256CbcHmacKey(key) => {
247 let mut buf = Vec::with_capacity(64);
248 buf.extend_from_slice(&key.enc_key);
249 buf.extend_from_slice(&key.mac_key);
250 EncodedSymmetricKey::BitwardenLegacyKey(buf.into())
251 }
252 Self::XChaCha20Poly1305Key(key) => {
253 let builder = coset::CoseKeyBuilder::new_symmetric_key(key.enc_key.to_vec());
254 let mut cose_key = builder.key_id((&key.key_id).into());
255 for op in &key.supported_operations {
256 cose_key = cose_key.add_key_op(*op);
257 }
258 let mut cose_key = cose_key.build();
259 cose_key.alg = Some(RegisteredLabelWithPrivate::PrivateUse(
260 cose::XCHACHA20_POLY1305,
261 ));
262 EncodedSymmetricKey::CoseKey(
263 cose_key
264 .to_vec()
265 .expect("cose key serialization should not fail")
266 .into(),
267 )
268 }
269 }
270 }
271
272 pub(crate) fn try_from_cose(serialized_key: &[u8]) -> Result<Self, CryptoError> {
273 let cose_key =
274 coset::CoseKey::from_slice(serialized_key).map_err(|_| CryptoError::InvalidKey)?;
275 let key = SymmetricCryptoKey::try_from(&cose_key)?;
276 Ok(key)
277 }
278
279 #[allow(missing_docs)]
280 pub fn to_base64(&self) -> B64 {
281 B64::from(self.to_encoded().as_ref())
282 }
283
284 pub(crate) fn key_id(&self) -> Option<KeyId> {
287 match self {
288 Self::Aes256CbcKey(_) => None,
289 Self::Aes256CbcHmacKey(_) => None,
290 Self::XChaCha20Poly1305Key(key) => Some(key.key_id.clone()),
291 }
292 }
293}
294
295impl ConstantTimeEq for SymmetricCryptoKey {
296 fn ct_eq(&self, other: &SymmetricCryptoKey) -> Choice {
300 use SymmetricCryptoKey::*;
301 match (self, other) {
302 (Aes256CbcKey(a), Aes256CbcKey(b)) => a.ct_eq(b),
303 (Aes256CbcKey(_), _) => Choice::from(0),
304
305 (Aes256CbcHmacKey(a), Aes256CbcHmacKey(b)) => a.ct_eq(b),
306 (Aes256CbcHmacKey(_), _) => Choice::from(0),
307
308 (XChaCha20Poly1305Key(a), XChaCha20Poly1305Key(b)) => a.ct_eq(b),
309 (XChaCha20Poly1305Key(_), _) => Choice::from(0),
310 }
311 }
312}
313
314impl PartialEq for SymmetricCryptoKey {
315 fn eq(&self, other: &Self) -> bool {
316 self.ct_eq(other).into()
317 }
318}
319
320impl TryFrom<String> for SymmetricCryptoKey {
321 type Error = CryptoError;
322
323 fn try_from(value: String) -> Result<Self, Self::Error> {
324 let bytes = B64::try_from(value).map_err(|_| CryptoError::InvalidKey)?;
325 Self::try_from(bytes)
326 }
327}
328
329impl TryFrom<B64> for SymmetricCryptoKey {
330 type Error = CryptoError;
331
332 fn try_from(value: B64) -> Result<Self, Self::Error> {
333 Self::try_from(&BitwardenLegacyKeyBytes::from(&value))
334 }
335}
336
337impl TryFrom<&BitwardenLegacyKeyBytes> for SymmetricCryptoKey {
338 type Error = CryptoError;
339
340 fn try_from(value: &BitwardenLegacyKeyBytes) -> Result<Self, Self::Error> {
341 let slice = value.as_ref();
342
343 if slice.len() == Self::AES256_CBC_HMAC_KEY_LEN || slice.len() == Self::AES256_CBC_KEY_LEN {
349 Self::try_from(EncodedSymmetricKey::BitwardenLegacyKey(value.clone()))
350 } else if slice.len() > Self::AES256_CBC_HMAC_KEY_LEN {
351 let unpadded_value = unpad_key(slice)?;
352 Ok(Self::try_from_cose(unpadded_value)?)
353 } else {
354 Err(CryptoError::InvalidKeyLen)
355 }
356 }
357}
358
359impl TryFrom<EncodedSymmetricKey> for SymmetricCryptoKey {
360 type Error = CryptoError;
361
362 fn try_from(value: EncodedSymmetricKey) -> Result<Self, Self::Error> {
363 match value {
364 EncodedSymmetricKey::BitwardenLegacyKey(key)
365 if key.as_ref().len() == Self::AES256_CBC_KEY_LEN =>
366 {
367 let mut enc_key = Box::pin(GenericArray::<u8, U32>::default());
368 enc_key.copy_from_slice(&key.as_ref()[..Self::AES256_CBC_KEY_LEN]);
369 Ok(Self::Aes256CbcKey(Aes256CbcKey { enc_key }))
370 }
371 EncodedSymmetricKey::BitwardenLegacyKey(key)
372 if key.as_ref().len() == Self::AES256_CBC_HMAC_KEY_LEN =>
373 {
374 let mut enc_key = Box::pin(GenericArray::<u8, U32>::default());
375 enc_key.copy_from_slice(&key.as_ref()[..32]);
376
377 let mut mac_key = Box::pin(GenericArray::<u8, U32>::default());
378 mac_key.copy_from_slice(&key.as_ref()[32..]);
379
380 Ok(Self::Aes256CbcHmacKey(Aes256CbcHmacKey {
381 enc_key,
382 mac_key,
383 }))
384 }
385 EncodedSymmetricKey::CoseKey(key) => Self::try_from_cose(key.as_ref()),
386 _ => Err(CryptoError::InvalidKey),
387 }
388 }
389}
390
391impl CryptoKey for SymmetricCryptoKey {}
392
393impl std::fmt::Debug for SymmetricCryptoKey {
395 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
396 match self {
397 SymmetricCryptoKey::Aes256CbcKey(key) => key.fmt(f),
398 SymmetricCryptoKey::Aes256CbcHmacKey(key) => key.fmt(f),
399 SymmetricCryptoKey::XChaCha20Poly1305Key(key) => key.fmt(f),
400 }
401 }
402}
403
404impl std::fmt::Debug for Aes256CbcKey {
405 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
406 let mut debug_struct = f.debug_struct("SymmetricKey::Aes256Cbc");
407 #[cfg(feature = "dangerous-crypto-debug")]
408 debug_struct.field("key", &hex::encode(self.enc_key.as_slice()));
409 debug_struct.finish()
410 }
411}
412
413impl std::fmt::Debug for Aes256CbcHmacKey {
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415 let mut debug_struct = f.debug_struct("SymmetricKey::Aes256CbcHmac");
416 #[cfg(feature = "dangerous-crypto-debug")]
417 debug_struct
418 .field("enc_key", &hex::encode(self.enc_key.as_slice()))
419 .field("mac_key", &hex::encode(self.mac_key.as_slice()));
420 debug_struct.finish()
421 }
422}
423
424impl std::fmt::Debug for XChaCha20Poly1305Key {
425 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
426 let mut debug_struct = f.debug_struct("SymmetricKey::XChaCha20Poly1305");
427 debug_struct.field("key_id", &self.key_id);
428 debug_struct.field(
429 "supported_operations",
430 &self
431 .supported_operations
432 .iter()
433 .map(|key_operation: &KeyOperation| cose::debug_key_operation(*key_operation))
434 .collect::<Vec<_>>(),
435 );
436 #[cfg(feature = "dangerous-crypto-debug")]
437 debug_struct.field("key", &hex::encode(self.enc_key.as_slice()));
438 debug_struct.finish()
439 }
440}
441
442fn pad_key(key_bytes: &mut Vec<u8>, min_length: u8) {
453 crate::keys::utils::pad_bytes(key_bytes, min_length as usize)
454 .expect("Padding cannot fail since the min_length is < 255")
455}
456
457fn unpad_key(key_bytes: &[u8]) -> Result<&[u8], CryptoError> {
468 crate::keys::utils::unpad_bytes(key_bytes).map_err(|_| CryptoError::InvalidKey)
469}
470
471pub enum EncodedSymmetricKey {
473 BitwardenLegacyKey(BitwardenLegacyKeyBytes),
475 CoseKey(CoseKeyBytes),
477}
478impl From<EncodedSymmetricKey> for Vec<u8> {
479 fn from(val: EncodedSymmetricKey) -> Self {
480 match val {
481 EncodedSymmetricKey::BitwardenLegacyKey(key) => key.to_vec(),
482 EncodedSymmetricKey::CoseKey(key) => key.to_vec(),
483 }
484 }
485}
486impl EncodedSymmetricKey {
487 #[allow(private_interfaces)]
489 pub fn content_format(&self) -> ContentFormat {
490 match self {
491 EncodedSymmetricKey::BitwardenLegacyKey(_) => ContentFormat::BitwardenLegacyKey,
492 EncodedSymmetricKey::CoseKey(_) => ContentFormat::CoseKey,
493 }
494 }
495}
496
497#[cfg(test)]
499pub fn derive_symmetric_key(name: &str) -> Aes256CbcHmacKey {
500 use zeroize::Zeroizing;
501
502 use crate::{derive_shareable_key, generate_random_bytes};
503
504 let secret: Zeroizing<[u8; 16]> = generate_random_bytes();
505 derive_shareable_key(secret, name, None)
506}
507
508#[cfg(test)]
509mod tests {
510 use bitwarden_encoding::B64;
511 use coset::iana::KeyOperation;
512 use generic_array::GenericArray;
513 use typenum::U32;
514
515 use super::{SymmetricCryptoKey, derive_symmetric_key};
516 use crate::{
517 Aes256CbcHmacKey, Aes256CbcKey, BitwardenLegacyKeyBytes, XChaCha20Poly1305Key,
518 keys::{
519 KeyId,
520 symmetric_crypto_key::{pad_key, unpad_key},
521 },
522 };
523
524 #[test]
525 #[ignore = "Manual test to verify debug format"]
526 fn test_key_debug() {
527 let aes_key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
528 println!("{:?}", aes_key);
529 let xchacha_key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
530 println!("{:?}", xchacha_key);
531 }
532
533 #[test]
534 fn test_symmetric_crypto_key() {
535 let key = SymmetricCryptoKey::Aes256CbcHmacKey(derive_symmetric_key("test"));
536 let key2 = SymmetricCryptoKey::try_from(key.to_base64()).unwrap();
537
538 assert_eq!(key, key2);
539
540 let key = "UY4B5N4DA4UisCNClgZtRr6VLy9ZF5BXXC7cDZRqourKi4ghEMgISbCsubvgCkHf5DZctQjVot11/vVvN9NNHQ==".to_string();
541 let key2 = SymmetricCryptoKey::try_from(key.clone()).unwrap();
542 assert_eq!(key, key2.to_base64().to_string());
543 }
544
545 #[test]
546 fn test_encode_decode_old_symmetric_crypto_key() {
547 let key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
548 let encoded = key.to_encoded();
549 let decoded = SymmetricCryptoKey::try_from(&encoded).unwrap();
550 assert_eq!(key, decoded);
551 }
552
553 #[test]
554 fn test_decode_new_symmetric_crypto_key() {
555 let key: B64 = ("pQEEAlDib+JxbqMBlcd3KTUesbufAzoAARFvBIQDBAUGIFggt79surJXmqhPhYuuqi9ZyPfieebmtw2OsmN5SDrb4yUB").parse()
556 .unwrap();
557 let key = BitwardenLegacyKeyBytes::from(&key);
558 let key = SymmetricCryptoKey::try_from(&key).unwrap();
559 match key {
560 SymmetricCryptoKey::XChaCha20Poly1305Key(_) => (),
561 _ => panic!("Invalid key type"),
562 }
563 }
564
565 #[test]
566 fn test_encode_xchacha20_poly1305_key() {
567 let key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
568 let encoded = key.to_encoded();
569 let decoded = SymmetricCryptoKey::try_from(&encoded).unwrap();
570 assert_eq!(key, decoded);
571 }
572
573 #[test]
574 fn test_pad_unpad_key_63() {
575 let original_key = vec![1u8; 63];
576 let mut key_bytes = original_key.clone();
577 let mut encoded_bytes = vec![1u8; 65];
578 encoded_bytes[63] = 2;
579 encoded_bytes[64] = 2;
580 pad_key(&mut key_bytes, 65);
581 assert_eq!(encoded_bytes, key_bytes);
582 let unpadded_key = unpad_key(&key_bytes).unwrap();
583 assert_eq!(original_key, unpadded_key);
584 }
585
586 #[test]
587 fn test_pad_unpad_key_64() {
588 let original_key = vec![1u8; 64];
589 let mut key_bytes = original_key.clone();
590 let mut encoded_bytes = vec![1u8; 65];
591 encoded_bytes[64] = 1;
592 pad_key(&mut key_bytes, 65);
593 assert_eq!(encoded_bytes, key_bytes);
594 let unpadded_key = unpad_key(&key_bytes).unwrap();
595 assert_eq!(original_key, unpadded_key);
596 }
597
598 #[test]
599 fn test_pad_unpad_key_65() {
600 let original_key = vec![1u8; 65];
601 let mut key_bytes = original_key.clone();
602 let mut encoded_bytes = vec![1u8; 66];
603 encoded_bytes[65] = 1;
604 pad_key(&mut key_bytes, 65);
605 assert_eq!(encoded_bytes, key_bytes);
606 let unpadded_key = unpad_key(&key_bytes).unwrap();
607 assert_eq!(original_key, unpadded_key);
608 }
609
610 #[test]
611 fn test_eq_aes_cbc_hmac() {
612 let key1 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
613 let key2 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
614 assert_ne!(key1, key2);
615 let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
616 assert_eq!(key1, key3);
617 }
618
619 #[test]
620 fn test_eq_aes_cbc() {
621 let key1 =
622 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(vec![1u8; 32])).unwrap();
623 let key2 =
624 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(vec![2u8; 32])).unwrap();
625 assert_ne!(key1, key2);
626 let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
627 assert_eq!(key1, key3);
628 }
629
630 #[test]
631 fn test_eq_xchacha20_poly1305() {
632 let key1 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
633 let key2 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
634 assert_ne!(key1, key2);
635 let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
636 assert_eq!(key1, key3);
637 }
638
639 #[test]
640 fn test_neq_different_key_types() {
641 let key1 = SymmetricCryptoKey::Aes256CbcKey(Aes256CbcKey {
642 enc_key: Box::pin(GenericArray::<u8, U32>::default()),
643 });
644 let key2 = SymmetricCryptoKey::XChaCha20Poly1305Key(XChaCha20Poly1305Key {
645 enc_key: Box::pin(GenericArray::<u8, U32>::default()),
646 key_id: KeyId::from([0; 16]),
647 supported_operations: vec![
648 KeyOperation::Decrypt,
649 KeyOperation::Encrypt,
650 KeyOperation::WrapKey,
651 KeyOperation::UnwrapKey,
652 ],
653 });
654 assert_ne!(key1, key2);
655 }
656
657 #[test]
658 fn test_eq_variant_aes256_cbc() {
659 let key1 = Aes256CbcKey {
660 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
661 vec![1u8; 32].as_slice(),
662 )),
663 };
664 let key2 = Aes256CbcKey {
665 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
666 vec![1u8; 32].as_slice(),
667 )),
668 };
669 let key3 = Aes256CbcKey {
670 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
671 vec![2u8; 32].as_slice(),
672 )),
673 };
674 assert_eq!(key1, key2);
675 assert_ne!(key1, key3);
676 }
677
678 #[test]
679 fn test_eq_variant_aes256_cbc_hmac() {
680 let key1 = Aes256CbcHmacKey {
681 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
682 vec![1u8; 32].as_slice(),
683 )),
684 mac_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
685 vec![2u8; 32].as_slice(),
686 )),
687 };
688 let key2 = Aes256CbcHmacKey {
689 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
690 vec![1u8; 32].as_slice(),
691 )),
692 mac_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
693 vec![2u8; 32].as_slice(),
694 )),
695 };
696 let key3 = Aes256CbcHmacKey {
697 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
698 vec![3u8; 32].as_slice(),
699 )),
700 mac_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
701 vec![4u8; 32].as_slice(),
702 )),
703 };
704 assert_eq!(key1, key2);
705 assert_ne!(key1, key3);
706 }
707
708 #[test]
709 fn test_eq_variant_xchacha20_poly1305() {
710 let key1 = XChaCha20Poly1305Key {
711 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
712 vec![1u8; 32].as_slice(),
713 )),
714 key_id: KeyId::from([0; 16]),
715 supported_operations: vec![
716 KeyOperation::Decrypt,
717 KeyOperation::Encrypt,
718 KeyOperation::WrapKey,
719 KeyOperation::UnwrapKey,
720 ],
721 };
722 let key2 = XChaCha20Poly1305Key {
723 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
724 vec![1u8; 32].as_slice(),
725 )),
726 key_id: KeyId::from([0; 16]),
727 supported_operations: vec![
728 KeyOperation::Decrypt,
729 KeyOperation::Encrypt,
730 KeyOperation::WrapKey,
731 KeyOperation::UnwrapKey,
732 ],
733 };
734 let key3 = XChaCha20Poly1305Key {
735 enc_key: Box::pin(GenericArray::<u8, U32>::clone_from_slice(
736 vec![2u8; 32].as_slice(),
737 )),
738 key_id: KeyId::from([1; 16]),
739 supported_operations: vec![
740 KeyOperation::Decrypt,
741 KeyOperation::Encrypt,
742 KeyOperation::WrapKey,
743 KeyOperation::UnwrapKey,
744 ],
745 };
746 assert_eq!(key1, key2);
747 assert_ne!(key1, key3);
748 }
749
750 #[test]
751 fn test_neq_different_key_id() {
752 let key1 = XChaCha20Poly1305Key {
753 enc_key: Box::pin(GenericArray::<u8, U32>::default()),
754 key_id: KeyId::from([0; 16]),
755 supported_operations: vec![
756 KeyOperation::Decrypt,
757 KeyOperation::Encrypt,
758 KeyOperation::WrapKey,
759 KeyOperation::UnwrapKey,
760 ],
761 };
762 let key2 = XChaCha20Poly1305Key {
763 enc_key: Box::pin(GenericArray::<u8, U32>::default()),
764 key_id: KeyId::from([1; 16]),
765 supported_operations: vec![
766 KeyOperation::Decrypt,
767 KeyOperation::Encrypt,
768 KeyOperation::WrapKey,
769 KeyOperation::UnwrapKey,
770 ],
771 };
772 assert_ne!(key1, key2);
773
774 let key1 = SymmetricCryptoKey::XChaCha20Poly1305Key(key1);
775 let key2 = SymmetricCryptoKey::XChaCha20Poly1305Key(key2);
776 assert_ne!(key1, key2);
777 }
778}