use crate::buffer::Buffer;
use crate::helpers::{AlgoHandle, Handle, KeyHandle, WindowsString};
use crate::property::{self, BlockLength, KeyLength, KeyLengths, MessageBlockLength, ObjectLength};
use crate::{Error, Result};
use std::fmt;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ptr::null_mut;
use winapi::shared::bcrypt::*;
use winapi::shared::minwindef::{PUCHAR, ULONG};
#[derive(Debug, Clone, Copy, PartialOrd, PartialEq)]
pub enum SymmetricAlgorithmId {
Aes,
Des,
DesX,
Rc2,
TripleDes,
TripleDes112,
}
impl SymmetricAlgorithmId {
fn to_str(self) -> &'static str {
match self {
Self::Aes => BCRYPT_AES_ALGORITHM,
Self::Des => BCRYPT_DES_ALGORITHM,
Self::DesX => BCRYPT_DESX_ALGORITHM,
Self::Rc2 => BCRYPT_RC2_ALGORITHM,
Self::TripleDes => BCRYPT_3DES_ALGORITHM,
Self::TripleDes112 => BCRYPT_3DES_112_ALGORITHM,
}
}
}
#[derive(Debug, Clone, Copy, PartialOrd, PartialEq)]
pub enum ChainingMode {
Ecb,
Cbc,
Cfb,
}
impl ChainingMode {
fn to_str(self) -> &'static str {
match self {
Self::Ecb => BCRYPT_CHAIN_MODE_ECB,
Self::Cbc => BCRYPT_CHAIN_MODE_CBC,
Self::Cfb => BCRYPT_CHAIN_MODE_CFB,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Padding {
Block,
}
pub trait Algorithm {
const ID: Option<SymmetricAlgorithmId>;
fn id(&self) -> SymmetricAlgorithmId;
}
impl Algorithm for SymmetricAlgorithmId {
const ID: Option<SymmetricAlgorithmId> = None;
fn id(&self) -> SymmetricAlgorithmId {
*self
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub struct Aes;
impl Algorithm for Aes {
const ID: Option<SymmetricAlgorithmId> = Some(SymmetricAlgorithmId::Aes);
fn id(&self) -> SymmetricAlgorithmId {
SymmetricAlgorithmId::Aes
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub struct Des;
impl Algorithm for Des {
const ID: Option<SymmetricAlgorithmId> = Some(SymmetricAlgorithmId::Des);
fn id(&self) -> SymmetricAlgorithmId {
SymmetricAlgorithmId::Des
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub struct DesX;
impl Algorithm for DesX {
const ID: Option<SymmetricAlgorithmId> = Some(SymmetricAlgorithmId::DesX);
fn id(&self) -> SymmetricAlgorithmId {
SymmetricAlgorithmId::DesX
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub struct Rc2;
impl Algorithm for Rc2 {
const ID: Option<SymmetricAlgorithmId> = Some(SymmetricAlgorithmId::Rc2);
fn id(&self) -> SymmetricAlgorithmId {
SymmetricAlgorithmId::Rc2
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub struct TripleDes;
impl Algorithm for TripleDes {
const ID: Option<SymmetricAlgorithmId> = Some(SymmetricAlgorithmId::TripleDes);
fn id(&self) -> SymmetricAlgorithmId {
SymmetricAlgorithmId::TripleDes
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub struct TripleDes112;
impl Algorithm for TripleDes112 {
const ID: Option<SymmetricAlgorithmId> = Some(SymmetricAlgorithmId::TripleDes112);
fn id(&self) -> SymmetricAlgorithmId {
SymmetricAlgorithmId::TripleDes112
}
}
pub trait KeyBits {
const VALUE: Option<usize> = None;
}
pub struct DynamicKeyBits;
impl KeyBits for DynamicKeyBits {
const VALUE: Option<usize> = None;
}
pub struct Key<A: Algorithm, B: KeyBits = DynamicKeyBits> {
inner: SymmetricAlgorithmKey,
_algo: PhantomData<A>,
_bits: PhantomData<B>,
}
impl<A: Algorithm, B: KeyBits> fmt::Debug for Key<A, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Key<{}> {{ ... }}",
A::ID.map(|x| x.to_str()).unwrap_or_default()
)
}
}
impl<A: Algorithm, B: KeyBits> core::convert::TryFrom<SymmetricAlgorithmKey> for Key<A, B> {
type Error = SymmetricAlgorithmKey;
fn try_from(value: SymmetricAlgorithmKey) -> Result<Self, Self::Error> {
let name = value
.handle
.get_property_unsized::<property::AlgorithmName>()
.expect("Key to always know its algorithm name");
let name = WindowsString::from_bytes_with_nul(Vec::from(name).into()).unwrap();
let id = A::ID
.map(SymmetricAlgorithmId::to_str)
.map(WindowsString::from)
.unwrap_or_else(WindowsString::new);
let key_size = value.key_size().expect("Key to know its length");
if name == id && B::VALUE.map_or(true, |len| len == key_size) {
Ok(Self {
inner: value,
_algo: PhantomData,
_bits: PhantomData,
})
} else {
Err(value)
}
}
}
impl<A: Algorithm, B: KeyBits> AsRef<SymmetricAlgorithmKey> for Key<A, B> {
fn as_ref(&self) -> &SymmetricAlgorithmKey {
&self.inner
}
}
impl<A: Algorithm, B: KeyBits> Key<A, B> {
pub fn into_erased(self) -> SymmetricAlgorithmKey {
self.inner
}
}
impl<A: Algorithm, B: KeyBits> Clone for Key<A, B> {
fn clone(&self) -> Self {
let mut handle = KeyHandle::new();
let mut _object = Vec::with_capacity(self.inner._object.len());
unsafe {
Error::check(BCryptDuplicateKey(
self.inner.handle.as_ptr(),
handle.as_mut_ptr(),
_object.as_mut_slice().as_mut_ptr(),
_object.capacity() as u32,
0,
))
}
.expect(
"CNG to succesfully duplicate a previously successfully created key
object",
);
Self {
inner: SymmetricAlgorithmKey {
handle,
_object: Buffer::from_vec(_object),
},
_algo: PhantomData,
_bits: PhantomData,
}
}
}
pub struct SymmetricAlgorithm {
handle: AlgoHandle,
chaining_mode: ChainingMode,
}
impl SymmetricAlgorithm {
pub fn open(id: SymmetricAlgorithmId, chaining_mode: ChainingMode) -> Result<Self> {
let handle = AlgoHandle::open(id.to_str())?;
let value = WindowsString::from(chaining_mode.to_str());
handle.set_property::<property::ChainingMode>(value.as_slice_with_nul())?;
Ok(Self {
handle,
chaining_mode,
})
}
pub fn chaining_mode(&self) -> ChainingMode {
self.chaining_mode
}
pub fn valid_key_sizes(&self) -> Result<Vec<usize>> {
let key_sizes = self.handle.get_property::<KeyLengths>()?;
if key_sizes.dwIncrement != 0 {
Ok(
(key_sizes.dwMinLength as usize..=key_sizes.dwMaxLength as usize)
.step_by(key_sizes.dwIncrement as usize)
.collect(),
)
} else {
Ok(vec![key_sizes.dwMinLength as usize])
}
}
pub fn new_key(&self, secret: &[u8]) -> Result<SymmetricAlgorithmKey> {
let object_size = self.handle.get_property::<ObjectLength>()?;
let mut key_handle = KeyHandle::new();
let mut object = Buffer::new(object_size as usize);
unsafe {
Error::check(BCryptGenerateSymmetricKey(
self.handle.as_ptr(),
key_handle.as_mut_ptr(),
object.as_mut_ptr(),
object.len() as ULONG,
secret.as_ptr() as PUCHAR,
secret.len() as ULONG,
0,
))
.map(|_| SymmetricAlgorithmKey {
handle: key_handle,
_object: object,
})
}
}
}
pub struct SymmetricAlgorithmKey {
handle: KeyHandle,
_object: Buffer,
}
impl fmt::Debug for SymmetricAlgorithmKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SymmetricAlgorithmKey {{ ... }}")
}
}
impl SymmetricAlgorithmKey {
pub fn key_size(&self) -> Result<usize> {
self.handle
.get_property::<KeyLength>()
.map(|key_size| key_size as usize)
}
pub fn block_size(&self) -> Result<usize> {
self.handle
.get_property::<BlockLength>()
.map(|block_size| block_size as usize)
}
pub fn set_msg_block_len(&mut self, len: usize) -> Result<()> {
self.handle
.set_property::<MessageBlockLength>(&(len as u32))
}
pub fn encrypt(
&self,
iv: Option<&mut [u8]>,
data: &[u8],
padding: Option<Padding>,
) -> Result<Buffer> {
let (iv_ptr, iv_len) = iv
.map(|iv| (iv.as_mut_ptr(), iv.len() as ULONG))
.unwrap_or((null_mut(), 0));
let flags = match padding {
Some(Padding::Block) => BCRYPT_BLOCK_PADDING,
_ => 0,
};
let mut encrypted_len = MaybeUninit::<ULONG>::uninit();
unsafe {
Error::check(BCryptEncrypt(
self.handle.as_ptr(),
data.as_ptr() as PUCHAR,
data.len() as ULONG,
null_mut(),
iv_ptr,
iv_len,
null_mut(),
0,
encrypted_len.as_mut_ptr(),
flags,
))?;
let mut output = Buffer::new(encrypted_len.assume_init() as usize);
Error::check(BCryptEncrypt(
self.handle.as_ptr(),
data.as_ptr() as PUCHAR,
data.len() as ULONG,
null_mut(),
iv_ptr,
iv_len,
output.as_mut_ptr(),
output.len() as ULONG,
encrypted_len.as_mut_ptr(),
flags,
))
.map(|_| output)
}
}
pub fn decrypt(
&self,
iv: Option<&mut [u8]>,
data: &[u8],
padding: Option<Padding>,
) -> Result<Buffer> {
let (iv_ptr, iv_len) = iv
.map(|iv| (iv.as_mut_ptr(), iv.len() as ULONG))
.unwrap_or((null_mut(), 0));
let flags = match padding {
Some(Padding::Block) => BCRYPT_BLOCK_PADDING,
_ => 0,
};
let mut plaintext_len = MaybeUninit::<ULONG>::uninit();
unsafe {
Error::check(BCryptDecrypt(
self.handle.as_ptr(),
data.as_ptr() as PUCHAR,
data.len() as ULONG,
null_mut(),
iv_ptr,
iv_len,
null_mut(),
0,
plaintext_len.as_mut_ptr(),
flags,
))?;
let mut output = Buffer::new(plaintext_len.assume_init() as usize);
Error::check(BCryptDecrypt(
self.handle.as_ptr(),
data.as_ptr() as PUCHAR,
data.len() as ULONG,
null_mut(),
iv_ptr,
iv_len,
output.as_mut_ptr(),
output.len() as ULONG,
plaintext_len.as_mut_ptr(),
flags,
))
.map(|_| output)
}
}
}
#[cfg(feature = "block-cipher")]
pub use block_cipher_trait::BlockCipherKey;
#[cfg(feature = "block-cipher")]
mod block_cipher_trait {
use super::*;
use core::convert::TryFrom;
pub struct BlockCipherKey<A: Algorithm, B: KeyBits> {
key: super::Key<A, B>,
_algo: PhantomData<A>,
_bits: PhantomData<B>,
}
impl<A: Algorithm, B: KeyBits> Clone for BlockCipherKey<A, B> {
fn clone(&self) -> Self {
BlockCipherKey {
key: self.key.clone(),
_algo: PhantomData,
_bits: PhantomData,
}
}
}
impl<A: Algorithm, B: KeyBits> BlockCipherKey<A, B> {
pub fn into_key(self) -> super::Key<A, B> {
self.key
}
}
impl<A: Algorithm, B: KeyBits> super::Key<A, B> {
pub fn try_into_block_cipher(self) -> Result<BlockCipherKey<A, B>, Self> {
let name = self
.inner
.handle
.get_property_unsized::<property::ChainingMode>()
.expect("Key to always know its algorithm name");
let mode: String = std::char::decode_utf16(name.iter().cloned())
.map(|c| c.unwrap_or(std::char::REPLACEMENT_CHARACTER))
.collect();
if mode.starts_with(ChainingMode::Ecb.to_str()) {
Ok(BlockCipherKey {
key: self,
_algo: PhantomData,
_bits: PhantomData,
})
} else {
Err(self)
}
}
}
use cipher::generic_array::{typenum, ArrayLength};
use cipher::inout::InOut;
use cipher::{
Block, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, BlockSizeUser,
Key, KeyInit, KeySizeUser, ParBlocksSizeUser,
};
impl<T: typenum::Unsigned> KeyBits for T {
const VALUE: Option<usize> = Some(Self::USIZE);
}
macro_rules! impl_block_cipher {
($(
($algo: ty, block: $block_size: ty, par: $par_blocks: ty, KeyBits: $($tt:tt)*)
),* $(,)*
) => {
$(
impl<B: KeyBits> KeySizeUser for BlockCipherKey<$algo, B>
where
B: typenum::Unsigned,
// Fancy way of allowing only {128, 192, 256}
B: $($tt)*,
// Help the trait solver see that it's also divisible by 8
B: typenum::PartialDiv<typenum::U8>,
<B as typenum::PartialDiv<typenum::U8>>::Output: ArrayLength<u8>,
{
/// Key size in bytes with which cipher guaranteed to be initialized.
type KeySize = <B as typenum::PartialDiv<typenum::U8>>::Output;
}
impl<B: KeyBits> KeyInit for BlockCipherKey<$algo, B>
where
Self: KeySizeUser
{
/// Create new block cipher instance from key with fixed size.
fn new(key: &Key<Self>) -> Self {
let algo = <$algo>::default();
let prov = SymmetricAlgorithm::open(algo.id(), ChainingMode::Ecb).unwrap();
let key = prov.new_key(key).unwrap();
match super::Key::try_from(key) {
Ok(key) => Self {
key,
_algo: PhantomData,
_bits: PhantomData,
},
Err(..) => panic!(),
}
}
}
impl<B: KeyBits> BlockCipher for BlockCipherKey<$algo, B> {}
impl<B: KeyBits> BlockSizeUser for BlockCipherKey<$algo, B> {
type BlockSize = $block_size;
}
impl<B: KeyBits> ParBlocksSizeUser for BlockCipherKey<$algo, B> {
type ParBlocksSize = $par_blocks;
}
impl<B: KeyBits> BlockEncrypt for BlockCipherKey<$algo, B> {
fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = $block_size>) {
struct EncBack<'a, B: KeyBits>(&'a BlockCipherKey<$algo, B>);
impl<'a, B: KeyBits> BlockSizeUser for EncBack<'a, B> {
type BlockSize = $block_size;
}
impl<'a, B: KeyBits> ParBlocksSizeUser for EncBack<'a, B> {
type ParBlocksSize = $par_blocks;
}
impl<'a, B: KeyBits> BlockBackend for EncBack<'a, B> {
#[inline(always)]
fn proc_block(&mut self, mut block: InOut<'_, '_, Block<Self>>) {
let key = self.0.key.as_ref();
let buf = key.encrypt(None, block.get_in().as_slice(), None).unwrap();
let mut buf = buf.into_inner();
block.get_out()[..].copy_from_slice(buf.as_mut_slice());
}
}
f.call(&mut EncBack(self))
}
}
impl<B: KeyBits> BlockDecrypt for BlockCipherKey<$algo, B> {
fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = $block_size>) {
struct DecBack<'a, B: KeyBits>(&'a BlockCipherKey<$algo, B>);
impl<'a, B: KeyBits> BlockSizeUser for DecBack<'a, B> {
type BlockSize = $block_size;
}
impl<'a, B: KeyBits> ParBlocksSizeUser for DecBack<'a, B> {
type ParBlocksSize = $par_blocks;
}
impl<'a, B: KeyBits> BlockBackend for DecBack<'a, B> {
#[inline(always)]
fn proc_block(&mut self, mut block: InOut<'_, '_, Block<Self>>) {
let key = self.0.key.as_ref();
let buf = key.decrypt(None, block.get_in().as_slice(), None).unwrap();
let mut buf = buf.into_inner();
block.get_out()[..].copy_from_slice(buf.as_mut_slice());
}
}
f.call(&mut DecBack(self))
}
}
)*
}
}
use typenum::consts::{B1, U1, U128, U16, U192, U256, U64, U8};
use typenum::type_operators::{IsEqual, IsGreaterOrEqual, IsLessOrEqual, PartialDiv};
impl_block_cipher!(
(Aes, block: U16, par: U1, KeyBits:
IsGreaterOrEqual<U128, Output = B1> +
IsLessOrEqual<U256, Output = B1> +
PartialDiv<U64>
),
(Rc2, block: U8, par: U1, KeyBits:
IsGreaterOrEqual<U16, Output = B1> +
IsLessOrEqual<U128, Output = B1> +
PartialDiv<U8>
),
(Des, block: U8, par: U1, KeyBits: IsEqual<U64, Output = B1>),
(DesX, block: U8, par: U1, KeyBits: IsEqual<U192, Output = B1>),
(TripleDes, block: U8, par: U1, KeyBits: IsEqual<U192, Output = B1>),
(TripleDes112, block: U8, par: U1, KeyBits:
IsGreaterOrEqual<U128, Output = B1> +
IsLessOrEqual<U192, Output = B1> +
PartialDiv<U64>
)
);
}
#[cfg(test)]
mod tests {
use super::*;
const SECRET: &'static str = "0123456789ABCDEF0123456789ABCDEF";
const IV: &'static str = "0123456789ABCDEF0123456789ABCDEF";
const DATA: &'static str = "0123456789ABCDEF0123456789ABCDEF";
#[test]
fn aes() {
check_common_chaining_modes(SymmetricAlgorithmId::Aes, 16, 16);
check_common_chaining_modes(SymmetricAlgorithmId::Aes, 24, 16);
check_common_chaining_modes(SymmetricAlgorithmId::Aes, 32, 16);
}
#[test]
fn des() {
check_common_chaining_modes(SymmetricAlgorithmId::Des, 8, 8);
}
#[test]
fn des_x() {
check_common_chaining_modes(SymmetricAlgorithmId::DesX, 24, 8);
}
#[test]
fn rc2() {
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 2, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 3, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 4, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 5, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 6, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 7, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 8, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 9, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 10, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 11, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 12, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 13, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 14, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 15, 8);
check_common_chaining_modes(SymmetricAlgorithmId::Rc2, 16, 8);
}
#[test]
fn triple_des() {
check_common_chaining_modes(SymmetricAlgorithmId::TripleDes, 24, 8);
}
#[test]
fn triple_des_112() {
check_common_chaining_modes(SymmetricAlgorithmId::TripleDes112, 16, 8);
}
fn check_common_chaining_modes(
algo_id: SymmetricAlgorithmId,
key_size: usize,
block_size: usize,
) {
check_encryption_decryption(
algo_id,
ChainingMode::Ecb,
&SECRET.as_bytes()[..key_size],
None,
&DATA.as_bytes()[..block_size],
block_size,
);
check_encryption_decryption(
algo_id,
ChainingMode::Cbc,
&SECRET.as_bytes()[..key_size],
Some(IV.as_bytes()[..block_size].to_vec().as_mut()),
&DATA.as_bytes(),
block_size,
);
check_encryption_decryption(
algo_id,
ChainingMode::Cfb,
&SECRET.as_bytes()[..key_size],
Some(IV.as_bytes()[..block_size].to_vec().as_mut()),
&DATA.as_bytes(),
block_size,
);
}
fn check_encryption_decryption(
algo_id: SymmetricAlgorithmId,
chaining_mode: ChainingMode,
secret: &[u8],
iv: Option<&mut [u8]>,
data: &[u8],
expected_block_size: usize,
) {
let iv_cloned = || iv.as_ref().map(|x| x.to_vec());
let algo = SymmetricAlgorithm::open(algo_id, chaining_mode).unwrap();
let key = algo.new_key(secret).unwrap();
let ciphertext = key
.encrypt(iv_cloned().as_mut().map(|x| x.as_mut()), data, None)
.unwrap();
let plaintext = key
.decrypt(
iv_cloned().as_mut().map(|x| x.as_mut()),
ciphertext.as_slice(),
None,
)
.unwrap();
assert_eq!(data, &plaintext.as_slice()[..data.len()]);
assert_eq!(secret.len() * 8, key.key_size().unwrap());
assert_eq!(expected_block_size, key.block_size().unwrap());
}
#[cfg(feature = "block-cipher")]
fn _assert_aes_keysize_valid() {
use cipher::{generic_array::typenum, KeyInit};
fn _assert_trait_impl<T: KeyInit>() {}
_assert_trait_impl::<BlockCipherKey<Aes, typenum::U128>>();
_assert_trait_impl::<BlockCipherKey<Aes, typenum::U192>>();
_assert_trait_impl::<BlockCipherKey<Aes, typenum::U256>>();
}
#[cfg(feature = "block-cipher")]
#[test]
fn cipher_trait() {
use cipher::generic_array::{typenum::Unsigned, GenericArray};
use cipher::{BlockDecrypt, BlockEncrypt, BlockSizeUser};
use core::convert::TryFrom;
macro_rules! run_tests {
($(($algo: ty, key: $key: literal)),* $(,)*) => {
$({
let algo = <$algo>::default();
let provider = SymmetricAlgorithm::open(algo.id(), ChainingMode::Ecb).unwrap();
let key: Vec<u8> = (0..$key).collect();
let key = provider.new_key(&key).unwrap();
let typed = Key::<$algo>::try_from(key).unwrap();
let typed = typed.try_into_block_cipher().unwrap();
let block_size = <BlockCipherKey<$algo, DynamicKeyBits> as BlockSizeUser>::BlockSize::USIZE;
let block_size = u8::try_from(block_size).unwrap();
let plaintext: Vec<u8> = (0..block_size).collect();
let mut data = plaintext.clone();
typed.encrypt_block(GenericArray::from_mut_slice(data.as_mut()));
assert_ne!(data, plaintext);
typed.decrypt_block(GenericArray::from_mut_slice(data.as_mut()));
assert_eq!(data, plaintext)
})*
};
}
run_tests!(
(Aes, key: 16),
(Aes, key: 24),
(Aes, key: 32),
(Rc2, key: 2),
(Rc2, key: 8),
(Rc2, key: 128),
(Des, key: 8),
(DesX, key: 24),
(TripleDes, key: 24),
(TripleDes112, key: 16),
(TripleDes112, key: 24),
);
}
#[cfg(feature = "block-cipher")]
#[test]
fn marker_bits() {
use cipher::generic_array::typenum;
use core::convert::TryFrom;
let algo = SymmetricAlgorithm::open(SymmetricAlgorithmId::Aes, ChainingMode::Ecb).unwrap();
let key = algo.new_key(b"123456789012345678901234").unwrap();
if let Ok(..) = Key::<Aes, typenum::U128>::try_from(key) {
panic!();
}
let key = algo.new_key(b"123456789012345678901234").unwrap();
if let Ok(..) = Key::<Aes, typenum::U256>::try_from(key) {
panic!();
}
let key = algo.new_key(b"123456789012345678901234").unwrap();
if let Err(..) = Key::<Aes, typenum::U192>::try_from(key) {
panic!();
}
let key = algo.new_key(b"12345678901234567890123456789012").unwrap();
if let Ok(..) = Key::<Aes, typenum::U128>::try_from(key) {
panic!();
}
let key = algo.new_key(b"12345678901234567890123456789012").unwrap();
if let Ok(..) = Key::<Aes, typenum::U192>::try_from(key) {
panic!();
}
let key = algo.new_key(b"12345678901234567890123456789012").unwrap();
if let Err(..) = Key::<Aes, typenum::U256>::try_from(key) {
panic!();
}
}
#[test]
fn send() {
use crate::helpers::assert_send;
assert_send::<SymmetricAlgorithm>();
assert_send::<SymmetricAlgorithmKey>();
assert_send::<Key<SymmetricAlgorithmId>>();
assert_send::<Key<Aes>>();
}
}