use crate::BlockCipher;
pub mod chacha20_poly1305;
pub mod eax;
pub mod gcm_siv;
pub mod ocb;
pub mod poly1305;
pub mod siv;
pub use chacha20_poly1305::ChaCha20Poly1305;
pub use eax::Eax;
pub use gcm_siv::{Aes128GcmSiv, Aes256GcmSiv};
pub use ocb::Ocb;
pub use poly1305::Poly1305;
pub use siv::Siv;
#[inline]
fn assert_block_multiple<C: BlockCipher>(buf: &[u8]) {
assert_eq!(
buf.len() % C::BLOCK_LEN,
0,
"buffer length must be a multiple of the block length"
);
}
#[inline]
fn xor_in_place(dst: &mut [u8], src: &[u8]) {
for (d, s) in dst.iter_mut().zip(src.iter()) {
*d ^= *s;
}
}
#[inline]
fn increment_be(counter: &mut [u8]) {
for b in counter.iter_mut().rev() {
let (next, carry) = b.overflowing_add(1);
*b = next;
if !carry {
break;
}
}
}
#[inline]
fn rb_for(block_len: usize) -> u8 {
match block_len {
8 => 0x1b,
16 => 0x87,
_ => panic!("CMAC only supports 64-bit or 128-bit block ciphers"),
}
}
fn dbl(block: &[u8]) -> Vec<u8> {
let mut out = vec![0u8; block.len()];
let mut carry = 0u8;
for (o, &b) in out.iter_mut().rev().zip(block.iter().rev()) {
*o = (b << 1) | carry;
carry = b >> 7;
}
if carry != 0 {
let last = out.len() - 1;
out[last] ^= rb_for(block.len());
}
out
}
#[inline]
fn assert_block_128<C: BlockCipher>() {
assert_eq!(
C::BLOCK_LEN,
16,
"this mode requires a 128-bit block cipher"
);
}
#[inline]
fn xor_block16_in_place(dst: &mut [u8; 16], src: &[u8; 16]) {
for i in 0..16 {
dst[i] ^= src[i];
}
}
#[inline]
fn increment_be32(counter: &mut [u8; 16]) {
for b in counter[12..].iter_mut().rev() {
let (next, carry) = b.overflowing_add(1);
*b = next;
if !carry {
break;
}
}
}
const GCM_MAX_COUNTER_BLOCKS: u64 = (u32::MAX as u64) - 1;
const GCM_MAX_PAYLOAD_BYTES: u64 = GCM_MAX_COUNTER_BLOCKS * 16;
#[inline]
fn gcm_payload_len_allowed_u64(len_bytes: u64) -> bool {
len_bytes.saturating_add(15) / 16 <= GCM_MAX_COUNTER_BLOCKS
}
#[inline]
fn gcm_payload_len_allowed(len_bytes: usize) -> bool {
gcm_payload_len_allowed_u64(u64::try_from(len_bytes).unwrap_or(u64::MAX))
}
#[inline]
fn assert_gcm_payload_len(len_bytes: usize) {
assert!(
gcm_payload_len_allowed(len_bytes),
"GCM payload too large: max {} bytes per key/nonce",
GCM_MAX_PAYLOAD_BYTES
);
}
#[inline]
fn gf_mul_x_xts(tweak: &mut [u8; 16]) {
let mut carry = 0u8;
for b in tweak.iter_mut() {
let next = *b >> 7;
*b = (*b << 1) | carry;
carry = next;
}
if carry != 0 {
tweak[0] ^= 0x87;
}
}
#[inline]
fn xex_encrypt_block<C: BlockCipher>(cipher: &C, tweak: &[u8; 16], block: &mut [u8; 16]) {
xor_block16_in_place(block, tweak);
cipher.encrypt(block);
xor_block16_in_place(block, tweak);
}
#[inline]
fn xex_decrypt_block<C: BlockCipher>(cipher: &C, tweak: &[u8; 16], block: &mut [u8; 16]) {
xor_block16_in_place(block, tweak);
cipher.decrypt(block);
xor_block16_in_place(block, tweak);
}
#[inline]
fn ghash_mul_vt(x: u128, y: u128) -> u128 {
const R: u128 = 0xe100_0000_0000_0000_0000_0000_0000_0000;
let mut z = 0u128;
let mut v = y;
for i in 0..128 {
if ((x >> (127 - i)) & 1) != 0 {
z ^= v;
}
if (v & 1) == 0 {
v >>= 1;
} else {
v = (v >> 1) ^ R;
}
}
z
}
#[inline]
fn ghash_mul_ct(x: u128, y: u128) -> u128 {
const R: u128 = 0xe100_0000_0000_0000_0000_0000_0000_0000;
let mut z = 0u128;
let mut v = y;
for i in 0..128 {
let bit = u8::try_from((x >> (127 - i)) & 1).expect("single bit fits in u8");
let bit_mask = 0u128.wrapping_sub(u128::from(bit));
z ^= v & bit_mask;
let lsb = u8::try_from(v & 1).expect("single bit fits in u8");
let lsb_mask = 0u128.wrapping_sub(u128::from(lsb));
v = (v >> 1) ^ (R & lsb_mask);
}
z
}
type GhashMulFn = fn(u128, u128) -> u128;
fn ghash_update(y: &mut u128, h: u128, data: &[u8], mul: GhashMulFn) {
let mut block = [0u8; 16];
for chunk in data.chunks(16) {
block.fill(0);
block[..chunk.len()].copy_from_slice(chunk);
*y ^= u128::from_be_bytes(block);
*y = mul(*y, h);
}
}
fn ghash(h: u128, aad: &[u8], ciphertext: &[u8], mul: GhashMulFn) -> u128 {
let mut y = 0u128;
ghash_update(&mut y, h, aad, mul);
ghash_update(&mut y, h, ciphertext, mul);
let mut len_block = [0u8; 16];
len_block[..8].copy_from_slice(&((aad.len() as u64) << 3).to_be_bytes());
len_block[8..].copy_from_slice(&((ciphertext.len() as u64) << 3).to_be_bytes());
y ^= u128::from_be_bytes(len_block);
mul(y, h)
}
#[inline]
fn ghash_iv(h: u128, iv: &[u8], mul: GhashMulFn) -> [u8; 16] {
if iv.len() == 12 {
let mut j0 = [0u8; 16];
j0[..12].copy_from_slice(iv);
j0[15] = 1;
return j0;
}
ghash(h, &[], iv, mul).to_be_bytes()
}
#[inline]
fn gcm_hash_subkey<C: BlockCipher>(cipher: &C) -> u128 {
let mut h = [0u8; 16];
cipher.encrypt(&mut h);
u128::from_be_bytes(h)
}
#[inline]
fn counter_keystream<C: BlockCipher>(cipher: &C, counter: &[u8; 16]) -> [u8; 16] {
let mut out = *counter;
cipher.encrypt(&mut out);
out
}
fn gcm_compute_tag<C: BlockCipher>(
cipher: &C,
nonce: &[u8],
aad: &[u8],
ciphertext: &[u8],
mul: GhashMulFn,
) -> [u8; 16] {
assert_block_128::<C>();
assert_gcm_payload_len(ciphertext.len());
let h = gcm_hash_subkey(cipher);
let j0 = ghash_iv(h, nonce, mul);
let s = ghash(h, aad, ciphertext, mul);
let tag_mask = u128::from_be_bytes(counter_keystream(cipher, &j0));
(s ^ tag_mask).to_be_bytes()
}
fn gcm_compute_tag_with_h<C: BlockCipher>(
cipher: &C,
h: u128,
nonce: &[u8],
aad: &[u8],
ciphertext: &[u8],
mul: GhashMulFn,
) -> [u8; 16] {
assert_gcm_payload_len(ciphertext.len());
let j0 = ghash_iv(h, nonce, mul);
let s = ghash(h, aad, ciphertext, mul);
let tag_mask = u128::from_be_bytes(counter_keystream(cipher, &j0));
(s ^ tag_mask).to_be_bytes()
}
#[inline]
fn ccm_l_from_nonce(nonce: &[u8]) -> usize {
assert!(
(7..=13).contains(&nonce.len()),
"CCM nonce length must be in 7..=13 bytes"
);
15 - nonce.len()
}
#[inline]
fn assert_ccm_tag_len(tag_len: usize) {
assert!(
(4..=16).contains(&tag_len) && tag_len.is_multiple_of(2),
"CCM tag length must be one of {{4,6,8,10,12,14,16}}"
);
}
#[inline]
fn ccm_pack_len(block: &mut [u8; 16], l: usize, value: u64) {
let needed_bits = l * 8;
assert!(
needed_bits >= 64 || value < (1u64 << needed_bits),
"CCM length/counter does not fit in L bytes"
);
for i in 0..l {
block[15 - i] = u8::try_from((value >> (8 * i)) & 0xff).expect("single byte");
}
}
#[inline]
fn ccm_b0(nonce: &[u8], msg_len: usize, aad_len: usize, tag_len: usize) -> [u8; 16] {
let l = ccm_l_from_nonce(nonce);
assert_ccm_tag_len(tag_len);
let msg_len_u64 = u64::try_from(msg_len).expect("message length fits u64");
let mut b0 = [0u8; 16];
let aad_flag = u8::from(aad_len != 0) << 6;
let t_field = u8::try_from((tag_len - 2) / 2).expect("CCM tag field fits u8") << 3;
let l_field = u8::try_from(l - 1).expect("CCM L field fits u8");
b0[0] = aad_flag | t_field | l_field;
b0[1..1 + nonce.len()].copy_from_slice(nonce);
ccm_pack_len(&mut b0, l, msg_len_u64);
b0
}
#[inline]
fn ccm_counter_block(nonce: &[u8], counter: u64) -> [u8; 16] {
let l = ccm_l_from_nonce(nonce);
let mut ctr = [0u8; 16];
ctr[0] = u8::try_from(l - 1).expect("CCM L field fits u8");
ctr[1..1 + nonce.len()].copy_from_slice(nonce);
ccm_pack_len(&mut ctr, l, counter);
ctr
}
fn ccm_encode_aad(aad: &[u8]) -> Vec<u8> {
if aad.is_empty() {
return Vec::new();
}
let mut out = Vec::with_capacity(aad.len() + 16);
let aad_len = aad.len() as u64;
if aad_len < ((1u64 << 16) - (1u64 << 8)) {
out.extend_from_slice(
&u16::try_from(aad_len)
.expect("length range checked")
.to_be_bytes(),
);
} else if aad_len < (1u64 << 32) {
out.extend_from_slice(&[0xff, 0xfe]);
out.extend_from_slice(&(aad_len as u32).to_be_bytes());
} else {
out.extend_from_slice(&[0xff, 0xff]);
out.extend_from_slice(&aad_len.to_be_bytes());
}
out.extend_from_slice(aad);
if !out.len().is_multiple_of(16) {
out.resize(out.len().next_multiple_of(16), 0);
}
out
}
fn ccm_cbc_mac<C: BlockCipher>(
cipher: &C,
nonce: &[u8],
aad: &[u8],
plaintext: &[u8],
tag_len: usize,
) -> [u8; 16] {
assert_block_128::<C>();
let mut y = [0u8; 16];
let b0 = ccm_b0(nonce, plaintext.len(), aad.len(), tag_len);
xor_block16_in_place(&mut y, &b0);
cipher.encrypt(&mut y);
let aad_encoded = ccm_encode_aad(aad);
for chunk in aad_encoded.chunks(16) {
let mut block = [0u8; 16];
block.copy_from_slice(chunk);
xor_block16_in_place(&mut y, &block);
cipher.encrypt(&mut y);
}
for chunk in plaintext.chunks(16) {
let mut block = [0u8; 16];
block[..chunk.len()].copy_from_slice(chunk);
xor_block16_in_place(&mut y, &block);
cipher.encrypt(&mut y);
}
y
}
fn ccm_apply_ctr<C: BlockCipher>(cipher: &C, nonce: &[u8], data: &mut [u8]) {
for (i, chunk) in data.chunks_mut(16).enumerate() {
let ctr = ccm_counter_block(nonce, u64::try_from(i + 1).expect("counter fits u64"));
let stream = counter_keystream(cipher, &ctr);
xor_in_place(chunk, &stream[..chunk.len()]);
}
}
const AES_KEY_WRAP_DEFAULT_IV: [u8; 8] = [0xA6; 8];
#[inline]
fn xor_aes_kw_t(a: &mut [u8; 8], t: u64) {
let t_be = t.to_be_bytes();
for i in 0..8 {
a[i] ^= t_be[i];
}
}
pub struct AesKeyWrap<C> {
cipher: C,
}
impl<C> AesKeyWrap<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> AesKeyWrap<C> {
pub fn wrap_key(&self, key_data: &[u8]) -> Option<Vec<u8>> {
self.wrap_key_with_iv(key_data, &AES_KEY_WRAP_DEFAULT_IV)
}
pub fn wrap_key_with_iv(&self, key_data: &[u8], iv: &[u8; 8]) -> Option<Vec<u8>> {
assert_block_128::<C>();
if !key_data.len().is_multiple_of(8) || key_data.len() < 16 {
return None;
}
let n = key_data.len() / 8;
let mut a = *iv;
let mut r = Vec::with_capacity(n);
for chunk in key_data.chunks_exact(8) {
let mut block = [0u8; 8];
block.copy_from_slice(chunk);
r.push(block);
}
for j in 0..6usize {
for (i, ri) in r.iter_mut().enumerate() {
let mut b = [0u8; 16];
b[..8].copy_from_slice(&a);
b[8..].copy_from_slice(ri);
self.cipher.encrypt(&mut b);
a.copy_from_slice(&b[..8]);
let t =
u64::try_from(j * n + i + 1).expect("AES-KW step index must fit in 64 bits");
xor_aes_kw_t(&mut a, t);
ri.copy_from_slice(&b[8..]);
}
}
let mut wrapped = Vec::with_capacity((n + 1) * 8);
wrapped.extend_from_slice(&a);
for ri in r {
wrapped.extend_from_slice(&ri);
}
Some(wrapped)
}
pub fn unwrap_key(&self, wrapped: &[u8]) -> Option<Vec<u8>> {
self.unwrap_key_with_iv(wrapped, &AES_KEY_WRAP_DEFAULT_IV)
}
pub fn unwrap_key_with_iv(&self, wrapped: &[u8], iv: &[u8; 8]) -> Option<Vec<u8>> {
assert_block_128::<C>();
if !wrapped.len().is_multiple_of(8) || wrapped.len() < 24 {
return None;
}
let n = (wrapped.len() / 8) - 1;
let mut a = [0u8; 8];
a.copy_from_slice(&wrapped[..8]);
let mut r = Vec::with_capacity(n);
for chunk in wrapped[8..].chunks_exact(8) {
let mut block = [0u8; 8];
block.copy_from_slice(chunk);
r.push(block);
}
for j in (0..6usize).rev() {
for i in (0..n).rev() {
let t =
u64::try_from(j * n + i + 1).expect("AES-KW step index must fit in 64 bits");
let mut a_xor_t = a;
xor_aes_kw_t(&mut a_xor_t, t);
let mut b = [0u8; 16];
b[..8].copy_from_slice(&a_xor_t);
b[8..].copy_from_slice(&r[i]);
self.cipher.decrypt(&mut b);
a.copy_from_slice(&b[..8]);
r[i].copy_from_slice(&b[8..]);
}
}
if crate::ct::constant_time_eq_mask(&a, iv) != u8::MAX {
return None;
}
let mut key_data = Vec::with_capacity(n * 8);
for ri in r {
key_data.extend_from_slice(&ri);
}
Some(key_data)
}
}
pub struct Ecb<C> {
cipher: C,
}
impl<C> Ecb<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> Ecb<C> {
pub fn encrypt_nopad(&self, data: &mut [u8]) {
assert_block_multiple::<C>(data);
for block in data.chunks_exact_mut(C::BLOCK_LEN) {
self.cipher.encrypt(block);
}
}
pub fn decrypt_nopad(&self, data: &mut [u8]) {
assert_block_multiple::<C>(data);
for block in data.chunks_exact_mut(C::BLOCK_LEN) {
self.cipher.decrypt(block);
}
}
}
pub struct Cbc<C> {
cipher: C,
}
impl<C> Cbc<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> Cbc<C> {
pub fn encrypt_nopad(&self, iv: &[u8], data: &mut [u8]) {
assert_eq!(iv.len(), C::BLOCK_LEN, "wrong IV length");
assert_block_multiple::<C>(data);
let mut prev = iv.to_vec();
for block in data.chunks_exact_mut(C::BLOCK_LEN) {
xor_in_place(block, &prev);
self.cipher.encrypt(block);
prev.copy_from_slice(block);
}
}
pub fn decrypt_nopad(&self, iv: &[u8], data: &mut [u8]) {
assert_eq!(iv.len(), C::BLOCK_LEN, "wrong IV length");
assert_block_multiple::<C>(data);
let mut prev = iv.to_vec();
let mut tmp = vec![0u8; C::BLOCK_LEN];
for block in data.chunks_exact_mut(C::BLOCK_LEN) {
tmp.copy_from_slice(block);
self.cipher.decrypt(block);
xor_in_place(block, &prev);
prev.copy_from_slice(&tmp);
}
}
}
pub struct Cfb<C> {
cipher: C,
}
impl<C> Cfb<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> Cfb<C> {
pub fn encrypt_nopad(&self, iv: &[u8], data: &mut [u8]) {
assert_eq!(iv.len(), C::BLOCK_LEN, "wrong IV length");
assert_block_multiple::<C>(data);
let mut feedback = iv.to_vec();
let mut keystream = feedback.clone();
for block in data.chunks_exact_mut(C::BLOCK_LEN) {
keystream.copy_from_slice(&feedback);
self.cipher.encrypt(&mut keystream);
xor_in_place(block, &keystream);
feedback.copy_from_slice(block);
}
}
pub fn decrypt_nopad(&self, iv: &[u8], data: &mut [u8]) {
assert_eq!(iv.len(), C::BLOCK_LEN, "wrong IV length");
assert_block_multiple::<C>(data);
let mut feedback = iv.to_vec();
let mut keystream = feedback.clone();
let mut tmp = vec![0u8; C::BLOCK_LEN];
for block in data.chunks_exact_mut(C::BLOCK_LEN) {
tmp.copy_from_slice(block);
keystream.copy_from_slice(&feedback);
self.cipher.encrypt(&mut keystream);
xor_in_place(block, &keystream);
feedback.copy_from_slice(&tmp);
}
}
}
pub struct Cfb8<C> {
cipher: C,
}
impl<C> Cfb8<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> Cfb8<C> {
pub fn encrypt(&self, iv: &[u8], data: &mut [u8]) {
assert_eq!(iv.len(), C::BLOCK_LEN, "wrong IV length");
let mut state = iv.to_vec();
let mut stream = vec![0u8; C::BLOCK_LEN];
for byte in data.iter_mut() {
stream.copy_from_slice(&state);
self.cipher.encrypt(&mut stream);
let ct = *byte ^ stream[0];
state.rotate_left(1);
state[C::BLOCK_LEN - 1] = ct;
*byte = ct;
}
}
pub fn decrypt(&self, iv: &[u8], data: &mut [u8]) {
assert_eq!(iv.len(), C::BLOCK_LEN, "wrong IV length");
let mut state = iv.to_vec();
let mut stream = vec![0u8; C::BLOCK_LEN];
for byte in data.iter_mut() {
let ct = *byte;
stream.copy_from_slice(&state);
self.cipher.encrypt(&mut stream);
*byte = ct ^ stream[0];
state.rotate_left(1);
state[C::BLOCK_LEN - 1] = ct;
}
}
}
pub struct Ofb<C> {
cipher: C,
}
impl<C> Ofb<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> Ofb<C> {
pub fn apply_keystream(&self, iv: &[u8], data: &mut [u8]) {
assert_eq!(iv.len(), C::BLOCK_LEN, "wrong IV length");
let mut feedback = iv.to_vec();
for chunk in data.chunks_mut(C::BLOCK_LEN) {
self.cipher.encrypt(&mut feedback);
xor_in_place(chunk, &feedback[..chunk.len()]);
}
}
}
pub struct Ctr<C> {
cipher: C,
}
impl<C> Ctr<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> Ctr<C> {
pub fn apply_keystream(&self, counter: &[u8], data: &mut [u8]) {
assert_eq!(counter.len(), C::BLOCK_LEN, "wrong counter length");
let mut ctr = counter.to_vec();
let mut stream = ctr.clone();
for chunk in data.chunks_mut(C::BLOCK_LEN) {
stream.copy_from_slice(&ctr);
self.cipher.encrypt(&mut stream);
xor_in_place(chunk, &stream[..chunk.len()]);
increment_be(&mut ctr);
}
}
}
pub struct Xts<C> {
data_cipher: C,
tweak_cipher: C,
}
impl<C> Xts<C> {
pub fn new(data_cipher: C, tweak_cipher: C) -> Self {
Self {
data_cipher,
tweak_cipher,
}
}
pub fn data_cipher(&self) -> &C {
&self.data_cipher
}
pub fn tweak_cipher(&self) -> &C {
&self.tweak_cipher
}
}
impl<C: BlockCipher> Xts<C> {
pub fn encrypt_sector(&self, tweak_value: &[u8; 16], data: &mut [u8]) {
assert_block_128::<C>();
assert!(
data.len() >= 16,
"XTS requires at least one complete block in each data unit"
);
let full_blocks = data.len() / 16;
let rem = data.len() % 16;
let mut tweak = *tweak_value;
self.tweak_cipher.encrypt(&mut tweak);
if rem == 0 {
for block in data.chunks_exact_mut(16) {
let mut tmp = [0u8; 16];
tmp.copy_from_slice(block);
xex_encrypt_block(&self.data_cipher, &tweak, &mut tmp);
block.copy_from_slice(&tmp);
gf_mul_x_xts(&mut tweak);
}
return;
}
for block in data[..(full_blocks - 1) * 16].chunks_exact_mut(16) {
let mut tmp = [0u8; 16];
tmp.copy_from_slice(block);
xex_encrypt_block(&self.data_cipher, &tweak, &mut tmp);
block.copy_from_slice(&tmp);
gf_mul_x_xts(&mut tweak);
}
let last_full_start = (full_blocks - 1) * 16;
let mut cc = [0u8; 16];
cc.copy_from_slice(&data[last_full_start..last_full_start + 16]);
xex_encrypt_block(&self.data_cipher, &tweak, &mut cc);
let mut pp = [0u8; 16];
pp[..rem].copy_from_slice(&data[last_full_start + 16..]);
pp[rem..].copy_from_slice(&cc[rem..]);
data[last_full_start + 16..].copy_from_slice(&cc[..rem]);
let mut next_tweak = tweak;
gf_mul_x_xts(&mut next_tweak);
xex_encrypt_block(&self.data_cipher, &next_tweak, &mut pp);
data[last_full_start..last_full_start + 16].copy_from_slice(&pp);
}
pub fn decrypt_sector(&self, tweak_value: &[u8; 16], data: &mut [u8]) {
assert_block_128::<C>();
assert!(
data.len() >= 16,
"XTS requires at least one complete block in each data unit"
);
let full_blocks = data.len() / 16;
let rem = data.len() % 16;
let mut tweak = *tweak_value;
self.tweak_cipher.encrypt(&mut tweak);
if rem == 0 {
for block in data.chunks_exact_mut(16) {
let mut tmp = [0u8; 16];
tmp.copy_from_slice(block);
xex_decrypt_block(&self.data_cipher, &tweak, &mut tmp);
block.copy_from_slice(&tmp);
gf_mul_x_xts(&mut tweak);
}
return;
}
for block in data[..(full_blocks - 1) * 16].chunks_exact_mut(16) {
let mut tmp = [0u8; 16];
tmp.copy_from_slice(block);
xex_decrypt_block(&self.data_cipher, &tweak, &mut tmp);
block.copy_from_slice(&tmp);
gf_mul_x_xts(&mut tweak);
}
let last_full_start = (full_blocks - 1) * 16;
let mut next_tweak = tweak;
gf_mul_x_xts(&mut next_tweak);
let mut pp = [0u8; 16];
pp.copy_from_slice(&data[last_full_start..last_full_start + 16]);
xex_decrypt_block(&self.data_cipher, &next_tweak, &mut pp);
let mut cc = [0u8; 16];
cc[..rem].copy_from_slice(&data[last_full_start + 16..]);
cc[rem..].copy_from_slice(&pp[rem..]);
let mut last_full = cc;
xex_decrypt_block(&self.data_cipher, &tweak, &mut last_full);
data[last_full_start..last_full_start + 16].copy_from_slice(&last_full);
data[last_full_start + 16..].copy_from_slice(&pp[..rem]);
}
}
pub struct Cmac<C> {
cipher: C,
}
impl<C> Cmac<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
pub struct Ccm<C, const TAG_LEN: usize = 16> {
cipher: C,
}
impl<C, const TAG_LEN: usize> Ccm<C, TAG_LEN> {
pub fn new(cipher: C) -> Self {
assert_ccm_tag_len(TAG_LEN);
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
pub fn tag_len(&self) -> usize {
TAG_LEN
}
}
impl<C: BlockCipher, const TAG_LEN: usize> Ccm<C, TAG_LEN> {
#[must_use]
pub fn compute_tag(&self, nonce: &[u8], aad: &[u8], plaintext: &[u8]) -> [u8; TAG_LEN] {
let t = ccm_cbc_mac(&self.cipher, nonce, aad, plaintext, TAG_LEN);
let s0 = counter_keystream(&self.cipher, &ccm_counter_block(nonce, 0));
let mut tag = [0u8; TAG_LEN];
for i in 0..TAG_LEN {
tag[i] = t[i] ^ s0[i];
}
tag
}
#[must_use]
pub fn encrypt(&self, nonce: &[u8], aad: &[u8], data: &mut [u8]) -> [u8; TAG_LEN] {
assert_block_128::<C>();
let tag = self.compute_tag(nonce, aad, data);
ccm_apply_ctr(&self.cipher, nonce, data);
tag
}
pub fn decrypt(&self, nonce: &[u8], aad: &[u8], data: &mut [u8], tag: &[u8; TAG_LEN]) -> bool {
assert_block_128::<C>();
let mut plaintext = data.to_vec();
ccm_apply_ctr(&self.cipher, nonce, &mut plaintext);
let expected = self.compute_tag(nonce, aad, &plaintext);
if crate::ct::constant_time_eq_mask(&expected, tag) != u8::MAX {
crate::ct::zeroize_slice(&mut plaintext);
return false;
}
data.copy_from_slice(&plaintext);
true
}
}
pub struct Gcm<C> {
cipher: C,
}
pub struct GcmVt<C> {
cipher: C,
}
impl<C> Gcm<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C> GcmVt<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> Gcm<C> {
#[must_use]
pub fn compute_tag(&self, nonce: &[u8], aad: &[u8], ciphertext: &[u8]) -> [u8; 16] {
gcm_compute_tag(&self.cipher, nonce, aad, ciphertext, ghash_mul_ct)
}
#[must_use]
pub fn encrypt(&self, nonce: &[u8], aad: &[u8], data: &mut [u8]) -> [u8; 16] {
assert_block_128::<C>();
assert_gcm_payload_len(data.len());
let mut h = [0u8; 16];
self.cipher.encrypt(&mut h);
let h = u128::from_be_bytes(h);
let j0 = ghash_iv(h, nonce, ghash_mul_ct);
let mut counter = j0;
increment_be32(&mut counter);
for chunk in data.chunks_mut(16) {
let stream = counter_keystream(&self.cipher, &counter);
xor_in_place(chunk, &stream[..chunk.len()]);
increment_be32(&mut counter);
}
let s = ghash(h, aad, data, ghash_mul_ct);
let tag_mask = u128::from_be_bytes(counter_keystream(&self.cipher, &j0));
(s ^ tag_mask).to_be_bytes()
}
pub fn decrypt(&self, nonce: &[u8], aad: &[u8], data: &mut [u8], tag: &[u8]) -> bool {
assert_block_128::<C>();
assert_gcm_payload_len(data.len());
let h = gcm_hash_subkey(&self.cipher);
let expected = gcm_compute_tag_with_h(&self.cipher, h, nonce, aad, data, ghash_mul_ct);
if crate::ct::constant_time_eq_mask(&expected, tag) != u8::MAX {
return false;
}
let j0 = ghash_iv(h, nonce, ghash_mul_ct);
let mut counter = j0;
increment_be32(&mut counter);
for chunk in data.chunks_mut(16) {
let stream = counter_keystream(&self.cipher, &counter);
xor_in_place(chunk, &stream[..chunk.len()]);
increment_be32(&mut counter);
}
true
}
}
impl<C: BlockCipher> GcmVt<C> {
#[must_use]
pub fn compute_tag(&self, nonce: &[u8], aad: &[u8], ciphertext: &[u8]) -> [u8; 16] {
gcm_compute_tag(&self.cipher, nonce, aad, ciphertext, ghash_mul_vt)
}
#[must_use]
pub fn encrypt(&self, nonce: &[u8], aad: &[u8], data: &mut [u8]) -> [u8; 16] {
assert_block_128::<C>();
assert_gcm_payload_len(data.len());
let mut h = [0u8; 16];
self.cipher.encrypt(&mut h);
let h = u128::from_be_bytes(h);
let j0 = ghash_iv(h, nonce, ghash_mul_vt);
let mut counter = j0;
increment_be32(&mut counter);
for chunk in data.chunks_mut(16) {
let stream = counter_keystream(&self.cipher, &counter);
xor_in_place(chunk, &stream[..chunk.len()]);
increment_be32(&mut counter);
}
let s = ghash(h, aad, data, ghash_mul_vt);
let tag_mask = u128::from_be_bytes(counter_keystream(&self.cipher, &j0));
(s ^ tag_mask).to_be_bytes()
}
pub fn decrypt(&self, nonce: &[u8], aad: &[u8], data: &mut [u8], tag: &[u8]) -> bool {
assert_block_128::<C>();
assert_gcm_payload_len(data.len());
let h = gcm_hash_subkey(&self.cipher);
let expected = gcm_compute_tag_with_h(&self.cipher, h, nonce, aad, data, ghash_mul_vt);
if crate::ct::constant_time_eq_mask(&expected, tag) != u8::MAX {
return false;
}
let j0 = ghash_iv(h, nonce, ghash_mul_vt);
let mut counter = j0;
increment_be32(&mut counter);
for chunk in data.chunks_mut(16) {
let stream = counter_keystream(&self.cipher, &counter);
xor_in_place(chunk, &stream[..chunk.len()]);
increment_be32(&mut counter);
}
true
}
}
pub struct Gmac<C> {
cipher: C,
}
pub struct GmacVt<C> {
cipher: C,
}
impl<C> Gmac<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C> GmacVt<C> {
pub fn new(cipher: C) -> Self {
Self { cipher }
}
pub fn cipher(&self) -> &C {
&self.cipher
}
}
impl<C: BlockCipher> Gmac<C> {
#[must_use]
pub fn compute(&self, nonce: &[u8], aad: &[u8]) -> [u8; 16] {
gcm_compute_tag(&self.cipher, nonce, aad, &[], ghash_mul_ct)
}
pub fn verify(&self, nonce: &[u8], aad: &[u8], tag: &[u8]) -> bool {
crate::ct::constant_time_eq_mask(&self.compute(nonce, aad), tag) == u8::MAX
}
}
impl<C: BlockCipher> GmacVt<C> {
#[must_use]
pub fn compute(&self, nonce: &[u8], aad: &[u8]) -> [u8; 16] {
gcm_compute_tag(&self.cipher, nonce, aad, &[], ghash_mul_vt)
}
pub fn verify(&self, nonce: &[u8], aad: &[u8], tag: &[u8]) -> bool {
crate::ct::constant_time_eq_mask(&self.compute(nonce, aad), tag) == u8::MAX
}
}
impl<C: BlockCipher> Cmac<C> {
pub fn compute(&self, data: &[u8]) -> Vec<u8> {
let blk = C::BLOCK_LEN;
let mut l = vec![0u8; blk];
self.cipher.encrypt(&mut l);
let k1 = dbl(&l);
let k2 = dbl(&k1);
let n = if data.is_empty() {
1
} else {
data.len().div_ceil(blk)
};
let last_complete = !data.is_empty() && data.len().is_multiple_of(blk);
let mut x = vec![0u8; blk];
let mut y = vec![0u8; blk];
for block in data.chunks(blk).take(n.saturating_sub(1)) {
y.copy_from_slice(&x);
xor_in_place(&mut y, block);
self.cipher.encrypt(&mut y);
x.copy_from_slice(&y);
}
let mut m_last = vec![0u8; blk];
if last_complete {
let start = (n - 1) * blk;
m_last.copy_from_slice(&data[start..start + blk]);
xor_in_place(&mut m_last, &k1);
} else {
let start = (n - 1) * blk;
let rem = data.len().saturating_sub(start);
if rem != 0 {
m_last[..rem].copy_from_slice(&data[start..]);
}
m_last[rem] = 0x80;
xor_in_place(&mut m_last, &k2);
}
xor_in_place(&mut m_last, &x);
self.cipher.encrypt(&mut m_last);
m_last
}
pub fn verify(&self, data: &[u8], tag: &[u8]) -> bool {
crate::ct::constant_time_eq_mask(&self.compute(data), tag) == u8::MAX
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Aes128, Aes192, Aes256};
fn parse<const N: usize>(s: &str) -> [u8; N] {
let mut out = [0u8; N];
assert_eq!(s.len(), 2 * N);
for i in 0..N {
out[i] = u8::from_str_radix(&s[2 * i..2 * i + 2], 16).unwrap();
}
out
}
fn parse_vec(s: &str) -> Vec<u8> {
assert_eq!(s.len() % 2, 0);
let mut out = Vec::with_capacity(s.len() / 2);
let bytes = s.as_bytes();
let mut i = 0usize;
while i + 1 < bytes.len() {
let hi =
u8::from_str_radix(std::str::from_utf8(&bytes[i..i + 1]).unwrap(), 16).unwrap();
let lo =
u8::from_str_radix(std::str::from_utf8(&bytes[i + 1..i + 2]).unwrap(), 16).unwrap();
out.push((hi << 4) | lo);
i += 2;
}
out
}
#[test]
fn ecb_aes128_sp800_38a() {
let key = parse::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("3ad77bb40d7a3660a89ecaf32466ef97"),
parse::<16>("f5d3d58503b9699de785895a96fdbaaf"),
parse::<16>("43b1cd7f598ece23881b00e3ed030688"),
parse::<16>("7b0c785e27e8ad3f8223207104725dd4"),
]
.concat();
Ecb::new(Aes128::new(&key)).encrypt_nopad(&mut data);
assert_eq!(data, expected);
Ecb::new(Aes128::new(&key)).decrypt_nopad(&mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn ecb_aes256_sp800_38a() {
let key = parse::<32>("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("f3eed1bdb5d2a03c064b5a7e3db181f8"),
parse::<16>("591ccb10d410ed26dc5ba74a31362870"),
parse::<16>("b6ed21b99ca6f4f9f153e7b1beafed1d"),
parse::<16>("23304b7a39f9f3ff067d8d8f9e24ecc7"),
]
.concat();
Ecb::new(Aes256::new(&key)).encrypt_nopad(&mut data);
assert_eq!(data, expected);
Ecb::new(Aes256::new(&key)).decrypt_nopad(&mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn cbc_aes128_sp800_38a() {
let key = parse::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let iv = parse::<16>("000102030405060708090a0b0c0d0e0f");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("7649abac8119b246cee98e9b12e9197d"),
parse::<16>("5086cb9b507219ee95db113a917678b2"),
parse::<16>("73bed6b8e3c1743b7116e69e22229516"),
parse::<16>("3ff1caa1681fac09120eca307586e1a7"),
]
.concat();
let mode = Cbc::new(Aes128::new(&key));
mode.encrypt_nopad(&iv, &mut data);
assert_eq!(data, expected);
mode.decrypt_nopad(&iv, &mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn cbc_aes256_sp800_38a() {
let key = parse::<32>("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
let iv = parse::<16>("000102030405060708090a0b0c0d0e0f");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("f58c4c04d6e5f1ba779eabfb5f7bfbd6"),
parse::<16>("9cfc4e967edb808d679f777bc6702c7d"),
parse::<16>("39f23369a9d9bacfa530e26304231461"),
parse::<16>("b2eb05e2c39be9fcda6c19078c6a9d1b"),
]
.concat();
let mode = Cbc::new(Aes256::new(&key));
mode.encrypt_nopad(&iv, &mut data);
assert_eq!(data, expected);
mode.decrypt_nopad(&iv, &mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn cfb_aes128_sp800_38a() {
let key = parse::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let iv = parse::<16>("000102030405060708090a0b0c0d0e0f");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("3b3fd92eb72dad20333449f8e83cfb4a"),
parse::<16>("c8a64537a0b3a93fcde3cdad9f1ce58b"),
parse::<16>("26751f67a3cbb140b1808cf187a4f4df"),
parse::<16>("c04b05357c5d1c0eeac4c66f9ff7f2e6"),
]
.concat();
let mode = Cfb::new(Aes128::new(&key));
mode.encrypt_nopad(&iv, &mut data);
assert_eq!(data, expected);
mode.decrypt_nopad(&iv, &mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn cfb_aes256_sp800_38a() {
let key = parse::<32>("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
let iv = parse::<16>("000102030405060708090a0b0c0d0e0f");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("dc7e84bfda79164b7ecd8486985d3860"),
parse::<16>("39ffed143b28b1c832113c6331e5407b"),
parse::<16>("df10132415e54b92a13ed0a8267ae2f9"),
parse::<16>("75a385741ab9cef82031623d55b1e471"),
]
.concat();
let mode = Cfb::new(Aes256::new(&key));
mode.encrypt_nopad(&iv, &mut data);
assert_eq!(data, expected);
mode.decrypt_nopad(&iv, &mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn cfb8_aes128_roundtrip() {
let key = parse::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let iv = parse::<16>("000102030405060708090a0b0c0d0e0f");
let plaintext = *b"cfb8 mode roundtrip check";
let mut data = plaintext;
let mode = Cfb8::new(Aes128::new(&key));
mode.encrypt(&iv, &mut data);
assert_ne!(data, plaintext);
mode.decrypt(&iv, &mut data);
assert_eq!(data, plaintext);
}
#[test]
fn cfb8_aes128_sp800_38a_prefix_vector() {
let key = parse::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let iv = parse::<16>("000102030405060708090a0b0c0d0e0f");
let mut data = parse_vec("6bc1bee22e409f96e93d7e117393172aae2d");
let expected = parse_vec("3b79424c9c0dd436bace9e0ed4586a4f32b9");
let mode = Cfb8::new(Aes128::new(&key));
mode.encrypt(&iv, &mut data);
assert_eq!(data, expected);
mode.decrypt(&iv, &mut data);
assert_eq!(data, parse_vec("6bc1bee22e409f96e93d7e117393172aae2d"));
}
#[test]
fn ofb_aes128_sp800_38a() {
let key = parse::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let iv = parse::<16>("000102030405060708090a0b0c0d0e0f");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("3b3fd92eb72dad20333449f8e83cfb4a"),
parse::<16>("7789508d16918f03f53c52dac54ed825"),
parse::<16>("9740051e9c5fecf64344f7a82260edcc"),
parse::<16>("304c6528f659c77866a510d9c1d6ae5e"),
]
.concat();
let mode = Ofb::new(Aes128::new(&key));
mode.apply_keystream(&iv, &mut data);
assert_eq!(data, expected);
mode.apply_keystream(&iv, &mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn ofb_aes256_sp800_38a() {
let key = parse::<32>("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
let iv = parse::<16>("000102030405060708090a0b0c0d0e0f");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("dc7e84bfda79164b7ecd8486985d3860"),
parse::<16>("4febdc6740d20b3ac88f6ad82a4fb08d"),
parse::<16>("71ab47a086e86eedf39d1c5bba97c408"),
parse::<16>("0126141d67f37be8538f5a8be740e484"),
]
.concat();
let mode = Ofb::new(Aes256::new(&key));
mode.apply_keystream(&iv, &mut data);
assert_eq!(data, expected);
mode.apply_keystream(&iv, &mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn ctr_aes128_sp800_38a() {
let key = parse::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let ctr = parse::<16>("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("874d6191b620e3261bef6864990db6ce"),
parse::<16>("9806f66b7970fdff8617187bb9fffdff"),
parse::<16>("5ae4df3edbd5d35e5b4f09020db03eab"),
parse::<16>("1e031dda2fbe03d1792170a0f3009cee"),
]
.concat();
let mode = Ctr::new(Aes128::new(&key));
mode.apply_keystream(&ctr, &mut data);
assert_eq!(data, expected);
mode.apply_keystream(&ctr, &mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn ctr_aes256_sp800_38a() {
let key = parse::<32>("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
let ctr = parse::<16>("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
let mut data = [
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat();
let expected = [
parse::<16>("601ec313775789a5b7a7f504bbf3d228"),
parse::<16>("f443e3ca4d62b59aca84e990cacaf5c5"),
parse::<16>("2b0930daa23de94ce87017ba2d84988d"),
parse::<16>("dfc9c58db67aada613c2dd08457941a6"),
]
.concat();
let mode = Ctr::new(Aes256::new(&key));
mode.apply_keystream(&ctr, &mut data);
assert_eq!(data, expected);
mode.apply_keystream(&ctr, &mut data);
assert_eq!(
data,
[
parse::<16>("6bc1bee22e409f96e93d7e117393172a"),
parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"),
parse::<16>("30c81c46a35ce411e5fbc1191a0a52ef"),
parse::<16>("f69f2445df4f9b17ad2b417be66c3710"),
]
.concat()
);
}
#[test]
fn cmac_aes128_sp800_38b() {
let key = parse::<16>("2b7e151628aed2a6abf7158809cf4f3c");
let mode = Cmac::new(Aes128::new(&key));
assert_eq!(
mode.compute(&[]),
parse::<16>("bb1d6929e95937287fa37d129b756746").to_vec()
);
assert_eq!(
mode.compute(&parse::<16>("6bc1bee22e409f96e93d7e117393172a")),
parse::<16>("070a16b46b4d4144f79bdd9dd04a287c").to_vec()
);
let mut msg = Vec::with_capacity(40);
msg.extend_from_slice(&parse::<16>("6bc1bee22e409f96e93d7e117393172a"));
msg.extend_from_slice(&parse::<16>("ae2d8a571e03ac9c9eb76fac45af8e51"));
msg.extend_from_slice(&parse::<8>("30c81c46a35ce411"));
assert_eq!(
mode.compute(&msg),
parse::<16>("dfa66747de9ae63030ca32611497c827").to_vec()
);
assert!(mode.verify(&msg, &parse::<16>("dfa66747de9ae63030ca32611497c827")));
}
#[test]
fn xts_aes128_two_block_matches_openssl() {
let key1 = parse::<16>("000102030405060708090a0b0c0d0e0f");
let key2 = parse::<16>("101112131415161718191a1b1c1d1e1f");
let tweak = [0u8; 16];
let mut data =
parse::<32>("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
let expected =
parse::<32>("74a109aabf1937c022d19da4b96cbc40b8ddc9c0653a7fb0dc8425c7ef276dea");
let mode = Xts::new(Aes128::new(&key1), Aes128::new(&key2));
mode.encrypt_sector(&tweak, &mut data);
assert_eq!(data, expected);
mode.decrypt_sector(&tweak, &mut data);
assert_eq!(
data,
parse::<32>("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
);
}
#[test]
fn xts_aes128_ciphertext_stealing_matches_openssl() {
let key1 = parse::<16>("000102030405060708090a0b0c0d0e0f");
let key2 = parse::<16>("101112131415161718191a1b1c1d1e1f");
let tweak = [0u8; 16];
let mut data =
parse::<31>("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e");
let expected =
parse::<31>("03ab02ee0037b6327b1110429d562a8674a109aabf1937c022d19da4b96cbc");
let mode = Xts::new(Aes128::new(&key1), Aes128::new(&key2));
mode.encrypt_sector(&tweak, &mut data);
assert_eq!(data, expected);
mode.decrypt_sector(&tweak, &mut data);
assert_eq!(
data,
parse::<31>("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e")
);
}
#[test]
fn xts_aes128_runtime_cross_check_with_openssl() {
let key1 = parse::<16>("000102030405060708090a0b0c0d0e0f");
let key2 = parse::<16>("101112131415161718191a1b1c1d1e1f");
let tweak = [0u8; 16];
let plaintext =
parse::<31>("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e");
let Some(expected) = crate::test_utils::run_openssl(
&[
"enc",
"-aes-128-xts",
"-e",
"-nopad",
"-K",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"-iv",
"00000000000000000000000000000000",
],
&plaintext,
) else {
return;
};
let mut data = plaintext;
let mode = Xts::new(Aes128::new(&key1), Aes128::new(&key2));
mode.encrypt_sector(&tweak, &mut data);
assert_eq!(data.as_slice(), expected.as_slice());
}
#[test]
fn xts_aes128_nist_cavp_vector() {
let key1 = parse::<16>("a1b90cba3f06ac353b2c343876081762");
let key2 = parse::<16>("090923026e91771815f29dab01932f2f");
let tweak = parse::<16>("4faef7117cda59c66e4b92013e768ad5");
let mut data = parse::<16>("ebabce95b14d3c8d6fb350390790311c");
let expected = parse::<16>("778ae8b43cb98d5a825081d5be471c63");
let mode = Xts::new(Aes128::new(&key1), Aes128::new(&key2));
mode.encrypt_sector(&tweak, &mut data);
assert_eq!(data, expected);
mode.decrypt_sector(&tweak, &mut data);
assert_eq!(data, parse::<16>("ebabce95b14d3c8d6fb350390790311c"));
}
#[test]
fn ctr_des_roundtrip_generic() {
let key = parse::<8>("133457799bbcdff1");
let counter = parse::<8>("0123456789abcdef");
let original = *b"generic DES mode path!";
let mut data = original;
let mode = Ctr::new(crate::Des::new(&key).expect("non-weak DES test key"));
mode.apply_keystream(&counter, &mut data);
assert_ne!(data, original);
mode.apply_keystream(&counter, &mut data);
assert_eq!(data, original);
}
#[test]
fn gcm_aes128_empty_plaintext_nist() {
let key = [0u8; 16];
let iv = [0u8; 12];
let mut data = Vec::new();
let mode = Gcm::new(Aes128::new(&key));
let tag = mode.encrypt(&iv, &[], &mut data);
assert_eq!(data, Vec::<u8>::new());
assert_eq!(tag, parse::<16>("58e2fccefa7e3061367f1d57a4e7455a"));
assert!(mode.decrypt(&iv, &[], &mut data, &tag));
}
#[test]
fn gcm_aes128_single_block_nist() {
let key = [0u8; 16];
let iv = [0u8; 12];
let mut data = [0u8; 16];
let expected_ct = parse::<16>("0388dace60b6a392f328c2b971b2fe78");
let expected_tag = parse::<16>("ab6e47d42cec13bdf53a67b21257bddf");
let mode = Gcm::new(Aes128::new(&key));
let tag = mode.encrypt(&iv, &[], &mut data);
assert_eq!(data, expected_ct);
assert_eq!(tag, expected_tag);
assert!(mode.decrypt(&iv, &[], &mut data, &tag));
assert_eq!(data, [0u8; 16]);
}
#[test]
fn gcm_aes128_with_aad_nist() {
let key = parse::<16>("feffe9928665731c6d6a8f9467308308");
let iv = parse::<12>("cafebabefacedbaddecaf888");
let aad = parse::<20>("feedfacedeadbeeffeedfacedeadbeefabaddad2");
let mut data = parse::<64>(
"d9313225f88406e5a55909c5aff5269a\
86a7a9531534f7da2e4c303d8a318a72\
1c3c0c95956809532fcf0e2449a6b525\
b16aedf5aa0de657ba637b391aafd255",
);
let expected_ct = parse::<64>(
"42831ec2217774244b7221b784d0d49c\
e3aa212f2c02a4e035c17e2329aca12e\
21d514b25466931c7d8f6a5aac84aa05\
1ba30b396a0aac973d58e091473f5985",
);
let expected_tag = parse::<16>("da80ce830cfda02da2a218a1744f4c76");
let mode = Gcm::new(Aes128::new(&key));
let tag = mode.encrypt(&iv, &aad, &mut data);
assert_eq!(data, expected_ct);
assert_eq!(tag, expected_tag);
assert!(mode.decrypt(&iv, &aad, &mut data, &tag));
assert_eq!(
data,
parse::<64>(
"d9313225f88406e5a55909c5aff5269a\
86a7a9531534f7da2e4c303d8a318a72\
1c3c0c95956809532fcf0e2449a6b525\
b16aedf5aa0de657ba637b391aafd255",
)
);
}
#[test]
fn gcm_aes256_single_block_cavp() {
let key = parse::<32>("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22");
let iv = parse::<12>("0d18e06c7c725ac9e362e1ce");
let mut data = parse::<16>("2db5168e932556f8089a0622981d017d");
let expected_ct = parse::<16>("fa4362189661d163fcd6a56d8bf0405a");
let expected_tag = parse::<16>("d636ac1bbedd5cc3ee727dc2ab4a9489");
let mode = Gcm::new(Aes256::new(&key));
let tag = mode.encrypt(&iv, &[], &mut data);
assert_eq!(data, expected_ct);
assert_eq!(tag, expected_tag);
assert!(mode.decrypt(&iv, &[], &mut data, &tag));
assert_eq!(data, parse::<16>("2db5168e932556f8089a0622981d017d"));
}
#[test]
fn gcm_aes256_non_96bit_iv_auth_only_cavp() {
let key = parse::<32>("c639f716597a86afd12319199e21a62b1fc0277a70e3ca120bd3ff745be88604");
let iv = parse::<1>("29");
let aad = parse::<16>("20fda1db6911d160121dc3c48e5f19b2");
let mut data: [u8; 0] = [];
let expected_tag = parse::<16>("221a3398f20d0d9fe913f33a6cd413d3");
let mode = Gcm::new(Aes256::new(&key));
let tag = mode.encrypt(&iv, &aad, &mut data);
assert_eq!(tag, expected_tag);
assert!(mode.decrypt(&iv, &aad, &mut data, &tag));
}
#[test]
fn gcm_rejects_wrong_tag_without_decrypting() {
let key = [0u8; 16];
let iv = [0u8; 12];
let mut data = [0u8; 16];
let mode = Gcm::new(Aes128::new(&key));
let tag = mode.encrypt(&iv, &[], &mut data);
let mut bad_tag = tag;
bad_tag[0] ^= 1;
let ciphertext = data;
assert!(!mode.decrypt(&iv, &[], &mut data, &bad_tag));
assert_eq!(data, ciphertext);
}
#[test]
fn gcm_ct_and_vt_backends_match() {
let key = parse::<16>("feffe9928665731c6d6a8f9467308308");
let iv = parse::<12>("cafebabefacedbaddecaf888");
let aad = parse::<20>("feedfacedeadbeeffeedfacedeadbeefabaddad2");
let plaintext = parse::<64>(
"d9313225f88406e5a55909c5aff5269a\
86a7a9531534f7da2e4c303d8a318a72\
1c3c0c95956809532fcf0e2449a6b525\
b16aedf5aa0de657ba637b391aafd255",
);
let gcm_ct = Gcm::new(Aes128::new(&key));
let gcm_vt = GcmVt::new(Aes128::new(&key));
let mut ct_data = plaintext;
let mut vt_data = plaintext;
let ct_tag = gcm_ct.encrypt(&iv, &aad, &mut ct_data);
let vt_tag = gcm_vt.encrypt(&iv, &aad, &mut vt_data);
assert_eq!(ct_data, vt_data);
assert_eq!(ct_tag, vt_tag);
assert!(gcm_ct.decrypt(&iv, &aad, &mut ct_data, &ct_tag));
assert!(gcm_vt.decrypt(&iv, &aad, &mut vt_data, &vt_tag));
assert_eq!(ct_data, plaintext);
assert_eq!(vt_data, plaintext);
}
#[test]
fn gcm_payload_limit_matches_sp800_38d_bound() {
assert!(gcm_payload_len_allowed_u64(0));
assert!(gcm_payload_len_allowed_u64(1));
assert!(gcm_payload_len_allowed_u64(16));
assert!(gcm_payload_len_allowed_u64(GCM_MAX_PAYLOAD_BYTES));
assert!(!gcm_payload_len_allowed_u64(GCM_MAX_PAYLOAD_BYTES + 1));
}
#[test]
fn gmac_matches_gcm_on_empty_plaintext() {
let key = parse::<16>("feffe9928665731c6d6a8f9467308308");
let iv = parse::<12>("cafebabefacedbaddecaf888");
let aad = parse::<20>("feedfacedeadbeeffeedfacedeadbeefabaddad2");
let gcm = Gcm::new(Aes128::new(&key));
let gmac = Gmac::new(Aes128::new(&key));
let tag = gmac.compute(&iv, &aad);
assert_eq!(tag, gcm.compute_tag(&iv, &aad, &[]));
assert!(gmac.verify(&iv, &aad, &tag));
}
#[test]
fn gmac_ct_and_vt_backends_match() {
let key = parse::<16>("feffe9928665731c6d6a8f9467308308");
let iv = parse::<12>("cafebabefacedbaddecaf888");
let aad = parse::<20>("feedfacedeadbeeffeedfacedeadbeefabaddad2");
let gmac_ct = Gmac::new(Aes128::new(&key));
let gmac_vt = GmacVt::new(Aes128::new(&key));
let tag_ct = gmac_ct.compute(&iv, &aad);
let tag_vt = gmac_vt.compute(&iv, &aad);
assert_eq!(tag_ct, tag_vt);
assert!(gmac_ct.verify(&iv, &aad, &tag_ct));
assert!(gmac_vt.verify(&iv, &aad, &tag_vt));
}
#[test]
fn ccm_aes128_rfc3610_packet_vector_1() {
let key = parse::<16>("c0c1c2c3c4c5c6c7c8c9cacbcccdcecf");
let nonce = parse::<13>("00000003020100a0a1a2a3a4a5");
let aad = parse::<8>("0001020304050607");
let mut msg = parse::<23>("08090a0b0c0d0e0f101112131415161718191a1b1c1d1e");
let expected_ct = parse::<23>("588c979a61c663d2f066d0c2c0f989806d5f6b61dac384");
let expected_tag = parse::<8>("17e8d12cfdf926e0");
let mode = Ccm::<_, 8>::new(Aes128::new(&key));
let tag = mode.encrypt(&nonce, &aad, &mut msg);
assert_eq!(msg, expected_ct);
assert_eq!(tag, expected_tag);
assert!(mode.decrypt(&nonce, &aad, &mut msg, &tag));
assert_eq!(
msg,
parse::<23>("08090a0b0c0d0e0f101112131415161718191a1b1c1d1e")
);
}
#[test]
fn ccm_aes128_rfc3610_packet_vector_2() {
let key = parse::<16>("c0c1c2c3c4c5c6c7c8c9cacbcccdcecf");
let nonce = parse::<13>("00000004030201a0a1a2a3a4a5");
let aad = parse::<8>("0001020304050607");
let mut msg = parse::<24>("08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
let expected_ct = parse::<24>("72c91a36e135f8cf291ca894085c87e3cc15c439c9e43a3b");
let expected_tag = parse::<8>("a091d56e10400916");
let mode = Ccm::<_, 8>::new(Aes128::new(&key));
let tag = mode.encrypt(&nonce, &aad, &mut msg);
assert_eq!(msg, expected_ct);
assert_eq!(tag, expected_tag);
assert!(mode.decrypt(&nonce, &aad, &mut msg, &tag));
assert_eq!(
msg,
parse::<24>("08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
);
}
#[test]
fn ccm_tag_mismatch_rejected() {
let key = [0x11u8; 16];
let nonce = [0x22u8; 13];
let aad = b"header";
let mode = Ccm::<_, 12>::new(Aes128::new(&key));
let mut data = *b"ccm plaintext data";
let tag = mode.encrypt(&nonce, aad, &mut data);
let ciphertext = data;
let mut bad_tag = tag;
bad_tag[0] ^= 0x80;
assert!(!mode.decrypt(&nonce, aad, &mut data, &bad_tag));
assert_eq!(data, ciphertext);
assert!(mode.decrypt(&nonce, aad, &mut data, &tag));
assert_eq!(data, *b"ccm plaintext data");
}
#[test]
fn ccm_aes128_cavp_tlen_4_vector() {
let key = parse::<16>("43b1a6bc8d0d22d6d1ca95c18593cca5");
let nonce = parse::<13>("9882578e750b9682c6ca7f8f86");
let aad = parse::<32>("2084f3861c9ad0ccee7c63a7e05aece5db8b34bd8724cc06b4ca99a7f9c4914f");
let mut msg = parse::<24>("a2b381c7d1545c408fe29817a21dc435a154c87256346b05");
let expected_ct = parse::<24>("cc69ed76985e0ed4c8365a72775e5a19bfccc71aeb116c85");
let expected_tag = parse::<4>("a8c74677");
let mode = Ccm::<_, 4>::new(Aes128::new(&key));
let tag = mode.encrypt(&nonce, &aad, &mut msg);
assert_eq!(msg, expected_ct);
assert_eq!(tag, expected_tag);
assert!(mode.decrypt(&nonce, &aad, &mut msg, &tag));
assert_eq!(
msg,
parse::<24>("a2b381c7d1545c408fe29817a21dc435a154c87256346b05")
);
}
#[test]
fn ccm_aes128_cavp_tlen_16_vector() {
let key = parse::<16>("4189351b5caea375a0299e81c621bf43");
let nonce = parse::<13>("48c0906930561e0ab0ef4cd972");
let aad = parse::<32>("40a27c1d1e23ea3dbe8056b2774861a4a201cce49f19997d19206d8c8a343951");
let mut msg = parse::<24>("4535d12b4377928a7c0a61c9f825a48671ea05910748c8ef");
let expected_ct = parse::<24>("26c56961c035a7e452cce61bc6ee220d77b3f94d18fd10b6");
let expected_tag = parse::<16>("d80e8bf80f4a46cab06d4313f0db9be9");
let mode = Ccm::<_, 16>::new(Aes128::new(&key));
let tag = mode.encrypt(&nonce, &aad, &mut msg);
assert_eq!(msg, expected_ct);
assert_eq!(tag, expected_tag);
assert!(mode.decrypt(&nonce, &aad, &mut msg, &tag));
assert_eq!(
msg,
parse::<24>("4535d12b4377928a7c0a61c9f825a48671ea05910748c8ef")
);
}
#[test]
fn aes_key_wrap_rfc3394_4_1() {
let kek = parse::<16>("000102030405060708090A0B0C0D0E0F");
let key_data = parse::<16>("00112233445566778899AABBCCDDEEFF");
let expected = parse::<24>("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5");
let kw = AesKeyWrap::new(Aes128::new(&kek));
assert_eq!(kw.wrap_key(&key_data), Some(expected.to_vec()));
assert_eq!(kw.unwrap_key(&expected), Some(key_data.to_vec()));
}
#[test]
fn aes_key_wrap_rfc3394_4_2() {
let kek = parse::<24>("000102030405060708090A0B0C0D0E0F1011121314151617");
let key_data = parse::<16>("00112233445566778899AABBCCDDEEFF");
let expected = parse::<24>("96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D");
let kw = AesKeyWrap::new(Aes192::new(&kek));
assert_eq!(kw.wrap_key(&key_data), Some(expected.to_vec()));
assert_eq!(kw.unwrap_key(&expected), Some(key_data.to_vec()));
}
#[test]
fn aes_key_wrap_rfc3394_4_3() {
let kek = parse::<32>("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
let key_data = parse::<16>("00112233445566778899AABBCCDDEEFF");
let expected = parse::<24>("64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7");
let kw = AesKeyWrap::new(Aes256::new(&kek));
assert_eq!(kw.wrap_key(&key_data), Some(expected.to_vec()));
assert_eq!(kw.unwrap_key(&expected), Some(key_data.to_vec()));
}
#[test]
fn aes_key_wrap_rfc3394_4_4() {
let kek = parse::<24>("000102030405060708090A0B0C0D0E0F1011121314151617");
let key_data = parse::<24>("00112233445566778899AABBCCDDEEFF0001020304050607");
let expected =
parse::<32>("031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2");
let kw = AesKeyWrap::new(Aes192::new(&kek));
assert_eq!(kw.wrap_key(&key_data), Some(expected.to_vec()));
assert_eq!(kw.unwrap_key(&expected), Some(key_data.to_vec()));
}
#[test]
fn aes_key_wrap_rfc3394_4_5() {
let kek = parse::<32>("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
let key_data = parse::<24>("00112233445566778899AABBCCDDEEFF0001020304050607");
let expected =
parse::<32>("A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1");
let kw = AesKeyWrap::new(Aes256::new(&kek));
assert_eq!(kw.wrap_key(&key_data), Some(expected.to_vec()));
assert_eq!(kw.unwrap_key(&expected), Some(key_data.to_vec()));
}
#[test]
fn aes_key_wrap_rfc3394_4_6() {
let kek = parse::<32>("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
let key_data =
parse::<32>("00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F");
let expected = parse::<40>(
"28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21",
);
let kw = AesKeyWrap::new(Aes256::new(&kek));
assert_eq!(kw.wrap_key(&key_data), Some(expected.to_vec()));
assert_eq!(kw.unwrap_key(&expected), Some(key_data.to_vec()));
}
#[test]
fn aes_key_wrap_rejects_bad_lengths_and_tampering() {
let kw = AesKeyWrap::new(Aes128::new(&[0u8; 16]));
assert!(kw.wrap_key(&[]).is_none());
assert!(kw.wrap_key(&[0u8; 8]).is_none());
assert!(kw.wrap_key(&[0u8; 15]).is_none());
assert!(kw.unwrap_key(&[]).is_none());
assert!(kw.unwrap_key(&[0u8; 16]).is_none());
let mut wrapped = kw.wrap_key(&[0u8; 16]).expect("wrap");
wrapped[0] ^= 1;
assert!(kw.unwrap_key(&wrapped).is_none());
}
}