1use std::pin::Pin;
2
3use bitwarden_encoding::B64;
4use coset::{CborSerializable, RegisteredLabelWithPrivate, iana::KeyOperation};
5use hybrid_array::Array;
6use rand::RngExt;
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<Array<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<Array<u8, U32>>>,
56 pub(crate) mac_key: Pin<Box<Array<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<Array<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::rng();
92 let mut enc_key = Box::pin(Array::<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(mut rng: impl rand::CryptoRng) -> Self {
150 let mut enc_key = Box::pin(Array::<u8, U32>::default());
151 let mut mac_key = Box::pin(Array::<u8, U32>::default());
152
153 rng.fill(enc_key.as_mut_slice());
154 rng.fill(mac_key.as_mut_slice());
155
156 Self::Aes256CbcHmacKey(Aes256CbcHmacKey { enc_key, mac_key })
157 }
158
159 pub fn make(algorithm: SymmetricKeyAlgorithm) -> Self {
161 match algorithm {
162 SymmetricKeyAlgorithm::Aes256CbcHmac => Self::make_aes256_cbc_hmac_key(),
163 SymmetricKeyAlgorithm::XChaCha20Poly1305 => Self::make_xchacha20_poly1305_key(),
164 }
165 }
166
167 pub fn make_aes256_cbc_hmac_key() -> Self {
169 let rng = rand::rng();
170 Self::make_aes256_cbc_hmac_key_internal(rng)
171 }
172
173 pub fn make_xchacha20_poly1305_key() -> Self {
175 let mut rng = rand::rng();
176 let mut enc_key = Box::pin(Array::<u8, U32>::default());
177 rng.fill(enc_key.as_mut_slice());
178 Self::XChaCha20Poly1305Key(XChaCha20Poly1305Key {
179 enc_key,
180 key_id: KeyId::make(),
181 supported_operations: vec![
182 KeyOperation::Decrypt,
183 KeyOperation::Encrypt,
184 KeyOperation::WrapKey,
185 KeyOperation::UnwrapKey,
186 ],
187 })
188 }
189
190 pub fn to_encoded(&self) -> BitwardenLegacyKeyBytes {
199 let encoded_key = self.to_encoded_raw();
200 match encoded_key {
201 EncodedSymmetricKey::BitwardenLegacyKey(_) => {
202 let encoded_key: Vec<u8> = encoded_key.into();
203 BitwardenLegacyKeyBytes::from(encoded_key)
204 }
205 EncodedSymmetricKey::CoseKey(_) => {
206 let mut encoded_key: Vec<u8> = encoded_key.into();
207 pad_key(&mut encoded_key, (Self::AES256_CBC_HMAC_KEY_LEN + 1) as u8); BitwardenLegacyKeyBytes::from(encoded_key)
209 }
210 }
211 }
212
213 #[cfg(test)]
216 pub fn generate_seeded_for_unit_tests(seed: &str) -> Self {
217 let mut seeded_rng = ChaChaRng::from_seed(sha2::Sha256::digest(seed.as_bytes()).into());
219 let mut enc_key = Box::pin(Array::<u8, U32>::default());
220 let mut mac_key = Box::pin(Array::<u8, U32>::default());
221
222 seeded_rng.fill(enc_key.as_mut_slice());
223 seeded_rng.fill(mac_key.as_mut_slice());
224
225 SymmetricCryptoKey::Aes256CbcHmacKey(Aes256CbcHmacKey { enc_key, mac_key })
226 }
227
228 pub(crate) fn to_encoded_raw(&self) -> EncodedSymmetricKey {
240 match self {
241 Self::Aes256CbcKey(key) => {
242 EncodedSymmetricKey::BitwardenLegacyKey(key.enc_key.to_vec().into())
243 }
244 Self::Aes256CbcHmacKey(key) => {
245 let mut buf = Vec::with_capacity(64);
246 buf.extend_from_slice(&key.enc_key);
247 buf.extend_from_slice(&key.mac_key);
248 EncodedSymmetricKey::BitwardenLegacyKey(buf.into())
249 }
250 Self::XChaCha20Poly1305Key(key) => {
251 let builder = coset::CoseKeyBuilder::new_symmetric_key(key.enc_key.to_vec());
252 let mut cose_key = builder.key_id((&key.key_id).into());
253 for op in &key.supported_operations {
254 cose_key = cose_key.add_key_op(*op);
255 }
256 let mut cose_key = cose_key.build();
257 cose_key.alg = Some(RegisteredLabelWithPrivate::PrivateUse(
258 cose::XCHACHA20_POLY1305,
259 ));
260 EncodedSymmetricKey::CoseKey(
261 cose_key
262 .to_vec()
263 .expect("cose key serialization should not fail")
264 .into(),
265 )
266 }
267 }
268 }
269
270 pub(crate) fn try_from_cose(serialized_key: &[u8]) -> Result<Self, CryptoError> {
271 let cose_key =
272 coset::CoseKey::from_slice(serialized_key).map_err(|_| CryptoError::InvalidKey)?;
273 let key = SymmetricCryptoKey::try_from(&cose_key)?;
274 Ok(key)
275 }
276
277 #[allow(missing_docs)]
278 pub fn to_base64(&self) -> B64 {
279 B64::from(self.to_encoded().as_ref())
280 }
281
282 pub fn key_id(&self) -> Option<KeyId> {
285 match self {
286 Self::Aes256CbcKey(_) => None,
287 Self::Aes256CbcHmacKey(_) => None,
288 Self::XChaCha20Poly1305Key(key) => Some(key.key_id.clone()),
289 }
290 }
291}
292
293impl ConstantTimeEq for SymmetricCryptoKey {
294 fn ct_eq(&self, other: &SymmetricCryptoKey) -> Choice {
298 use SymmetricCryptoKey::*;
299 match (self, other) {
300 (Aes256CbcKey(a), Aes256CbcKey(b)) => a.ct_eq(b),
301 (Aes256CbcKey(_), _) => Choice::from(0),
302
303 (Aes256CbcHmacKey(a), Aes256CbcHmacKey(b)) => a.ct_eq(b),
304 (Aes256CbcHmacKey(_), _) => Choice::from(0),
305
306 (XChaCha20Poly1305Key(a), XChaCha20Poly1305Key(b)) => a.ct_eq(b),
307 (XChaCha20Poly1305Key(_), _) => Choice::from(0),
308 }
309 }
310}
311
312impl PartialEq for SymmetricCryptoKey {
313 fn eq(&self, other: &Self) -> bool {
314 self.ct_eq(other).into()
315 }
316}
317
318impl TryFrom<String> for SymmetricCryptoKey {
319 type Error = CryptoError;
320
321 fn try_from(value: String) -> Result<Self, Self::Error> {
322 let bytes = B64::try_from(value).map_err(|_| CryptoError::InvalidKey)?;
323 Self::try_from(bytes)
324 }
325}
326
327impl TryFrom<B64> for SymmetricCryptoKey {
328 type Error = CryptoError;
329
330 fn try_from(value: B64) -> Result<Self, Self::Error> {
331 Self::try_from(&BitwardenLegacyKeyBytes::from(&value))
332 }
333}
334
335impl TryFrom<&BitwardenLegacyKeyBytes> for SymmetricCryptoKey {
336 type Error = CryptoError;
337
338 fn try_from(value: &BitwardenLegacyKeyBytes) -> Result<Self, Self::Error> {
339 let slice = value.as_ref();
340
341 if slice.len() == Self::AES256_CBC_HMAC_KEY_LEN || slice.len() == Self::AES256_CBC_KEY_LEN {
347 Self::try_from(EncodedSymmetricKey::BitwardenLegacyKey(value.clone()))
348 } else if slice.len() > Self::AES256_CBC_HMAC_KEY_LEN {
349 let unpadded_value = unpad_key(slice)?;
350 Ok(Self::try_from_cose(unpadded_value)?)
351 } else {
352 Err(CryptoError::InvalidKeyLen)
353 }
354 }
355}
356
357impl TryFrom<EncodedSymmetricKey> for SymmetricCryptoKey {
358 type Error = CryptoError;
359
360 fn try_from(value: EncodedSymmetricKey) -> Result<Self, Self::Error> {
361 match value {
362 EncodedSymmetricKey::BitwardenLegacyKey(key)
363 if key.as_ref().len() == Self::AES256_CBC_KEY_LEN =>
364 {
365 let mut enc_key = Box::pin(Array::<u8, U32>::default());
366 enc_key.copy_from_slice(&key.as_ref()[..Self::AES256_CBC_KEY_LEN]);
367 Ok(Self::Aes256CbcKey(Aes256CbcKey { enc_key }))
368 }
369 EncodedSymmetricKey::BitwardenLegacyKey(key)
370 if key.as_ref().len() == Self::AES256_CBC_HMAC_KEY_LEN =>
371 {
372 let mut enc_key = Box::pin(Array::<u8, U32>::default());
373 enc_key.copy_from_slice(&key.as_ref()[..32]);
374
375 let mut mac_key = Box::pin(Array::<u8, U32>::default());
376 mac_key.copy_from_slice(&key.as_ref()[32..]);
377
378 Ok(Self::Aes256CbcHmacKey(Aes256CbcHmacKey {
379 enc_key,
380 mac_key,
381 }))
382 }
383 EncodedSymmetricKey::CoseKey(key) => Self::try_from_cose(key.as_ref()),
384 _ => Err(CryptoError::InvalidKey),
385 }
386 }
387}
388
389impl CryptoKey for SymmetricCryptoKey {}
390
391impl std::fmt::Debug for SymmetricCryptoKey {
393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 match self {
395 SymmetricCryptoKey::Aes256CbcKey(key) => key.fmt(f),
396 SymmetricCryptoKey::Aes256CbcHmacKey(key) => key.fmt(f),
397 SymmetricCryptoKey::XChaCha20Poly1305Key(key) => key.fmt(f),
398 }
399 }
400}
401
402impl std::fmt::Debug for Aes256CbcKey {
403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404 let mut debug_struct = f.debug_struct("SymmetricKey::Aes256Cbc");
405 #[cfg(feature = "dangerous-crypto-debug")]
406 debug_struct.field("key", &hex::encode(self.enc_key.as_slice()));
407 debug_struct.finish()
408 }
409}
410
411impl std::fmt::Debug for Aes256CbcHmacKey {
412 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413 let mut debug_struct = f.debug_struct("SymmetricKey::Aes256CbcHmac");
414 #[cfg(feature = "dangerous-crypto-debug")]
415 debug_struct
416 .field("enc_key", &hex::encode(self.enc_key.as_slice()))
417 .field("mac_key", &hex::encode(self.mac_key.as_slice()));
418 debug_struct.finish()
419 }
420}
421
422impl std::fmt::Debug for XChaCha20Poly1305Key {
423 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
424 let mut debug_struct = f.debug_struct("SymmetricKey::XChaCha20Poly1305");
425 debug_struct.field("key_id", &self.key_id);
426 debug_struct.field(
427 "supported_operations",
428 &self
429 .supported_operations
430 .iter()
431 .map(|key_operation: &KeyOperation| cose::debug_key_operation(*key_operation))
432 .collect::<Vec<_>>(),
433 );
434 #[cfg(feature = "dangerous-crypto-debug")]
435 debug_struct.field("key", &hex::encode(self.enc_key.as_slice()));
436 debug_struct.finish()
437 }
438}
439
440fn pad_key(key_bytes: &mut Vec<u8>, min_length: u8) {
451 crate::keys::utils::pad_bytes(key_bytes, min_length as usize)
452 .expect("Padding cannot fail since the min_length is < 255")
453}
454
455fn unpad_key(key_bytes: &[u8]) -> Result<&[u8], CryptoError> {
466 crate::keys::utils::unpad_bytes(key_bytes).map_err(|_| CryptoError::InvalidKey)
467}
468
469pub enum EncodedSymmetricKey {
471 BitwardenLegacyKey(BitwardenLegacyKeyBytes),
473 CoseKey(CoseKeyBytes),
475}
476impl From<EncodedSymmetricKey> for Vec<u8> {
477 fn from(val: EncodedSymmetricKey) -> Self {
478 match val {
479 EncodedSymmetricKey::BitwardenLegacyKey(key) => key.to_vec(),
480 EncodedSymmetricKey::CoseKey(key) => key.to_vec(),
481 }
482 }
483}
484impl EncodedSymmetricKey {
485 #[allow(private_interfaces)]
487 pub fn content_format(&self) -> ContentFormat {
488 match self {
489 EncodedSymmetricKey::BitwardenLegacyKey(_) => ContentFormat::BitwardenLegacyKey,
490 EncodedSymmetricKey::CoseKey(_) => ContentFormat::CoseKey,
491 }
492 }
493}
494
495#[cfg(test)]
497pub fn derive_symmetric_key(name: &str) -> Aes256CbcHmacKey {
498 use zeroize::Zeroizing;
499
500 use crate::{derive_shareable_key, generate_random_bytes};
501
502 let secret: Zeroizing<[u8; 16]> = generate_random_bytes();
503 derive_shareable_key(secret, name, None)
504}
505
506#[cfg(test)]
507mod tests {
508 use bitwarden_encoding::B64;
509 use coset::iana::KeyOperation;
510 use hybrid_array::Array;
511 use typenum::U32;
512
513 use super::{SymmetricCryptoKey, derive_symmetric_key};
514 use crate::{
515 Aes256CbcHmacKey, Aes256CbcKey, BitwardenLegacyKeyBytes, XChaCha20Poly1305Key,
516 keys::{
517 KeyId,
518 symmetric_crypto_key::{pad_key, unpad_key},
519 },
520 };
521
522 #[test]
523 #[ignore = "Manual test to verify debug format"]
524 fn test_key_debug() {
525 let aes_key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
526 println!("{:?}", aes_key);
527 let xchacha_key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
528 println!("{:?}", xchacha_key);
529 }
530
531 #[test]
532 fn test_symmetric_crypto_key() {
533 let key = SymmetricCryptoKey::Aes256CbcHmacKey(derive_symmetric_key("test"));
534 let key2 = SymmetricCryptoKey::try_from(key.to_base64()).unwrap();
535
536 assert_eq!(key, key2);
537
538 let key = "UY4B5N4DA4UisCNClgZtRr6VLy9ZF5BXXC7cDZRqourKi4ghEMgISbCsubvgCkHf5DZctQjVot11/vVvN9NNHQ==".to_string();
539 let key2 = SymmetricCryptoKey::try_from(key.clone()).unwrap();
540 assert_eq!(key, key2.to_base64().to_string());
541 }
542
543 #[test]
544 fn test_encode_decode_old_symmetric_crypto_key() {
545 let key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
546 let encoded = key.to_encoded();
547 let decoded = SymmetricCryptoKey::try_from(&encoded).unwrap();
548 assert_eq!(key, decoded);
549 }
550
551 #[test]
552 fn test_decode_new_symmetric_crypto_key() {
553 let key: B64 = ("pQEEAlDib+JxbqMBlcd3KTUesbufAzoAARFvBIQDBAUGIFggt79surJXmqhPhYuuqi9ZyPfieebmtw2OsmN5SDrb4yUB").parse()
554 .unwrap();
555 let key = BitwardenLegacyKeyBytes::from(&key);
556 let key = SymmetricCryptoKey::try_from(&key).unwrap();
557 match key {
558 SymmetricCryptoKey::XChaCha20Poly1305Key(_) => (),
559 _ => panic!("Invalid key type"),
560 }
561 }
562
563 #[test]
564 fn test_encode_xchacha20_poly1305_key() {
565 let key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
566 let encoded = key.to_encoded();
567 let decoded = SymmetricCryptoKey::try_from(&encoded).unwrap();
568 assert_eq!(key, decoded);
569 }
570
571 #[test]
572 fn test_pad_unpad_key_63() {
573 let original_key = vec![1u8; 63];
574 let mut key_bytes = original_key.clone();
575 let mut encoded_bytes = vec![1u8; 65];
576 encoded_bytes[63] = 2;
577 encoded_bytes[64] = 2;
578 pad_key(&mut key_bytes, 65);
579 assert_eq!(encoded_bytes, key_bytes);
580 let unpadded_key = unpad_key(&key_bytes).unwrap();
581 assert_eq!(original_key, unpadded_key);
582 }
583
584 #[test]
585 fn test_pad_unpad_key_64() {
586 let original_key = vec![1u8; 64];
587 let mut key_bytes = original_key.clone();
588 let mut encoded_bytes = vec![1u8; 65];
589 encoded_bytes[64] = 1;
590 pad_key(&mut key_bytes, 65);
591 assert_eq!(encoded_bytes, key_bytes);
592 let unpadded_key = unpad_key(&key_bytes).unwrap();
593 assert_eq!(original_key, unpadded_key);
594 }
595
596 #[test]
597 fn test_pad_unpad_key_65() {
598 let original_key = vec![1u8; 65];
599 let mut key_bytes = original_key.clone();
600 let mut encoded_bytes = vec![1u8; 66];
601 encoded_bytes[65] = 1;
602 pad_key(&mut key_bytes, 65);
603 assert_eq!(encoded_bytes, key_bytes);
604 let unpadded_key = unpad_key(&key_bytes).unwrap();
605 assert_eq!(original_key, unpadded_key);
606 }
607
608 #[test]
609 fn test_eq_aes_cbc_hmac() {
610 let key1 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
611 let key2 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
612 assert_ne!(key1, key2);
613 let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
614 assert_eq!(key1, key3);
615 }
616
617 #[test]
618 fn test_eq_aes_cbc() {
619 let key1 =
620 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(vec![1u8; 32])).unwrap();
621 let key2 =
622 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(vec![2u8; 32])).unwrap();
623 assert_ne!(key1, key2);
624 let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
625 assert_eq!(key1, key3);
626 }
627
628 #[test]
629 fn test_eq_xchacha20_poly1305() {
630 let key1 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
631 let key2 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
632 assert_ne!(key1, key2);
633 let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
634 assert_eq!(key1, key3);
635 }
636
637 #[test]
638 fn test_neq_different_key_types() {
639 let key1 = SymmetricCryptoKey::Aes256CbcKey(Aes256CbcKey {
640 enc_key: Box::pin(Array::<u8, U32>::default()),
641 });
642 let key2 = SymmetricCryptoKey::XChaCha20Poly1305Key(XChaCha20Poly1305Key {
643 enc_key: Box::pin(Array::<u8, U32>::default()),
644 key_id: KeyId::from([0; 16]),
645 supported_operations: vec![
646 KeyOperation::Decrypt,
647 KeyOperation::Encrypt,
648 KeyOperation::WrapKey,
649 KeyOperation::UnwrapKey,
650 ],
651 });
652 assert_ne!(key1, key2);
653 }
654
655 #[test]
656 fn test_eq_variant_aes256_cbc() {
657 let key1 = Aes256CbcKey {
658 enc_key: Box::pin(Array::from([1u8; 32])),
659 };
660 let key2 = Aes256CbcKey {
661 enc_key: Box::pin(Array::from([1u8; 32])),
662 };
663 let key3 = Aes256CbcKey {
664 enc_key: Box::pin(Array::from([2u8; 32])),
665 };
666 assert_eq!(key1, key2);
667 assert_ne!(key1, key3);
668 }
669
670 #[test]
671 fn test_eq_variant_aes256_cbc_hmac() {
672 let key1 = Aes256CbcHmacKey {
673 enc_key: Box::pin(Array::from([1u8; 32])),
674 mac_key: Box::pin(Array::from([2u8; 32])),
675 };
676 let key2 = Aes256CbcHmacKey {
677 enc_key: Box::pin(Array::from([1u8; 32])),
678 mac_key: Box::pin(Array::from([2u8; 32])),
679 };
680 let key3 = Aes256CbcHmacKey {
681 enc_key: Box::pin(Array::from([3u8; 32])),
682 mac_key: Box::pin(Array::from([4u8; 32])),
683 };
684 assert_eq!(key1, key2);
685 assert_ne!(key1, key3);
686 }
687
688 #[test]
689 fn test_eq_variant_xchacha20_poly1305() {
690 let key1 = XChaCha20Poly1305Key {
691 enc_key: Box::pin(Array::from([1u8; 32])),
692 key_id: KeyId::from([0; 16]),
693 supported_operations: vec![
694 KeyOperation::Decrypt,
695 KeyOperation::Encrypt,
696 KeyOperation::WrapKey,
697 KeyOperation::UnwrapKey,
698 ],
699 };
700 let key2 = XChaCha20Poly1305Key {
701 enc_key: Box::pin(Array::from([1u8; 32])),
702 key_id: KeyId::from([0; 16]),
703 supported_operations: vec![
704 KeyOperation::Decrypt,
705 KeyOperation::Encrypt,
706 KeyOperation::WrapKey,
707 KeyOperation::UnwrapKey,
708 ],
709 };
710 let key3 = XChaCha20Poly1305Key {
711 enc_key: Box::pin(Array::from([2u8; 32])),
712 key_id: KeyId::from([1; 16]),
713 supported_operations: vec![
714 KeyOperation::Decrypt,
715 KeyOperation::Encrypt,
716 KeyOperation::WrapKey,
717 KeyOperation::UnwrapKey,
718 ],
719 };
720 assert_eq!(key1, key2);
721 assert_ne!(key1, key3);
722 }
723
724 #[test]
725 fn test_neq_different_key_id() {
726 let key1 = XChaCha20Poly1305Key {
727 enc_key: Box::pin(Array::<u8, U32>::default()),
728 key_id: KeyId::from([0; 16]),
729 supported_operations: vec![
730 KeyOperation::Decrypt,
731 KeyOperation::Encrypt,
732 KeyOperation::WrapKey,
733 KeyOperation::UnwrapKey,
734 ],
735 };
736 let key2 = XChaCha20Poly1305Key {
737 enc_key: Box::pin(Array::<u8, U32>::default()),
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_ne!(key1, key2);
747
748 let key1 = SymmetricCryptoKey::XChaCha20Poly1305Key(key1);
749 let key2 = SymmetricCryptoKey::XChaCha20Poly1305Key(key2);
750 assert_ne!(key1, key2);
751 }
752}