use crate::cipher::aes::Aes;
use crate::cipher::des::TripleDes;
use crate::cipher::modes::{gf128_mul, ghash_update};
use crate::hash::ripemd160::Ripemd160;
use crate::hash::sha1::Sha1;
use crate::hash::sha3::{KeccakState, Sha3_256, Sha3_384, Sha3_512};
use crate::hash::sha256::Sha256;
use crate::hash::sha384::Sha384;
use crate::hash::sha512::Sha512;
use crate::{BlockCipher, Hasher};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Algorithm {
HmacSha1,
HmacSha256,
HmacSha384,
HmacSha512,
HmacSha3_256,
HmacSha3_384,
HmacSha3_512,
HmacRipemd160,
CmacAes128,
CmacAes192,
CmacAes256,
CmacTripleDes,
Kmac128,
Kmac256,
GmacAes128,
GmacAes192,
GmacAes256,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
InvalidKeyLen,
InvalidNonceLen,
NotInitialized,
AlreadyFinalized,
OutputBufferTooSmall {
needed: usize,
},
WrongInitVariant,
VerificationFailed,
}
enum HmacState {
Sha1(Sha1),
Sha256(Sha256),
Sha384(Sha384),
Sha512(Sha512),
Sha3_256(Sha3_256),
Sha3_384(Sha3_384),
Sha3_512(Sha3_512),
Ripemd160(Ripemd160),
}
impl HmacState {
fn block_len(&self) -> usize {
match self {
HmacState::Sha1(_) => Sha1::BLOCK_LEN,
HmacState::Sha256(_) => Sha256::BLOCK_LEN,
HmacState::Sha384(_) => Sha384::BLOCK_LEN,
HmacState::Sha512(_) => Sha512::BLOCK_LEN,
HmacState::Sha3_256(_) => Sha3_256::BLOCK_LEN,
HmacState::Sha3_384(_) => Sha3_384::BLOCK_LEN,
HmacState::Sha3_512(_) => Sha3_512::BLOCK_LEN,
HmacState::Ripemd160(_) => Ripemd160::BLOCK_LEN,
}
}
fn output_len(&self) -> usize {
match self {
HmacState::Sha1(_) => Sha1::OUTPUT_LEN,
HmacState::Sha256(_) => Sha256::OUTPUT_LEN,
HmacState::Sha384(_) => Sha384::OUTPUT_LEN,
HmacState::Sha512(_) => Sha512::OUTPUT_LEN,
HmacState::Sha3_256(_) => Sha3_256::OUTPUT_LEN,
HmacState::Sha3_384(_) => Sha3_384::OUTPUT_LEN,
HmacState::Sha3_512(_) => Sha3_512::OUTPUT_LEN,
HmacState::Ripemd160(_) => Ripemd160::OUTPUT_LEN,
}
}
fn update(&mut self, data: &[u8]) {
match self {
HmacState::Sha1(h) => h.update(data),
HmacState::Sha256(h) => h.update(data),
HmacState::Sha384(h) => h.update(data),
HmacState::Sha512(h) => h.update(data),
HmacState::Sha3_256(h) => h.update(data),
HmacState::Sha3_384(h) => h.update(data),
HmacState::Sha3_512(h) => h.update(data),
HmacState::Ripemd160(h) => h.update(data),
}
}
fn hash_key(&self, key: &[u8]) -> Vec<u8> {
match self {
HmacState::Sha1(_) => Sha1::hash(key),
HmacState::Sha256(_) => Sha256::hash(key),
HmacState::Sha384(_) => Sha384::hash(key),
HmacState::Sha512(_) => Sha512::hash(key),
HmacState::Sha3_256(_) => Sha3_256::hash(key),
HmacState::Sha3_384(_) => Sha3_384::hash(key),
HmacState::Sha3_512(_) => Sha3_512::hash(key),
HmacState::Ripemd160(_) => Ripemd160::hash(key),
}
}
fn finalize_inner(self) -> Vec<u8> {
match self {
HmacState::Sha1(h) => h.finalize(),
HmacState::Sha256(h) => h.finalize(),
HmacState::Sha384(h) => h.finalize(),
HmacState::Sha512(h) => h.finalize(),
HmacState::Sha3_256(h) => h.finalize(),
HmacState::Sha3_384(h) => h.finalize(),
HmacState::Sha3_512(h) => h.finalize(),
HmacState::Ripemd160(h) => h.finalize(),
}
}
fn outer_hash(&self, opad_key: &[u8], inner_digest: &[u8]) -> Vec<u8> {
match self {
HmacState::Sha1(_) => {
let mut h = Sha1::new();
h.update(opad_key);
h.update(inner_digest);
h.finalize()
}
HmacState::Sha256(_) => {
let mut h = Sha256::new();
h.update(opad_key);
h.update(inner_digest);
h.finalize()
}
HmacState::Sha384(_) => {
let mut h = Sha384::new();
h.update(opad_key);
h.update(inner_digest);
h.finalize()
}
HmacState::Sha512(_) => {
let mut h = Sha512::new();
h.update(opad_key);
h.update(inner_digest);
h.finalize()
}
HmacState::Sha3_256(_) => {
let mut h = Sha3_256::new();
h.update(opad_key);
h.update(inner_digest);
h.finalize()
}
HmacState::Sha3_384(_) => {
let mut h = Sha3_384::new();
h.update(opad_key);
h.update(inner_digest);
h.finalize()
}
HmacState::Sha3_512(_) => {
let mut h = Sha3_512::new();
h.update(opad_key);
h.update(inner_digest);
h.finalize()
}
HmacState::Ripemd160(_) => {
let mut h = Ripemd160::new();
h.update(opad_key);
h.update(inner_digest);
h.finalize()
}
}
}
}
enum Inner {
None,
Hmac {
inner: HmacState,
opad_key: Vec<u8>,
},
Cmac {
aes: Option<Aes>,
tdes: Option<TripleDes>,
block_len: usize,
k1: [u8; 16],
k2: [u8; 16],
x: [u8; 16],
buf: [u8; 16],
buf_len: usize,
},
Kmac {
sponge: KeccakState,
out_len: usize,
},
Gmac {
aes: Aes,
h: [u8; 16],
e_j0: [u8; 16],
y: [u8; 16],
buf: [u8; 16],
buf_len: usize,
total_len: u64,
},
}
pub struct Mac {
algo: Algorithm,
inner: Inner,
initialized: bool,
finalized: bool,
}
impl Mac {
pub fn new(algo: Algorithm) -> Self {
Self {
algo,
inner: Inner::None,
initialized: false,
finalized: false,
}
}
pub fn init(&mut self, key: &[u8]) -> Result<(), Error> {
match self.algo {
Algorithm::GmacAes128 | Algorithm::GmacAes192 | Algorithm::GmacAes256 => Err(Error::WrongInitVariant),
Algorithm::Kmac128 | Algorithm::Kmac256 => self.init_kmac(key, &[]),
_ => self.init_internal(key, None, None),
}
}
pub fn init_kmac(&mut self, key: &[u8], custom: &[u8]) -> Result<(), Error> {
match self.algo {
Algorithm::Kmac128 | Algorithm::Kmac256 => self.init_internal(key, None, Some(custom)),
_ => Err(Error::WrongInitVariant),
}
}
pub fn init_with_nonce(&mut self, key: &[u8], nonce: &[u8]) -> Result<(), Error> {
match self.algo {
Algorithm::GmacAes128 | Algorithm::GmacAes192 | Algorithm::GmacAes256 => {
if nonce.len() != 12 {
return Err(Error::InvalidNonceLen);
}
self.init_internal(key, Some(nonce), None)
}
_ => Err(Error::WrongInitVariant),
}
}
fn init_internal(&mut self, key: &[u8], nonce: Option<&[u8]>, custom: Option<&[u8]>) -> Result<(), Error> {
self.inner = match self.algo {
Algorithm::HmacSha1
| Algorithm::HmacSha256
| Algorithm::HmacSha384
| Algorithm::HmacSha512
| Algorithm::HmacSha3_256
| Algorithm::HmacSha3_384
| Algorithm::HmacSha3_512
| Algorithm::HmacRipemd160 => {
let mut state = match self.algo {
Algorithm::HmacSha1 => HmacState::Sha1(Sha1::new()),
Algorithm::HmacSha256 => HmacState::Sha256(Sha256::new()),
Algorithm::HmacSha384 => HmacState::Sha384(Sha384::new()),
Algorithm::HmacSha512 => HmacState::Sha512(Sha512::new()),
Algorithm::HmacSha3_256 => HmacState::Sha3_256(Sha3_256::new()),
Algorithm::HmacSha3_384 => HmacState::Sha3_384(Sha3_384::new()),
Algorithm::HmacSha3_512 => HmacState::Sha3_512(Sha3_512::new()),
Algorithm::HmacRipemd160 => HmacState::Ripemd160(Ripemd160::new()),
_ => unreachable!(),
};
let block_len = state.block_len();
let mut key_block = vec![0u8; block_len];
if key.len() > block_len {
let hashed = state.hash_key(key);
key_block[..hashed.len()].copy_from_slice(&hashed);
} else {
key_block[..key.len()].copy_from_slice(key);
}
let mut ipad_key = key_block.clone();
let mut opad_key = key_block;
for b in &mut ipad_key {
*b ^= 0x36;
}
for b in &mut opad_key {
*b ^= 0x5C;
}
state.update(&ipad_key);
Inner::Hmac { inner: state, opad_key }
}
Algorithm::CmacAes128 | Algorithm::CmacAes192 | Algorithm::CmacAes256 | Algorithm::CmacTripleDes => {
let expected_key_len = match self.algo {
Algorithm::CmacAes128 => 16,
Algorithm::CmacAes192 => 24,
Algorithm::CmacAes256 => 32,
Algorithm::CmacTripleDes => 24,
_ => unreachable!(),
};
if key.len() != expected_key_len {
return Err(Error::InvalidKeyLen);
}
let (aes, tdes, block_len) = match self.algo {
Algorithm::CmacAes128 | Algorithm::CmacAes192 | Algorithm::CmacAes256 => {
(Some(Aes::new(key)), None, 16usize)
}
Algorithm::CmacTripleDes => (None, Some(TripleDes::new(key)), 8usize),
_ => unreachable!(),
};
let mut l = [0u8; 16];
if let Some(ref c) = aes {
c.encrypt_block(&mut l[..16]);
} else if let Some(ref c) = tdes {
c.encrypt_block(&mut l[..8]);
}
let k1 = cmac_double(&l[..block_len]);
let k2 = cmac_double(&k1[..block_len]);
let mut k1_arr = [0u8; 16];
let mut k2_arr = [0u8; 16];
k1_arr[..block_len].copy_from_slice(&k1[..block_len]);
k2_arr[..block_len].copy_from_slice(&k2[..block_len]);
Inner::Cmac {
aes,
tdes,
block_len,
k1: k1_arr,
k2: k2_arr,
x: [0u8; 16],
buf: [0u8; 16],
buf_len: 0,
}
}
Algorithm::Kmac128 | Algorithm::Kmac256 => {
let (rate, out_len) = match self.algo {
Algorithm::Kmac128 => (168usize, 32usize),
Algorithm::Kmac256 => (136usize, 64usize),
_ => unreachable!(),
};
let mut sponge = KeccakState::new(rate, 0x04);
let custom = custom.unwrap_or(&[]);
let mut prefix = Vec::new();
append_encode_string(&mut prefix, b"KMAC");
append_encode_string(&mut prefix, custom);
bytepad_to(&mut prefix, rate);
sponge.absorb(&prefix);
let mut keyenc = Vec::new();
append_encode_string(&mut keyenc, key);
bytepad_to(&mut keyenc, rate);
sponge.absorb(&keyenc);
Inner::Kmac { sponge, out_len }
}
Algorithm::GmacAes128 | Algorithm::GmacAes192 | Algorithm::GmacAes256 => {
let expected_key_len = match self.algo {
Algorithm::GmacAes128 => 16,
Algorithm::GmacAes192 => 24,
Algorithm::GmacAes256 => 32,
_ => unreachable!(),
};
if key.len() != expected_key_len {
return Err(Error::InvalidKeyLen);
}
let nonce = nonce.expect("init_with_nonce path");
debug_assert_eq!(nonce.len(), 12);
let aes = Aes::new(key);
let mut h = [0u8; 16];
aes.encrypt_block(&mut h);
let mut j0 = [0u8; 16];
j0[..12].copy_from_slice(nonce);
j0[15] = 1;
let mut e_j0 = j0;
aes.encrypt_block(&mut e_j0);
Inner::Gmac {
aes,
h,
e_j0,
y: [0u8; 16],
buf: [0u8; 16],
buf_len: 0,
total_len: 0,
}
}
};
self.initialized = true;
self.finalized = false;
Ok(())
}
pub const fn tag_len(&self) -> usize {
match self.algo {
Algorithm::HmacSha1 | Algorithm::HmacRipemd160 => 20,
Algorithm::HmacSha256 | Algorithm::HmacSha3_256 => 32,
Algorithm::HmacSha384 | Algorithm::HmacSha3_384 => 48,
Algorithm::HmacSha512 | Algorithm::HmacSha3_512 => 64,
Algorithm::CmacAes128 | Algorithm::CmacAes192 | Algorithm::CmacAes256 => 16,
Algorithm::CmacTripleDes => 8,
Algorithm::Kmac128 => 32,
Algorithm::Kmac256 => 64,
Algorithm::GmacAes128 | Algorithm::GmacAes192 | Algorithm::GmacAes256 => 16,
}
}
pub fn update(&mut self, data: &[u8]) -> Result<(), Error> {
if !self.initialized {
return Err(Error::NotInitialized);
}
if self.finalized {
return Err(Error::AlreadyFinalized);
}
match &mut self.inner {
Inner::None => unreachable!(),
Inner::Hmac { inner, .. } => {
inner.update(data);
}
Inner::Cmac {
aes,
tdes,
block_len,
buf,
buf_len,
x,
..
} => {
let bs = *block_len;
let mut pos = 0;
while pos < data.len() {
let space = bs - *buf_len;
let take = space.min(data.len() - pos);
buf[*buf_len..*buf_len + take].copy_from_slice(&data[pos..pos + take]);
*buf_len += take;
pos += take;
if *buf_len == bs && pos < data.len() {
for i in 0..bs {
x[i] ^= buf[i];
}
if let Some(c) = aes.as_ref() {
c.encrypt_block(&mut x[..16]);
} else if let Some(c) = tdes.as_ref() {
c.encrypt_block(&mut x[..8]);
}
*buf_len = 0;
}
}
}
Inner::Kmac { sponge, .. } => {
sponge.absorb(data);
}
Inner::Gmac {
h,
y,
buf,
buf_len,
total_len,
..
} => {
*total_len += data.len() as u64;
let mut pos = 0;
while pos < data.len() {
let space = 16 - *buf_len;
let take = space.min(data.len() - pos);
buf[*buf_len..*buf_len + take].copy_from_slice(&data[pos..pos + take]);
*buf_len += take;
pos += take;
if *buf_len == 16 {
for i in 0..16 {
y[i] ^= buf[i];
}
*y = gf128_mul(y, h);
*buf_len = 0;
}
}
}
}
Ok(())
}
pub fn sign(&mut self, out: &mut [u8]) -> Result<usize, Error> {
if !self.initialized {
return Err(Error::NotInitialized);
}
if self.finalized {
return Err(Error::AlreadyFinalized);
}
let tlen = self.tag_len();
if out.len() < tlen {
return Err(Error::OutputBufferTooSmall { needed: tlen });
}
let inner = core::mem::replace(&mut self.inner, Inner::None);
match inner {
Inner::None => unreachable!(),
Inner::Hmac { inner, opad_key } => {
let inner_digest = inner.finalize_inner();
let outer = match self.algo {
Algorithm::HmacSha1 => HmacState::Sha1(Sha1::new()),
Algorithm::HmacSha256 => HmacState::Sha256(Sha256::new()),
Algorithm::HmacSha384 => HmacState::Sha384(Sha384::new()),
Algorithm::HmacSha512 => HmacState::Sha512(Sha512::new()),
Algorithm::HmacSha3_256 => HmacState::Sha3_256(Sha3_256::new()),
Algorithm::HmacSha3_384 => HmacState::Sha3_384(Sha3_384::new()),
Algorithm::HmacSha3_512 => HmacState::Sha3_512(Sha3_512::new()),
Algorithm::HmacRipemd160 => HmacState::Ripemd160(Ripemd160::new()),
_ => unreachable!(),
};
let tag = outer.outer_hash(&opad_key, &inner_digest);
out[..tlen].copy_from_slice(&tag[..tlen]);
}
Inner::Cmac {
aes,
tdes,
block_len,
k1,
k2,
mut x,
mut buf,
buf_len,
} => {
let bs = block_len;
if buf_len == bs {
for i in 0..bs {
buf[i] ^= k1[i];
}
} else {
buf[buf_len] = 0x80;
for b in &mut buf[buf_len + 1..bs] {
*b = 0x00;
}
for i in 0..bs {
buf[i] ^= k2[i];
}
}
for i in 0..bs {
x[i] ^= buf[i];
}
if let Some(c) = aes.as_ref() {
c.encrypt_block(&mut x[..16]);
} else if let Some(c) = tdes.as_ref() {
c.encrypt_block(&mut x[..8]);
}
out[..tlen].copy_from_slice(&x[..tlen]);
}
Inner::Kmac { mut sponge, out_len } => {
let trailer = right_encode((out_len * 8) as u64);
sponge.absorb(&trailer);
sponge.squeeze(&mut out[..tlen]);
}
Inner::Gmac {
aes: _aes,
h,
e_j0,
mut y,
buf,
buf_len,
total_len,
} => {
if buf_len > 0 {
let mut last = [0u8; 16];
last[..buf_len].copy_from_slice(&buf[..buf_len]);
for i in 0..16 {
y[i] ^= last[i];
}
y = gf128_mul(&y, &h);
}
let mut len_block = [0u8; 16];
let a_bits = total_len * 8;
len_block[..8].copy_from_slice(&a_bits.to_be_bytes());
for i in 0..16 {
y[i] ^= len_block[i];
}
y = gf128_mul(&y, &h);
let mut tag = [0u8; 16];
for i in 0..16 {
tag[i] = y[i] ^ e_j0[i];
}
out[..tlen].copy_from_slice(&tag[..tlen]);
let _ = ghash_update;
}
}
self.finalized = true;
Ok(tlen)
}
pub fn verify(&mut self, expected_tag: &[u8]) -> Result<(), Error> {
let tlen = self.tag_len();
if expected_tag.is_empty() || expected_tag.len() > tlen {
let mut sink = vec![0u8; tlen];
let _ = self.sign(&mut sink);
return Err(Error::VerificationFailed);
}
let mut full = vec![0u8; tlen];
self.sign(&mut full)?;
let mut diff = 0u8;
for i in 0..expected_tag.len() {
diff |= full[i] ^ expected_tag[i];
}
if diff == 0 {
Ok(())
} else {
Err(Error::VerificationFailed)
}
}
pub fn sign_to_vec(&mut self) -> Result<Vec<u8>, Error> {
let tlen = self.tag_len();
let mut out = vec![0u8; tlen];
self.sign(&mut out)?;
Ok(out)
}
}
fn cmac_double(input: &[u8]) -> [u8; 16] {
let bs = input.len();
debug_assert!(bs == 8 || bs == 16);
let rb: u8 = if bs == 16 { 0x87 } else { 0x1B };
let mut out = [0u8; 16];
let mut carry: u8 = 0;
for i in (0..bs).rev() {
let v = input[i];
out[i] = (v << 1) | carry;
carry = (v >> 7) & 1;
}
if (input[0] & 0x80) != 0 {
out[bs - 1] ^= rb;
}
out
}
fn left_encode(x: u64) -> Vec<u8> {
let mut bytes = Vec::new();
let be = x.to_be_bytes();
let first = be.iter().position(|&b| b != 0).unwrap_or(7);
let n = (8 - first) as u8;
bytes.push(n);
bytes.extend_from_slice(&be[first..]);
bytes
}
fn right_encode(x: u64) -> Vec<u8> {
let mut bytes = Vec::new();
let be = x.to_be_bytes();
let first = be.iter().position(|&b| b != 0).unwrap_or(7);
let n = (8 - first) as u8;
bytes.extend_from_slice(&be[first..]);
bytes.push(n);
bytes
}
fn append_encode_string(out: &mut Vec<u8>, s: &[u8]) {
out.extend_from_slice(&left_encode((s.len() as u64) * 8));
out.extend_from_slice(s);
}
fn bytepad_to(buf: &mut Vec<u8>, w: usize) {
let prefix = left_encode(w as u64);
let mut full = Vec::with_capacity(prefix.len() + buf.len());
full.extend_from_slice(&prefix);
full.extend_from_slice(buf);
let pad = (w - (full.len() % w)) % w;
full.extend(core::iter::repeat(0u8).take(pad));
*buf = full;
}
#[cfg(test)]
mod tests {
use super::*;
fn hex(s: &str) -> Vec<u8> {
let s: String = s.chars().filter(|c| !c.is_whitespace()).collect();
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
.collect()
}
#[test]
fn hmac_sha256_rfc4231_tc1() {
let key = hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
let data = b"Hi There";
let expected = hex("b0344c61d8db38535ca8afceaf0bf12b\
881dc200c9833da726e9376c2e32cff7");
let mut m = Mac::new(Algorithm::HmacSha256);
m.init(&key).unwrap();
m.update(data).unwrap();
let tag = m.sign_to_vec().unwrap();
assert_eq!(tag, expected);
}
#[test]
fn hmac_sha256_rfc4231_tc2_streaming() {
let key = b"Jefe";
let expected = hex("5bdcc146bf60754e6a042426089575c7\
5a003f089d2739839dec58b964ec3843");
let data = b"what do ya want for nothing?";
let mut m = Mac::new(Algorithm::HmacSha256);
m.init(key).unwrap();
for chunk in data.chunks(3) {
m.update(chunk).unwrap();
}
let tag = m.sign_to_vec().unwrap();
assert_eq!(tag, expected);
}
#[test]
fn hmac_sha256_long_key_rfc4231_tc6() {
let key = vec![0xaau8; 131];
let data = b"Test Using Larger Than Block-Size Key - Hash Key First";
let expected = hex("60e431591ee0b67f0d8a26aacbf5b77f\
8e0bc6213728c5140546040f0ee37f54");
let mut m = Mac::new(Algorithm::HmacSha256);
m.init(&key).unwrap();
m.update(data).unwrap();
let tag = m.sign_to_vec().unwrap();
assert_eq!(tag, expected);
}
#[test]
fn hmac_sha512_rfc4231_tc1() {
let key = hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
let data = b"Hi There";
let expected = hex("87aa7cdea5ef619d4ff0b4241a1d6cb0\
2379f4e2ce4ec2787ad0b30545e17cde\
daa833b7d6b8a702038b274eaea3f4e4\
be9d914eeb61f1702e696c203a126854");
let mut m = Mac::new(Algorithm::HmacSha512);
m.init(&key).unwrap();
m.update(data).unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn hmac_sha1_rfc2202_tc1() {
let key = hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
let data = b"Hi There";
let expected = hex("b617318655057264e28bc0b6fb378c8ef146be00");
let mut m = Mac::new(Algorithm::HmacSha1);
m.init(&key).unwrap();
m.update(data).unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn cmac_aes128_rfc4493_empty() {
let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
let expected = hex("bb1d6929e95937287fa37d129b756746");
let mut m = Mac::new(Algorithm::CmacAes128);
m.init(&key).unwrap();
m.update(b"").unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn cmac_aes128_rfc4493_one_block() {
let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
let m_bytes = hex("6bc1bee22e409f96e93d7e117393172a");
let expected = hex("070a16b46b4d4144f79bdd9dd04a287c");
let mut m = Mac::new(Algorithm::CmacAes128);
m.init(&key).unwrap();
m.update(&m_bytes).unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn cmac_aes128_rfc4493_40bytes() {
let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
let m_bytes = hex("6bc1bee22e409f96e93d7e117393172a\
ae2d8a571e03ac9c9eb76fac45af8e51\
30c81c46a35ce411");
let expected = hex("dfa66747de9ae63030ca32611497c827");
let mut m = Mac::new(Algorithm::CmacAes128);
m.init(&key).unwrap();
m.update(&m_bytes[..7]).unwrap();
m.update(&m_bytes[7..23]).unwrap();
m.update(&m_bytes[23..]).unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn cmac_aes128_rfc4493_64bytes() {
let key = hex("2b7e151628aed2a6abf7158809cf4f3c");
let m_bytes = hex("6bc1bee22e409f96e93d7e117393172a\
ae2d8a571e03ac9c9eb76fac45af8e51\
30c81c46a35ce411e5fbc1191a0a52ef\
f69f2445df4f9b17ad2b417be66c3710");
let expected = hex("51f0bebf7e3b9d92fc49741779363cfe");
let mut m = Mac::new(Algorithm::CmacAes128);
m.init(&key).unwrap();
m.update(&m_bytes).unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn kmac128_sample1() {
let key = hex("404142434445464748494a4b4c4d4e4f\
505152535455565758595a5b5c5d5e5f");
let data = hex("00010203");
let expected = hex("e5780b0d3ea6f7d3a429c5706aa43a00\
fadbd7d49628839e3187243f456ee14e");
let mut m = Mac::new(Algorithm::Kmac128);
m.init(&key).unwrap();
m.update(&data).unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn kmac128_sample2_with_custom() {
let key = hex("404142434445464748494a4b4c4d4e4f\
505152535455565758595a5b5c5d5e5f");
let data = hex("00010203");
let custom = b"My Tagged Application";
let expected = hex("3b1fba963cd8b0b59e8c1a6d71888b71\
43651af8ba0a7070c0979e2811324aa5");
let mut m = Mac::new(Algorithm::Kmac128);
m.init_kmac(&key, custom).unwrap();
m.update(&data).unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn kmac256_sample4_with_custom() {
let key = hex("404142434445464748494a4b4c4d4e4f\
505152535455565758595a5b5c5d5e5f");
let data = hex("00010203");
let custom = b"My Tagged Application";
let expected = hex("20c570c31346f703c9ac36c61c03cb64\
c3970d0cfc787e9b79599d273a68d2f7\
f69d4cc3de9d104a351689f27cf6f595\
1f0103f33f4f24871024d9c27773a8dd");
let mut m = Mac::new(Algorithm::Kmac256);
m.init_kmac(&key, custom).unwrap();
m.update(&data).unwrap();
assert_eq!(m.sign_to_vec().unwrap(), expected);
}
#[test]
fn gmac_aes128_matches_gcm_empty_plaintext() {
use crate::cipher::aes::Aes128;
use crate::cipher::modes::Gcm;
let key = hex("feffe9928665731c6d6a8f9467308308");
let nonce_bytes = hex("cafebabefacedbaddecaf888");
let nonce: [u8; 12] = nonce_bytes.clone().try_into().unwrap();
let aad = hex("d9313225f88406e5a55909c5aff5269a\
86a7a9531534f7da2e4c303d8a318a72\
1c3c0c95956809532fcf0e2449a6b525");
let cipher = Aes128::new(&key);
let (_ct, tag_ref) = Gcm::encrypt(&cipher, &nonce, &aad, &[]);
let mut m = Mac::new(Algorithm::GmacAes128);
m.init_with_nonce(&key, &nonce_bytes).unwrap();
for chunk in aad.chunks(7) {
m.update(chunk).unwrap();
}
let tag = m.sign_to_vec().unwrap();
assert_eq!(tag.len(), 16);
assert_eq!(tag, tag_ref.to_vec());
}
#[test]
fn gmac_verify_truncated() {
let key = hex("feffe9928665731c6d6a8f9467308308");
let nonce = hex("cafebabefacedbaddecaf888");
let aad = b"some authenticated data";
let mut signer = Mac::new(Algorithm::GmacAes128);
signer.init_with_nonce(&key, &nonce).unwrap();
signer.update(aad).unwrap();
let full_tag = signer.sign_to_vec().unwrap();
let truncated = &full_tag[..12];
let mut verifier = Mac::new(Algorithm::GmacAes128);
verifier.init_with_nonce(&key, &nonce).unwrap();
verifier.update(aad).unwrap();
assert_eq!(verifier.verify(truncated), Ok(()));
let mut bad = full_tag.clone();
bad[0] ^= 0xFF;
let mut verifier = Mac::new(Algorithm::GmacAes128);
verifier.init_with_nonce(&key, &nonce).unwrap();
verifier.update(aad).unwrap();
assert_eq!(verifier.verify(&bad[..12]), Err(Error::VerificationFailed));
}
#[test]
fn round_trip_all_hmac_and_cmac() {
let key128 = [0x42u8; 16];
let key192 = [0x42u8; 24];
let key256 = [0x42u8; 32];
let cases: &[(Algorithm, &[u8])] = &[
(Algorithm::HmacSha1, b"hmac-sha1-key-here"),
(Algorithm::HmacSha256, b"hmac-sha256-key-here"),
(Algorithm::HmacSha384, b"hmac-sha384-key-here"),
(Algorithm::HmacSha512, b"hmac-sha512-key-here"),
(Algorithm::HmacSha3_256, b"hmac-sha3-256-key"),
(Algorithm::HmacSha3_384, b"hmac-sha3-384-key"),
(Algorithm::HmacSha3_512, b"hmac-sha3-512-key"),
(Algorithm::HmacRipemd160, b"hmac-ripemd160-key"),
(Algorithm::CmacAes128, &key128),
(Algorithm::CmacAes192, &key192),
(Algorithm::CmacAes256, &key256),
(Algorithm::CmacTripleDes, &key192),
];
for (algo, key) in cases {
let mut signer = Mac::new(*algo);
signer.init(key).unwrap();
signer.update(b"the quick brown fox jumps over the lazy dog").unwrap();
let tag = signer.sign_to_vec().unwrap();
let mut verifier = Mac::new(*algo);
verifier.init(key).unwrap();
verifier.update(b"the quick brown fox jumps over the lazy dog").unwrap();
assert_eq!(verifier.verify(&tag), Ok(()), "{:?}", algo);
let mut bad = tag.clone();
bad[0] ^= 0x01;
let mut verifier = Mac::new(*algo);
verifier.init(key).unwrap();
verifier.update(b"the quick brown fox jumps over the lazy dog").unwrap();
assert_eq!(verifier.verify(&bad), Err(Error::VerificationFailed), "{:?}", algo);
}
}
#[test]
fn hmac_init_after_use_resets() {
let mut m = Mac::new(Algorithm::HmacSha256);
m.init(b"first key").unwrap();
m.update(b"first message").unwrap();
let _ = m.sign_to_vec().unwrap();
m.init(b"second key").unwrap();
m.update(b"second message").unwrap();
let tag = m.sign_to_vec().unwrap();
let mut ref_m = Mac::new(Algorithm::HmacSha256);
ref_m.init(b"second key").unwrap();
ref_m.update(b"second message").unwrap();
assert_eq!(tag, ref_m.sign_to_vec().unwrap());
}
#[test]
fn wrong_init_variant_rejected() {
let mut m = Mac::new(Algorithm::GmacAes128);
assert_eq!(m.init(&[0u8; 16]), Err(Error::WrongInitVariant));
let mut m = Mac::new(Algorithm::HmacSha256);
assert_eq!(m.init_with_nonce(b"k", &[0u8; 12]), Err(Error::WrongInitVariant));
let mut m = Mac::new(Algorithm::HmacSha256);
assert_eq!(m.init_kmac(b"k", b""), Err(Error::WrongInitVariant));
}
#[test]
fn cmac_invalid_key_len() {
let mut m = Mac::new(Algorithm::CmacAes128);
assert_eq!(m.init(&[0u8; 17]), Err(Error::InvalidKeyLen));
}
#[test]
fn gmac_invalid_nonce_len() {
let mut m = Mac::new(Algorithm::GmacAes128);
assert_eq!(m.init_with_nonce(&[0u8; 16], &[0u8; 11]), Err(Error::InvalidNonceLen));
}
#[test]
fn output_too_small() {
let mut m = Mac::new(Algorithm::HmacSha256);
m.init(b"k").unwrap();
m.update(b"data").unwrap();
let mut small = [0u8; 8];
assert!(matches!(m.sign(&mut small), Err(Error::OutputBufferTooSmall { .. })));
}
#[test]
fn verify_rejects_empty_or_too_long() {
let mut m = Mac::new(Algorithm::HmacSha256);
m.init(b"k").unwrap();
m.update(b"d").unwrap();
assert_eq!(m.verify(&[]), Err(Error::VerificationFailed));
let mut m = Mac::new(Algorithm::HmacSha256);
m.init(b"k").unwrap();
m.update(b"d").unwrap();
assert_eq!(m.verify(&[0u8; 33]), Err(Error::VerificationFailed));
}
}