use std::pin::Pin;
use bitwarden_encoding::B64;
use coset::{CborSerializable, RegisteredLabelWithPrivate, iana::KeyOperation};
use hybrid_array::Array;
use rand::RngExt;
#[cfg(test)]
use rand::SeedableRng;
#[cfg(test)]
use rand_chacha::ChaChaRng;
use serde::{Deserialize, Serialize};
#[cfg(test)]
use sha2::Digest;
use subtle::{Choice, ConstantTimeEq};
use typenum::U32;
#[cfg(feature = "wasm")]
use wasm_bindgen::convert::{FromWasmAbi, IntoWasmAbi, OptionFromWasmAbi};
use zeroize::{Zeroize, ZeroizeOnDrop};
use super::{key_encryptable::CryptoKey, key_id::KeyId};
use crate::{BitwardenLegacyKeyBytes, ContentFormat, CoseKeyBytes, CryptoError, cose};
#[cfg(feature = "wasm")]
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
const TS_CUSTOM_TYPES: &'static str = r#"
export type SymmetricKey = Tagged<string, "SymmetricKey">;
"#;
#[cfg(feature = "wasm")]
impl wasm_bindgen::describe::WasmDescribe for SymmetricCryptoKey {
fn describe() {
<String as wasm_bindgen::describe::WasmDescribe>::describe();
}
}
#[cfg(feature = "wasm")]
impl FromWasmAbi for SymmetricCryptoKey {
type Abi = <String as FromWasmAbi>::Abi;
unsafe fn from_abi(abi: Self::Abi) -> Self {
use wasm_bindgen::UnwrapThrowExt;
let string = unsafe { String::from_abi(abi) };
let b64 = B64::try_from(string).unwrap_throw();
SymmetricCryptoKey::try_from(b64).unwrap_throw()
}
}
#[cfg(feature = "wasm")]
impl OptionFromWasmAbi for SymmetricCryptoKey {
fn is_none(abi: &Self::Abi) -> bool {
<String as OptionFromWasmAbi>::is_none(abi)
}
}
#[cfg(feature = "wasm")]
impl IntoWasmAbi for SymmetricCryptoKey {
type Abi = <String as IntoWasmAbi>::Abi;
fn into_abi(self) -> Self::Abi {
let string: String = self.to_base64().to_string();
string.into_abi()
}
}
#[derive(Debug, PartialEq)]
pub enum SymmetricKeyAlgorithm {
Aes256CbcHmac,
XChaCha20Poly1305,
}
#[derive(ZeroizeOnDrop, Clone)]
pub struct Aes256CbcKey {
pub(crate) enc_key: Pin<Box<Array<u8, U32>>>,
}
impl ConstantTimeEq for Aes256CbcKey {
fn ct_eq(&self, other: &Self) -> Choice {
self.enc_key.ct_eq(&other.enc_key)
}
}
impl PartialEq for Aes256CbcKey {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
#[derive(ZeroizeOnDrop, Clone)]
pub struct Aes256CbcHmacKey {
pub(crate) enc_key: Pin<Box<Array<u8, U32>>>,
pub(crate) mac_key: Pin<Box<Array<u8, U32>>>,
}
impl ConstantTimeEq for Aes256CbcHmacKey {
fn ct_eq(&self, other: &Self) -> Choice {
self.enc_key.ct_eq(&other.enc_key) & self.mac_key.ct_eq(&other.mac_key)
}
}
impl PartialEq for Aes256CbcHmacKey {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
#[derive(Zeroize, Clone)]
pub struct XChaCha20Poly1305Key {
pub(crate) key_id: KeyId,
pub(crate) enc_key: Pin<Box<Array<u8, U32>>>,
#[zeroize(skip)]
pub(crate) supported_operations: Vec<KeyOperation>,
}
impl XChaCha20Poly1305Key {
pub fn make() -> Self {
let mut rng = rand::rng();
let mut enc_key = Box::pin(Array::<u8, U32>::default());
rng.fill(enc_key.as_mut_slice());
let key_id = KeyId::make();
Self {
enc_key,
key_id,
supported_operations: vec![
KeyOperation::Decrypt,
KeyOperation::Encrypt,
KeyOperation::WrapKey,
KeyOperation::UnwrapKey,
],
}
}
pub(crate) fn disable_key_operation(&mut self, op: KeyOperation) -> &mut Self {
self.supported_operations.retain(|k| *k != op);
self
}
}
impl ConstantTimeEq for XChaCha20Poly1305Key {
fn ct_eq(&self, other: &Self) -> Choice {
self.enc_key.ct_eq(&other.enc_key) & self.key_id.ct_eq(&other.key_id)
}
}
impl PartialEq for XChaCha20Poly1305Key {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
#[derive(ZeroizeOnDrop, Clone)]
pub enum SymmetricCryptoKey {
#[allow(missing_docs)]
Aes256CbcKey(Aes256CbcKey),
#[allow(missing_docs)]
Aes256CbcHmacKey(Aes256CbcHmacKey),
XChaCha20Poly1305Key(XChaCha20Poly1305Key),
}
impl SymmetricCryptoKey {
const AES256_CBC_KEY_LEN: usize = 32;
const AES256_CBC_HMAC_KEY_LEN: usize = 64;
pub(crate) fn make_aes256_cbc_hmac_key_internal(mut rng: impl rand::CryptoRng) -> Self {
let mut enc_key = Box::pin(Array::<u8, U32>::default());
let mut mac_key = Box::pin(Array::<u8, U32>::default());
rng.fill(enc_key.as_mut_slice());
rng.fill(mac_key.as_mut_slice());
Self::Aes256CbcHmacKey(Aes256CbcHmacKey { enc_key, mac_key })
}
pub fn make(algorithm: SymmetricKeyAlgorithm) -> Self {
match algorithm {
SymmetricKeyAlgorithm::Aes256CbcHmac => Self::make_aes256_cbc_hmac_key(),
SymmetricKeyAlgorithm::XChaCha20Poly1305 => Self::make_xchacha20_poly1305_key(),
}
}
pub fn make_aes256_cbc_hmac_key() -> Self {
let rng = rand::rng();
Self::make_aes256_cbc_hmac_key_internal(rng)
}
pub fn make_xchacha20_poly1305_key() -> Self {
let mut rng = rand::rng();
let mut enc_key = Box::pin(Array::<u8, U32>::default());
rng.fill(enc_key.as_mut_slice());
Self::XChaCha20Poly1305Key(XChaCha20Poly1305Key {
enc_key,
key_id: KeyId::make(),
supported_operations: vec![
KeyOperation::Decrypt,
KeyOperation::Encrypt,
KeyOperation::WrapKey,
KeyOperation::UnwrapKey,
],
})
}
pub fn to_encoded(&self) -> BitwardenLegacyKeyBytes {
let encoded_key = self.to_encoded_raw();
match encoded_key {
EncodedSymmetricKey::BitwardenLegacyKey(_) => {
let encoded_key: Vec<u8> = encoded_key.into();
BitwardenLegacyKeyBytes::from(encoded_key)
}
EncodedSymmetricKey::CoseKey(_) => {
let mut encoded_key: Vec<u8> = encoded_key.into();
pad_key(&mut encoded_key, (Self::AES256_CBC_HMAC_KEY_LEN + 1) as u8); BitwardenLegacyKeyBytes::from(encoded_key)
}
}
}
#[cfg(test)]
pub fn generate_seeded_for_unit_tests(seed: &str) -> Self {
let mut seeded_rng = ChaChaRng::from_seed(sha2::Sha256::digest(seed.as_bytes()).into());
let mut enc_key = Box::pin(Array::<u8, U32>::default());
let mut mac_key = Box::pin(Array::<u8, U32>::default());
seeded_rng.fill(enc_key.as_mut_slice());
seeded_rng.fill(mac_key.as_mut_slice());
SymmetricCryptoKey::Aes256CbcHmacKey(Aes256CbcHmacKey { enc_key, mac_key })
}
pub(crate) fn to_encoded_raw(&self) -> EncodedSymmetricKey {
match self {
Self::Aes256CbcKey(key) => {
EncodedSymmetricKey::BitwardenLegacyKey(key.enc_key.to_vec().into())
}
Self::Aes256CbcHmacKey(key) => {
let mut buf = Vec::with_capacity(64);
buf.extend_from_slice(&key.enc_key);
buf.extend_from_slice(&key.mac_key);
EncodedSymmetricKey::BitwardenLegacyKey(buf.into())
}
Self::XChaCha20Poly1305Key(key) => {
let builder = coset::CoseKeyBuilder::new_symmetric_key(key.enc_key.to_vec());
let mut cose_key = builder.key_id((&key.key_id).into());
for op in &key.supported_operations {
cose_key = cose_key.add_key_op(*op);
}
let mut cose_key = cose_key.build();
cose_key.alg = Some(RegisteredLabelWithPrivate::PrivateUse(
cose::XCHACHA20_POLY1305,
));
EncodedSymmetricKey::CoseKey(
cose_key
.to_vec()
.expect("cose key serialization should not fail")
.into(),
)
}
}
}
pub(crate) fn try_from_cose(serialized_key: &[u8]) -> Result<Self, CryptoError> {
let cose_key =
coset::CoseKey::from_slice(serialized_key).map_err(|_| CryptoError::InvalidKey)?;
let key = SymmetricCryptoKey::try_from(&cose_key)?;
Ok(key)
}
#[allow(missing_docs)]
pub fn to_base64(&self) -> B64 {
B64::from(self.to_encoded().as_ref())
}
pub fn key_id(&self) -> Option<KeyId> {
match self {
Self::Aes256CbcKey(_) => None,
Self::Aes256CbcHmacKey(_) => None,
Self::XChaCha20Poly1305Key(key) => Some(key.key_id.clone()),
}
}
}
impl ConstantTimeEq for SymmetricCryptoKey {
fn ct_eq(&self, other: &SymmetricCryptoKey) -> Choice {
use SymmetricCryptoKey::*;
match (self, other) {
(Aes256CbcKey(a), Aes256CbcKey(b)) => a.ct_eq(b),
(Aes256CbcKey(_), _) => Choice::from(0),
(Aes256CbcHmacKey(a), Aes256CbcHmacKey(b)) => a.ct_eq(b),
(Aes256CbcHmacKey(_), _) => Choice::from(0),
(XChaCha20Poly1305Key(a), XChaCha20Poly1305Key(b)) => a.ct_eq(b),
(XChaCha20Poly1305Key(_), _) => Choice::from(0),
}
}
}
impl PartialEq for SymmetricCryptoKey {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl TryFrom<String> for SymmetricCryptoKey {
type Error = CryptoError;
fn try_from(value: String) -> Result<Self, Self::Error> {
let bytes = B64::try_from(value).map_err(|_| CryptoError::InvalidKey)?;
Self::try_from(bytes)
}
}
impl TryFrom<B64> for SymmetricCryptoKey {
type Error = CryptoError;
fn try_from(value: B64) -> Result<Self, Self::Error> {
Self::try_from(&BitwardenLegacyKeyBytes::from(&value))
}
}
impl TryFrom<&BitwardenLegacyKeyBytes> for SymmetricCryptoKey {
type Error = CryptoError;
fn try_from(value: &BitwardenLegacyKeyBytes) -> Result<Self, Self::Error> {
let slice = value.as_ref();
if slice.len() == Self::AES256_CBC_HMAC_KEY_LEN || slice.len() == Self::AES256_CBC_KEY_LEN {
Self::try_from(EncodedSymmetricKey::BitwardenLegacyKey(value.clone()))
} else if slice.len() > Self::AES256_CBC_HMAC_KEY_LEN {
let unpadded_value = unpad_key(slice)?;
Ok(Self::try_from_cose(unpadded_value)?)
} else {
Err(CryptoError::InvalidKeyLen)
}
}
}
impl TryFrom<EncodedSymmetricKey> for SymmetricCryptoKey {
type Error = CryptoError;
fn try_from(value: EncodedSymmetricKey) -> Result<Self, Self::Error> {
match value {
EncodedSymmetricKey::BitwardenLegacyKey(key)
if key.as_ref().len() == Self::AES256_CBC_KEY_LEN =>
{
let mut enc_key = Box::pin(Array::<u8, U32>::default());
enc_key.copy_from_slice(&key.as_ref()[..Self::AES256_CBC_KEY_LEN]);
Ok(Self::Aes256CbcKey(Aes256CbcKey { enc_key }))
}
EncodedSymmetricKey::BitwardenLegacyKey(key)
if key.as_ref().len() == Self::AES256_CBC_HMAC_KEY_LEN =>
{
let mut enc_key = Box::pin(Array::<u8, U32>::default());
enc_key.copy_from_slice(&key.as_ref()[..32]);
let mut mac_key = Box::pin(Array::<u8, U32>::default());
mac_key.copy_from_slice(&key.as_ref()[32..]);
Ok(Self::Aes256CbcHmacKey(Aes256CbcHmacKey {
enc_key,
mac_key,
}))
}
EncodedSymmetricKey::CoseKey(key) => Self::try_from_cose(key.as_ref()),
_ => Err(CryptoError::InvalidKey),
}
}
}
impl CryptoKey for SymmetricCryptoKey {}
impl std::fmt::Debug for SymmetricCryptoKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SymmetricCryptoKey::Aes256CbcKey(key) => key.fmt(f),
SymmetricCryptoKey::Aes256CbcHmacKey(key) => key.fmt(f),
SymmetricCryptoKey::XChaCha20Poly1305Key(key) => key.fmt(f),
}
}
}
impl std::fmt::Debug for Aes256CbcKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug_struct = f.debug_struct("SymmetricKey::Aes256Cbc");
#[cfg(feature = "dangerous-crypto-debug")]
debug_struct.field("key", &hex::encode(self.enc_key.as_slice()));
debug_struct.finish()
}
}
impl std::fmt::Debug for Aes256CbcHmacKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug_struct = f.debug_struct("SymmetricKey::Aes256CbcHmac");
#[cfg(feature = "dangerous-crypto-debug")]
debug_struct
.field("enc_key", &hex::encode(self.enc_key.as_slice()))
.field("mac_key", &hex::encode(self.mac_key.as_slice()));
debug_struct.finish()
}
}
impl std::fmt::Debug for XChaCha20Poly1305Key {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug_struct = f.debug_struct("SymmetricKey::XChaCha20Poly1305");
debug_struct.field("key_id", &self.key_id);
debug_struct.field(
"supported_operations",
&self
.supported_operations
.iter()
.map(|key_operation: &KeyOperation| cose::debug_key_operation(*key_operation))
.collect::<Vec<_>>(),
);
#[cfg(feature = "dangerous-crypto-debug")]
debug_struct.field("key", &hex::encode(self.enc_key.as_slice()));
debug_struct.finish()
}
}
fn pad_key(key_bytes: &mut Vec<u8>, min_length: u8) {
crate::keys::utils::pad_bytes(key_bytes, min_length as usize)
.expect("Padding cannot fail since the min_length is < 255")
}
fn unpad_key(key_bytes: &[u8]) -> Result<&[u8], CryptoError> {
crate::keys::utils::unpad_bytes(key_bytes).map_err(|_| CryptoError::InvalidKey)
}
pub enum EncodedSymmetricKey {
BitwardenLegacyKey(BitwardenLegacyKeyBytes),
CoseKey(CoseKeyBytes),
}
impl From<EncodedSymmetricKey> for Vec<u8> {
fn from(val: EncodedSymmetricKey) -> Self {
match val {
EncodedSymmetricKey::BitwardenLegacyKey(key) => key.to_vec(),
EncodedSymmetricKey::CoseKey(key) => key.to_vec(),
}
}
}
impl EncodedSymmetricKey {
#[allow(private_interfaces)]
pub fn content_format(&self) -> ContentFormat {
match self {
EncodedSymmetricKey::BitwardenLegacyKey(_) => ContentFormat::BitwardenLegacyKey,
EncodedSymmetricKey::CoseKey(_) => ContentFormat::CoseKey,
}
}
}
impl<'de> Deserialize<'de> for SymmetricCryptoKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let encoded_key = BitwardenLegacyKeyBytes::deserialize(deserializer)?;
SymmetricCryptoKey::try_from(&encoded_key).map_err(serde::de::Error::custom)
}
}
impl Serialize for SymmetricCryptoKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let encoded_key = self.to_encoded();
encoded_key.serialize(serializer)
}
}
#[cfg(test)]
pub fn derive_symmetric_key(name: &str) -> Aes256CbcHmacKey {
use zeroize::Zeroizing;
use crate::{derive_shareable_key, generate_random_bytes};
let secret: Zeroizing<[u8; 16]> = generate_random_bytes();
derive_shareable_key(secret, name, None)
}
#[cfg(test)]
mod tests {
use bitwarden_encoding::B64;
use coset::iana::KeyOperation;
use hybrid_array::Array;
use typenum::U32;
use super::{SymmetricCryptoKey, derive_symmetric_key};
use crate::{
Aes256CbcHmacKey, Aes256CbcKey, BitwardenLegacyKeyBytes, XChaCha20Poly1305Key,
keys::{
KeyId,
symmetric_crypto_key::{pad_key, unpad_key},
},
};
#[test]
#[ignore = "Manual test to verify debug format"]
fn test_key_debug() {
let aes_key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
println!("{:?}", aes_key);
let xchacha_key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
println!("{:?}", xchacha_key);
}
#[test]
fn test_serialize_deserialize_symmetric_crypto_key() {
let key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
let serialized = serde_json::to_string(&key).unwrap();
let deserialized: SymmetricCryptoKey = serde_json::from_str(&serialized).unwrap();
assert_eq!(key, deserialized);
}
#[test]
fn test_symmetric_crypto_key() {
let key = SymmetricCryptoKey::Aes256CbcHmacKey(derive_symmetric_key("test"));
let key2 = SymmetricCryptoKey::try_from(key.to_base64()).unwrap();
assert_eq!(key, key2);
let key = "UY4B5N4DA4UisCNClgZtRr6VLy9ZF5BXXC7cDZRqourKi4ghEMgISbCsubvgCkHf5DZctQjVot11/vVvN9NNHQ==".to_string();
let key2 = SymmetricCryptoKey::try_from(key.clone()).unwrap();
assert_eq!(key, key2.to_base64().to_string());
}
#[test]
fn test_encode_decode_old_symmetric_crypto_key() {
let key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
let encoded = key.to_encoded();
let decoded = SymmetricCryptoKey::try_from(&encoded).unwrap();
assert_eq!(key, decoded);
}
#[test]
fn test_decode_new_symmetric_crypto_key() {
let key: B64 = ("pQEEAlDib+JxbqMBlcd3KTUesbufAzoAARFvBIQDBAUGIFggt79surJXmqhPhYuuqi9ZyPfieebmtw2OsmN5SDrb4yUB").parse()
.unwrap();
let key = BitwardenLegacyKeyBytes::from(&key);
let key = SymmetricCryptoKey::try_from(&key).unwrap();
match key {
SymmetricCryptoKey::XChaCha20Poly1305Key(_) => (),
_ => panic!("Invalid key type"),
}
}
#[test]
fn test_encode_xchacha20_poly1305_key() {
let key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
let encoded = key.to_encoded();
let decoded = SymmetricCryptoKey::try_from(&encoded).unwrap();
assert_eq!(key, decoded);
}
#[test]
fn test_pad_unpad_key_63() {
let original_key = vec![1u8; 63];
let mut key_bytes = original_key.clone();
let mut encoded_bytes = vec![1u8; 65];
encoded_bytes[63] = 2;
encoded_bytes[64] = 2;
pad_key(&mut key_bytes, 65);
assert_eq!(encoded_bytes, key_bytes);
let unpadded_key = unpad_key(&key_bytes).unwrap();
assert_eq!(original_key, unpadded_key);
}
#[test]
fn test_pad_unpad_key_64() {
let original_key = vec![1u8; 64];
let mut key_bytes = original_key.clone();
let mut encoded_bytes = vec![1u8; 65];
encoded_bytes[64] = 1;
pad_key(&mut key_bytes, 65);
assert_eq!(encoded_bytes, key_bytes);
let unpadded_key = unpad_key(&key_bytes).unwrap();
assert_eq!(original_key, unpadded_key);
}
#[test]
fn test_pad_unpad_key_65() {
let original_key = vec![1u8; 65];
let mut key_bytes = original_key.clone();
let mut encoded_bytes = vec![1u8; 66];
encoded_bytes[65] = 1;
pad_key(&mut key_bytes, 65);
assert_eq!(encoded_bytes, key_bytes);
let unpadded_key = unpad_key(&key_bytes).unwrap();
assert_eq!(original_key, unpadded_key);
}
#[test]
fn test_eq_aes_cbc_hmac() {
let key1 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
let key2 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
assert_ne!(key1, key2);
let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
assert_eq!(key1, key3);
}
#[test]
fn test_eq_aes_cbc() {
let key1 =
SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(vec![1u8; 32])).unwrap();
let key2 =
SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(vec![2u8; 32])).unwrap();
assert_ne!(key1, key2);
let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
assert_eq!(key1, key3);
}
#[test]
fn test_eq_xchacha20_poly1305() {
let key1 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
let key2 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
assert_ne!(key1, key2);
let key3 = SymmetricCryptoKey::try_from(key1.to_base64()).unwrap();
assert_eq!(key1, key3);
}
#[test]
fn test_neq_different_key_types() {
let key1 = SymmetricCryptoKey::Aes256CbcKey(Aes256CbcKey {
enc_key: Box::pin(Array::<u8, U32>::default()),
});
let key2 = SymmetricCryptoKey::XChaCha20Poly1305Key(XChaCha20Poly1305Key {
enc_key: Box::pin(Array::<u8, U32>::default()),
key_id: KeyId::from([0; 16]),
supported_operations: vec![
KeyOperation::Decrypt,
KeyOperation::Encrypt,
KeyOperation::WrapKey,
KeyOperation::UnwrapKey,
],
});
assert_ne!(key1, key2);
}
#[test]
fn test_eq_variant_aes256_cbc() {
let key1 = Aes256CbcKey {
enc_key: Box::pin(Array::from([1u8; 32])),
};
let key2 = Aes256CbcKey {
enc_key: Box::pin(Array::from([1u8; 32])),
};
let key3 = Aes256CbcKey {
enc_key: Box::pin(Array::from([2u8; 32])),
};
assert_eq!(key1, key2);
assert_ne!(key1, key3);
}
#[test]
fn test_eq_variant_aes256_cbc_hmac() {
let key1 = Aes256CbcHmacKey {
enc_key: Box::pin(Array::from([1u8; 32])),
mac_key: Box::pin(Array::from([2u8; 32])),
};
let key2 = Aes256CbcHmacKey {
enc_key: Box::pin(Array::from([1u8; 32])),
mac_key: Box::pin(Array::from([2u8; 32])),
};
let key3 = Aes256CbcHmacKey {
enc_key: Box::pin(Array::from([3u8; 32])),
mac_key: Box::pin(Array::from([4u8; 32])),
};
assert_eq!(key1, key2);
assert_ne!(key1, key3);
}
#[test]
fn test_eq_variant_xchacha20_poly1305() {
let key1 = XChaCha20Poly1305Key {
enc_key: Box::pin(Array::from([1u8; 32])),
key_id: KeyId::from([0; 16]),
supported_operations: vec![
KeyOperation::Decrypt,
KeyOperation::Encrypt,
KeyOperation::WrapKey,
KeyOperation::UnwrapKey,
],
};
let key2 = XChaCha20Poly1305Key {
enc_key: Box::pin(Array::from([1u8; 32])),
key_id: KeyId::from([0; 16]),
supported_operations: vec![
KeyOperation::Decrypt,
KeyOperation::Encrypt,
KeyOperation::WrapKey,
KeyOperation::UnwrapKey,
],
};
let key3 = XChaCha20Poly1305Key {
enc_key: Box::pin(Array::from([2u8; 32])),
key_id: KeyId::from([1; 16]),
supported_operations: vec![
KeyOperation::Decrypt,
KeyOperation::Encrypt,
KeyOperation::WrapKey,
KeyOperation::UnwrapKey,
],
};
assert_eq!(key1, key2);
assert_ne!(key1, key3);
}
#[test]
fn test_neq_different_key_id() {
let key1 = XChaCha20Poly1305Key {
enc_key: Box::pin(Array::<u8, U32>::default()),
key_id: KeyId::from([0; 16]),
supported_operations: vec![
KeyOperation::Decrypt,
KeyOperation::Encrypt,
KeyOperation::WrapKey,
KeyOperation::UnwrapKey,
],
};
let key2 = XChaCha20Poly1305Key {
enc_key: Box::pin(Array::<u8, U32>::default()),
key_id: KeyId::from([1; 16]),
supported_operations: vec![
KeyOperation::Decrypt,
KeyOperation::Encrypt,
KeyOperation::WrapKey,
KeyOperation::UnwrapKey,
],
};
assert_ne!(key1, key2);
let key1 = SymmetricCryptoKey::XChaCha20Poly1305Key(key1);
let key2 = SymmetricCryptoKey::XChaCha20Poly1305Key(key2);
assert_ne!(key1, key2);
}
}