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