use core::marker::PhantomData;
use core::ops::Range;
pub mod raw;
use crate::error::Result;
pub trait Operation: Sized {
fn is_encrypt() -> bool;
}
#[derive(Serialize, Deserialize)]
pub enum Encryption {}
impl Operation for Encryption {
fn is_encrypt() -> bool {
true
}
}
#[derive(Serialize, Deserialize)]
pub enum Decryption {}
impl Operation for Decryption {
fn is_encrypt() -> bool {
false
}
}
pub trait Type {
fn is_valid_mode(mode: raw::CipherMode) -> bool;
}
pub enum TraditionalNoIv {}
impl Type for TraditionalNoIv {
fn is_valid_mode(mode: raw::CipherMode) -> bool {
match mode {
raw::CipherMode::ECB => true,
_ => false,
}
}
}
pub enum Traditional {}
impl Type for Traditional {
fn is_valid_mode(mode: raw::CipherMode) -> bool {
match mode {
raw::CipherMode::CBC | raw::CipherMode::CFB | raw::CipherMode::OFB | raw::CipherMode::CTR => true,
_ => false,
}
}
}
pub enum Authenticated {}
impl Type for Authenticated {
fn is_valid_mode(mode: raw::CipherMode) -> bool {
match mode {
raw::CipherMode::GCM
| raw::CipherMode::CCM
| raw::CipherMode::KW
| raw::CipherMode::KWP
| raw::CipherMode::CHACHAPOLY => true,
_ => false,
}
}
}
pub trait State {}
pub enum Fresh {}
impl State for Fresh {}
pub enum AdditionalData {}
impl State for AdditionalData {}
pub enum CipherData {}
impl State for CipherData {}
pub enum Finished {}
impl State for Finished {}
pub struct Cipher<O: Operation, T: Type, S: State = Fresh> {
raw_cipher: raw::Cipher,
padding: raw::CipherPadding,
_op: PhantomData<O>,
_type: PhantomData<T>,
_state: PhantomData<S>,
}
impl<O: Operation, T: Type, S: State> Cipher<O, T, S> {
fn change_state<N: State>(self) -> Cipher<O, T, N> {
self.change_type_and_state()
}
fn change_type_and_state<N: Type, M: State>(self) -> Cipher<O, N, M> {
Cipher {
raw_cipher: self.raw_cipher,
padding: self.padding,
_op: PhantomData,
_type: PhantomData,
_state: PhantomData,
}
}
pub fn block_size(&self) -> usize {
self.raw_cipher.block_size()
}
pub fn iv_size(&self) -> usize {
self.raw_cipher.iv_size()
}
pub fn tag_size(&self) -> Option<Range<usize>> {
if self.raw_cipher.is_authenticated() {
Some(32..129)
} else {
None
}
}
pub fn cipher_mode(&self) -> raw::CipherMode {
self.raw_cipher.cipher_mode()
}
}
impl<O: Operation, T: Type> Cipher<O, T, Fresh> {
pub fn new(cipher_id: raw::CipherId, cipher_mode: raw::CipherMode, key_bit_len: u32) -> Result<Cipher<O, T, Fresh>> {
assert!(T::is_valid_mode(cipher_mode));
let raw_cipher = raw::Cipher::setup(cipher_id, cipher_mode, key_bit_len)?;
Ok(Cipher {
raw_cipher: raw_cipher,
padding: raw::CipherPadding::Pkcs7,
_op: PhantomData,
_type: PhantomData,
_state: PhantomData,
})
}
pub fn set_parity(key: &mut [u8]) -> Result<()> {
raw::Cipher::set_parity(key)
}
}
impl<Op: Operation, T: Type> Cipher<Op, T, Fresh> {
fn set_key_and_maybe_iv(&mut self, key: &[u8], iv: Option<&[u8]>) -> Result<()> {
let cipher_op = if Op::is_encrypt() {
raw::Operation::Encrypt
} else {
raw::Operation::Decrypt
};
self.raw_cipher.set_key(cipher_op, key)?;
if let Some(iv) = iv {
self.raw_cipher.set_iv(iv)?;
}
self.raw_cipher.reset()
}
pub fn set_padding(&mut self, padding: raw::CipherPadding) -> Result<()> {
self.padding = padding;
self.raw_cipher.set_padding(padding)
}
}
impl<O: Operation> Cipher<O, TraditionalNoIv, Fresh> {
pub fn set_key(mut self, key: &[u8]) -> Result<Cipher<O, Traditional, CipherData>> {
self.set_key_and_maybe_iv(key, None)?;
Ok(self.change_type_and_state())
}
}
impl<O: Operation> Cipher<O, Traditional, Fresh> {
pub fn set_key_iv(mut self, key: &[u8], iv: &[u8]) -> Result<Cipher<O, Traditional, CipherData>> {
self.set_key_and_maybe_iv(key, Some(iv))?;
Ok(self.change_state())
}
}
impl<O: Operation> Cipher<O, Authenticated, Fresh> {
pub fn set_key_iv(mut self, key: &[u8], iv: &[u8]) -> Result<Cipher<O, Authenticated, AdditionalData>> {
self.set_key_and_maybe_iv(key, Some(iv))?;
Ok(self.change_state())
}
}
impl<O: Operation> Cipher<O, Authenticated, AdditionalData> {
pub fn set_ad(mut self, ad: &[u8]) -> Result<Cipher<O, Authenticated, CipherData>> {
self.raw_cipher.update_ad(ad)?;
Ok(self.change_state())
}
}
impl Cipher<Encryption, Traditional, CipherData> {
pub fn encrypt(
mut self,
plain_text: &[u8],
cipher_text: &mut [u8],
) -> Result<(usize, Cipher<Encryption, Traditional, Finished>)> {
let len = self.raw_cipher.encrypt(plain_text, cipher_text)?;
Ok((len, self.change_state()))
}
}
impl Cipher<Decryption, Traditional, CipherData> {
pub fn decrypt(
mut self,
cipher_text: &[u8],
plain_text: &mut [u8],
) -> Result<(usize, Cipher<Decryption, Traditional, Finished>)> {
let len = self.raw_cipher.decrypt(cipher_text, plain_text)?;
Ok((len, self.change_state()))
}
}
impl Cipher<Encryption, TraditionalNoIv, Fresh> {
pub fn cmac(
mut self,
key: &[u8],
in_data: &[u8],
out_data: &mut [u8],
) -> Result<Cipher<Encryption, TraditionalNoIv, Finished>> {
self.raw_cipher.cmac(key, in_data, out_data)?;
Ok(self.change_state())
}
}
impl Cipher<Encryption, Authenticated, AdditionalData> {
pub fn encrypt_auth(
mut self,
ad: &[u8],
plain_text: &[u8],
cipher_and_tag: &mut [u8],
tag_len: usize,
) -> Result<(usize, Cipher<Encryption, Authenticated, Finished>)> {
Ok((
self.raw_cipher.encrypt_auth(ad, plain_text, cipher_and_tag, tag_len)?,
self.change_state(),
))
}
pub fn encrypt_auth_inplace(
mut self,
ad: &[u8],
data: &mut [u8],
tag: &mut [u8],
) -> Result<(usize, Cipher<Encryption, Authenticated, Finished>)> {
Ok((self.raw_cipher.encrypt_auth_inplace(ad, data, tag)?, self.change_state()))
}
}
impl Cipher<Decryption, Authenticated, AdditionalData> {
pub fn decrypt_auth(
mut self,
ad: &[u8],
cipher_text_and_tag: &[u8],
plain_text: &mut [u8],
tag_len: usize,
) -> Result<(usize, Cipher<Decryption, Authenticated, Finished>)> {
Ok((
self.raw_cipher.decrypt_auth(ad, cipher_text_and_tag, plain_text, tag_len)?,
self.change_state(),
))
}
pub fn decrypt_auth_inplace(
mut self,
ad: &[u8],
data: &mut [u8],
tag: &[u8],
) -> Result<(usize, Cipher<Decryption, Authenticated, Finished>)> {
Ok((self.raw_cipher.decrypt_auth_inplace(ad, data, tag)?, self.change_state()))
}
}
impl<O: Operation, T: Type> Cipher<O, T, CipherData> {
pub fn update(mut self, in_data: &[u8], out_data: &mut [u8]) -> Result<(usize, Cipher<O, T, CipherData>)> {
let len = self.raw_cipher.update(in_data, out_data)?;
Ok((len, self.change_state()))
}
pub fn finish(mut self, out_data: &mut [u8]) -> Result<(usize, Cipher<O, T, Finished>)> {
let len = self.raw_cipher.finish(out_data)?;
Ok((len, self.change_state()))
}
}
impl<O: Operation> Cipher<O, Authenticated, Finished> {
pub fn write_tag(mut self, out_tag: &mut [u8]) -> Result<Cipher<O, Authenticated, Finished>> {
self.raw_cipher.write_tag(out_tag)?;
Ok(self.change_state())
}
pub fn check_tag(mut self, tag: &[u8]) -> Result<Cipher<O, Authenticated, Finished>> {
self.raw_cipher.check_tag(tag)?;
Ok(self.change_state())
}
}
#[test]
fn cmac() {
let key = [
0x7c, 0x0b, 0x7d, 0xb9, 0x81, 0x1f, 0x10, 0xd0, 0x0e, 0x47, 0x6c, 0x7a, 0x0d, 0x92, 0xf6, 0xe0,
];
let msg = [
0x1e, 0xe0, 0xec, 0x46, 0x6d, 0x46, 0xfd, 0x84, 0x9b, 0x40, 0xc0, 0x66, 0xb4, 0xfb, 0xbd, 0x22, 0xa2, 0x0a, 0x4d, 0x80,
0xa0, 0x08, 0xac, 0x9a, 0xf1, 0x7e, 0x4f, 0xdf, 0xd1, 0x06, 0x78, 0x5e,
];
let expected = vec![
0xba, 0xec, 0xdc, 0x91, 0xe9, 0xa1, 0xfc, 0x35, 0x72, 0xad, 0xf1, 0xe4, 0x23, 0x2a, 0xe2, 0x85,
];
let cipher = Cipher::<_, TraditionalNoIv, _>::new(raw::CipherId::Aes, raw::CipherMode::ECB, (key.len() * 8) as _).unwrap();
let mut generated = vec![0u8; 16];
cipher.cmac(&key, &msg, &mut generated).unwrap();
assert_eq!(generated, expected);
}
#[test]
fn ccm() {
let k = [
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
];
let iv = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16];
let ad = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
let p = [0x20, 0x21, 0x22, 0x23];
let mut p_out = [0u8; 4];
let c = [0x71, 0x62, 0x01, 0x5b];
let mut c_out = [0u8; 8];
let t = [0x4d, 0xac, 0x25, 0x5d];
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::CCM, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &iv).unwrap();
cipher.encrypt_auth(&ad, &p, &mut c_out, 4).unwrap();
assert_eq!(c, c_out[0..4]);
assert_eq!(t, c_out[4..8]);
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::CCM, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &iv).unwrap();
cipher.decrypt_auth(&ad, &c_out, &mut p_out, 4).unwrap();
assert_eq!(p, p_out);
}
#[test]
fn ccm_inplace() {
let k = [
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
];
let iv = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16];
let ad = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
let mut c = [0x20, 0x21, 0x22, 0x23, 0x0, 0x0, 0x0, 0x0];
let validate_cipher = [0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d];
let validate_plain = [0x20, 0x21, 0x22, 0x23];
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::CCM, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &iv).unwrap();
let (data, tag) = c.split_at_mut(4);
cipher.encrypt_auth_inplace(&ad, data, tag).unwrap();
assert_eq!(c, validate_cipher);
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::CCM, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &iv).unwrap();
let (data, tag) = c.split_at_mut(4);
cipher.decrypt_auth_inplace(&ad, data, tag).unwrap();
assert_eq!(validate_plain, data);
}
#[test]
fn aes_kw() {
let k = [
0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2, 0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6,
];
let p = [
0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea, 0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f,
];
let mut p_out = [0u8; 16];
let c = [
0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d, 0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3, 0xf5, 0x6f, 0xab, 0xea,
0x25, 0x48, 0xf5, 0xfb,
];
let mut c_out = [0u8; 24];
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::KW, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &[]).unwrap();
cipher.encrypt_auth(&[], &p, &mut c_out, 0).unwrap();
assert_eq!(c, c_out);
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::KW, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &[]).unwrap();
cipher.decrypt_auth(&[], &c, &mut p_out, 0).unwrap();
assert_eq!(p, p_out);
}
#[test]
fn aes_kwp() {
let k = [
0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a, 0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4,
];
let p = [0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8, 0x96];
let mut p_out = [0u8; 16];
let c = [
0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e, 0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7, 0x4d, 0xb6, 0xf8, 0xc5,
0x64, 0xe2, 0x35, 0x00,
];
let mut c_out = [0u8; 24];
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::KWP, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &[]).unwrap();
cipher.encrypt_auth(&[], &p, &mut c_out, 0).unwrap();
assert_eq!(c, c_out);
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::KWP, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &[]).unwrap();
let out_len = cipher.decrypt_auth(&[], &c, &mut p_out, 0).unwrap().0;
assert_eq!(p, &p_out[..out_len]);
}
#[test]
fn aes_gcm() {
let k = [
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x40, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
];
let iv = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16];
let ad = [0x03, 0x04, 0x05];
let p = [0x20, 0x21, 0x22, 0x23];
let c = [0x01, 0x08, 0x55, 0x0f];
let t = [0x3f, 0xd9, 0x8e, 0x74];
let mut p_out = [0u8; 4];
let mut c_out = [0u8; 8];
let cipher =
Cipher::<Encryption, Authenticated, Fresh>::new(raw::CipherId::Aes, raw::CipherMode::GCM, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &iv).unwrap();
cipher.encrypt_auth(&ad, &p, &mut c_out, 4).unwrap();
assert_eq!(c, c_out[0..4]);
assert_eq!(t, c_out[4..8]);
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::GCM, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &iv).unwrap();
cipher.decrypt_auth(&ad, &c_out, &mut p_out, 4).unwrap();
assert_eq!(p, p_out);
}