mod common;
use ferritls_core::gcm::Aes128Gcm;
use ferritls_core::ops::{self, AeadGcm, AeadOps, HashOps};
use ferritls_core::sha2::Sha256;
struct MockAead;
struct MockGcm;
impl AeadGcm for MockGcm {
fn seal(&self, _nonce: &[u8; 12], _aad: &[u8], buf: &mut [u8]) -> [u8; 16] {
buf.fill(0xAA);
[0xBB; 16]
}
fn open_compute_tag(&self, _nonce: &[u8; 12], _aad: &[u8], buf: &mut [u8]) -> [u8; 16] {
buf.fill(0xCC);
[0xDD; 16]
}
fn clone_box(&self) -> Box<dyn AeadGcm> {
Box::new(MockGcm)
}
}
impl AeadOps for MockAead {
fn name(&self) -> &'static str {
"mock-aead"
}
fn aes128_gcm(&self, _key: &[u8; 16]) -> Box<dyn AeadGcm> {
Box::new(MockGcm)
}
fn aes256_gcm(&self, _key: &[u8; 32]) -> Box<dyn AeadGcm> {
Box::new(MockGcm)
}
}
struct MockHash;
fn mock_compress(h: &mut [u32; 8], _block: &[u8; 64]) {
*h = [0xEEEE_EEEE; 8];
}
impl HashOps for MockHash {
fn name(&self) -> &'static str {
"mock-hash"
}
fn sha256_compress(&self) -> ferritls_core::ops::Sha256Compress {
mock_compress
}
}
static MOCK_AEAD: MockAead = MockAead;
static MOCK_HASH: MockHash = MockHash;
#[cfg(not(feature = "fips"))]
#[test]
fn dispatch_and_install_semantics() {
let d = Sha256::one_shot(b"abc");
common::assert_hex(
&d,
"ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad",
"sha256(abc)",
);
let g = Aes128Gcm::new(&[0x07; 16]);
let sealed = g.seal(&[0x01; 12], b"aad", b"secret");
assert_eq!(
g.open(&[0x01; 12], b"aad", &sealed).unwrap(),
b"secret".to_vec()
);
let mut tampered = sealed.clone();
tampered[0] ^= 1;
assert_eq!(
g.open(&[0x01; 12], b"aad", &tampered),
Err(ferritls_core::Error::VerificationFailed)
);
let g2 = g.clone();
assert_eq!(
g2.open(&[0x01; 12], b"aad", &sealed).unwrap(),
b"secret".to_vec()
);
ops::install(&MOCK_AEAD).expect("first install succeeds");
let mock_g = Aes128Gcm::new(&[0x07; 16]);
let mock_sealed = mock_g.seal(&[0x01; 12], b"aad", b"xy");
assert_eq!(
mock_sealed,
[vec![0xAA, 0xAA], vec![0xBB; 16]].concat(),
"seal must route through the mock backend"
);
assert_eq!(
mock_g.open(&[0x01; 12], b"aad", &mock_sealed),
Err(ferritls_core::Error::VerificationFailed)
);
assert_eq!(
ops::install(&MOCK_AEAD),
Err(ferritls_core::Error::Unsupported)
);
ops::install_hash(&MOCK_HASH).expect("hash install succeeds");
assert_eq!(
Sha256::one_shot(b"abc"),
[0xEE; 32],
"hash dispatch via mock"
);
assert_eq!(
ops::install_hash(&MOCK_HASH),
Err(ferritls_core::Error::Unsupported)
);
}
#[cfg(feature = "fips")]
#[test]
fn fips_refuses_install() {
assert_eq!(
ops::install(&MOCK_AEAD),
Err(ferritls_core::Error::Unsupported)
);
assert_eq!(
ops::install_hash(&MOCK_HASH),
Err(ferritls_core::Error::Unsupported)
);
let d = Sha256::one_shot(b"abc");
common::assert_hex(
&d,
"ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad",
"sha256(abc) under fips build",
);
let g = Aes128Gcm::new(&[0x07; 16]);
let sealed = g.seal(&[0x01; 12], b"aad", b"secret");
assert_eq!(
g.open(&[0x01; 12], b"aad", &sealed).unwrap(),
b"secret".to_vec()
);
}