From cc72bb89194e499ef489b1c53ae124bb16c2d956 Mon Sep 17 00:00:00 2001 From: JohnE Date: Wed, 11 Mar 2026 21:33:48 -0700 Subject: [PATCH] FIX: test data was not accurate for AEAD --- crates/ccc-crypto-wolfssl/src/provider.rs | 101 +----------------- crates/ccc-crypto-wolfssl/src/self_test.rs | 113 +++++++++++++++++++++ 2 files changed, 116 insertions(+), 98 deletions(-) create mode 100644 crates/ccc-crypto-wolfssl/src/self_test.rs diff --git a/crates/ccc-crypto-wolfssl/src/provider.rs b/crates/ccc-crypto-wolfssl/src/provider.rs index fb634d2..7221c7f 100644 --- a/crates/ccc-crypto-wolfssl/src/provider.rs +++ b/crates/ccc-crypto-wolfssl/src/provider.rs @@ -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 = 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 { - (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()), - }, - } -} diff --git a/crates/ccc-crypto-wolfssl/src/self_test.rs b/crates/ccc-crypto-wolfssl/src/self_test.rs new file mode 100644 index 0000000..eb0b8fe --- /dev/null +++ b/crates/ccc-crypto-wolfssl/src/self_test.rs @@ -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 = 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 { + (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()), + }, + } +}