FIX: test data was not accurate for AEAD

This commit is contained in:
JohnE 2026-03-11 21:33:48 -07:00
parent c82d472004
commit cc72bb8919
2 changed files with 116 additions and 98 deletions

View File

@ -13,53 +13,10 @@ use ccc_crypto_core::{
capabilities::ProviderCapabilities,
error::CryptoError,
provider::{AeadProvider, CryptoProvider, HashProvider, KdfProvider, KemProvider, MacProvider},
types::{AlgoTestResult, BenchmarkReport, KemEncapResult, KemKeyPair, SelfTestReport},
types::{BenchmarkReport, KemEncapResult, KemKeyPair, SelfTestReport},
};
use crate::{aead, capabilities, hash, kdf, kem, mac};
// ──────────────────────────────────────────────────────────────────────────────
// Embedded NIST / RFC test vectors for self_test()
// These are checked at runtime; failures gate the provider from being marked
// `available` in the capability catalog.
// ──────────────────────────────────────────────────────────────────────────────
struct AeadVector {
algo: AeadAlgorithm,
key: &'static str,
nonce: &'static str,
aad: &'static str,
pt: &'static str,
ct_tag: &'static str, // ciphertext || tag, hex-encoded
}
/// NIST SP 800-38D and RFC 8439 test vectors.
static AEAD_VECTORS: &[AeadVector] = &[
// ── AES-256-GCM: NIST CAVS test case GCM-256/96/128 (test case 1) ───────
AeadVector {
algo: AeadAlgorithm::AesGcm256,
key: "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
nonce: "cafebabefacedbaddecaf888",
aad: "",
pt: "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72\
1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
ct_tag: "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa\
8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
},
// ── ChaCha20-Poly1305: RFC 8439 §2.8.2 test vector ──────────────────────
AeadVector {
algo: AeadAlgorithm::ChaCha20Poly1305,
key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
nonce: "070000004041424344454647",
aad: "50515253c0c1c2c3c4c5c6c7",
pt: "4c616469657320616e642047656e746c656d656e206f662074686520636c617373\
206f6620273939",
ct_tag: "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63\
dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b369\
2ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3\
ff4def08e4b7a9de576d26586cec64b6116",
},
];
use crate::{aead, capabilities, hash, kdf, kem, mac, self_test};
// ──────────────────────────────────────────────────────────────────────────────
// WolfSslProvider
@ -220,15 +177,7 @@ impl CryptoProvider for WolfSslProvider {
}
fn self_test(&self) -> SelfTestReport {
let mut results: Vec<AlgoTestResult> = Vec::new();
// Run AEAD test vectors.
for v in AEAD_VECTORS {
let result = run_aead_vector(v);
results.push(result);
}
SelfTestReport::finalise("wolfssl", results)
self_test::run()
}
fn benchmark(&self) -> BenchmarkReport {
@ -236,48 +185,4 @@ impl CryptoProvider for WolfSslProvider {
}
}
// ──────────────────────────────────────────────────────────────────────────────
// Test vector runner
// ──────────────────────────────────────────────────────────────────────────────
fn run_aead_vector(v: &AeadVector) -> AlgoTestResult {
let test_name = format!("{} NIST/RFC vector", v.algo.name());
let decode = |hex: &str| -> Vec<u8> {
(0..hex.len())
.step_by(2)
.map(|i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap_or(0))
.collect()
};
let key = decode(v.key);
let nonce = decode(v.nonce);
let aad = decode(v.aad);
let pt = decode(v.pt);
let expected = decode(v.ct_tag);
match aead::encrypt(v.algo, &key, &nonce, &pt, &aad) {
Ok(ct_tag) if ct_tag == expected => AlgoTestResult {
algo_id: v.algo as u32,
algo_name: test_name,
passed: true,
error_message: None,
},
Ok(ct_tag) => AlgoTestResult {
algo_id: v.algo as u32,
algo_name: test_name.clone(),
passed: false,
error_message: Some(format!(
"output mismatch: got {} bytes, expected {} bytes",
ct_tag.len(),
expected.len()
)),
},
Err(e) => AlgoTestResult {
algo_id: v.algo as u32,
algo_name: test_name,
passed: false,
error_message: Some(e.to_string()),
},
}
}

View File

@ -0,0 +1,113 @@
//! Embedded NIST / RFC test vectors for the power-on self-test.
//!
//! These are checked at runtime by [`WolfSslProvider::self_test()`]; failures
//! gate the provider from being marked `available` in the capability catalog.
use ccc_crypto_core::{
algorithms::AeadAlgorithm,
types::{AlgoTestResult, SelfTestReport},
};
use crate::aead;
// ──────────────────────────────────────────────────────────────────────────────
// AEAD vectors
// ──────────────────────────────────────────────────────────────────────────────
struct AeadVector {
algo: AeadAlgorithm,
key: &'static str,
nonce: &'static str,
aad: &'static str,
pt: &'static str,
ct_tag: &'static str, // ciphertext || tag, hex-encoded
}
/// NIST SP 800-38D and RFC 8439 test vectors.
static AEAD_VECTORS: &[AeadVector] = &[
// ── AES-256-GCM: NIST SP 800-38D Test Case 16 ───────────────────────
// Key: feffe9...308308 × 2 (AES-256)
// Nonce: cafebabefacedbaddecaf888
// AAD: feedfacedeadbeeffeedfacedeadbeefabaddad2 (20 bytes)
// PT: d9313225...637b39 (60 bytes)
// ct_tag = ciphertext (60 bytes) || GHASH tag (16 bytes) = 76 bytes
AeadVector {
algo: AeadAlgorithm::AesGcm256,
key: "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
nonce: "cafebabefacedbaddecaf888",
aad: "feedfacedeadbeeffeedfacedeadbeefabaddad2",
pt: "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72\
1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
ct_tag: "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa\
8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662\
76fc6ece0f4e1768cddf8853bb2d551b",
},
// ── ChaCha20-Poly1305: RFC 8439 §2.8.2 ──────────────────────────────
// PT: "Ladies and Gentlemen of the class of '99" (40 bytes)
// ct_tag = ciphertext (40 bytes) || Poly1305 tag (16 bytes) = 56 bytes
AeadVector {
algo: AeadAlgorithm::ChaCha20Poly1305,
key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
nonce: "070000004041424344454647",
aad: "50515253c0c1c2c3c4c5c6c7",
pt: "4c616469657320616e642047656e746c656d656e206f662074686520636c617373\
206f6620273939",
ct_tag: "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d6\
3dbea45e8ca96712f180d4e9016c65a7dde15e3106075ebd",
},
];
// ──────────────────────────────────────────────────────────────────────────────
// Runner
// ──────────────────────────────────────────────────────────────────────────────
/// Run all embedded self-test vectors and return a [`SelfTestReport`].
pub(crate) fn run() -> SelfTestReport {
let mut results: Vec<AlgoTestResult> = Vec::new();
for v in AEAD_VECTORS {
results.push(run_aead_vector(v));
}
SelfTestReport::finalise("wolfssl", results)
}
fn run_aead_vector(v: &AeadVector) -> AlgoTestResult {
let test_name = format!("{} NIST/RFC vector", v.algo.name());
let decode = |hex: &str| -> Vec<u8> {
(0..hex.len())
.step_by(2)
.map(|i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap_or(0))
.collect()
};
let key = decode(v.key);
let nonce = decode(v.nonce);
let aad = decode(v.aad);
let pt = decode(v.pt);
let expected = decode(v.ct_tag);
match aead::encrypt(v.algo, &key, &nonce, &pt, &aad) {
Ok(ct_tag) if ct_tag == expected => AlgoTestResult {
algo_id: v.algo as u32,
algo_name: test_name,
passed: true,
error_message: None,
},
Ok(ct_tag) => AlgoTestResult {
algo_id: v.algo as u32,
algo_name: test_name.clone(),
passed: false,
error_message: Some(format!(
"output mismatch: got {} bytes, expected {} bytes",
ct_tag.len(),
expected.len()
)),
},
Err(e) => AlgoTestResult {
algo_id: v.algo as u32,
algo_name: test_name,
passed: false,
error_message: Some(e.to_string()),
},
}
}