extern crate alloc;
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
use redoubt_util::hex_to_bytes;
use redoubt_hkdf_core::HkdfApi;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Flag {
ModifiedTag,
Pseudorandom,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TestResult {
Valid,
Invalid,
#[allow(dead_code)]
Acceptable,
}
pub struct TestCase {
pub tc_id: usize,
pub comment: String,
pub flags: Vec<Flag>,
pub key: String,
pub msg: String,
pub tag: String,
pub result: TestResult,
}
fn run_test_case(backend: &mut impl HkdfApi, tc: &TestCase) -> Result<(), String> {
let key = hex_to_bytes(&tc.key);
let msg = hex_to_bytes(&tc.msg);
let expected_tag = hex_to_bytes(&tc.tag);
let mut computed_tag = [0u8; 32];
backend.api_hmac_sha256(&key, &msg, &mut computed_tag);
let matches = &computed_tag[..expected_tag.len()] == expected_tag.as_slice();
match (&tc.result, matches) {
(TestResult::Valid, true) | (TestResult::Acceptable, true) => Ok(()),
(TestResult::Valid, false) | (TestResult::Acceptable, false) => Err(format!(
"tc_id {} ({}): MAC mismatch\n expected: {}\n got: {}",
tc.tc_id,
tc.comment,
tc.tag,
hex::encode(&computed_tag[..expected_tag.len()])
)),
(TestResult::Invalid, true) => Err(format!(
"tc_id {} ({}): expected invalid but MAC matched",
tc.tc_id, tc.comment
)),
(TestResult::Invalid, false) => Ok(()),
}
}
mod hex {
use super::String;
use super::format;
pub fn encode(data: &[u8]) -> String {
data.iter().map(|b| format!("{:02x}", b)).collect()
}
}
pub fn run_hmac_wycheproof_tests(backend: &mut impl HkdfApi) {
use super::hmac_sha256_wycheproof_vectors::test_vectors;
let vectors = test_vectors();
let mut failures = Vec::new();
for tc in vectors.iter() {
if let Err(msg) = run_test_case(backend, tc) {
failures.push(msg);
}
}
if !failures.is_empty() {
panic!(
"HMAC-SHA256 Wycheproof test failures ({}/{}):\n{}",
failures.len(),
vectors.len(),
failures.join("\n")
);
}
}