lum_ccc_rust/crates/ccc-crypto-wolfssl/src/provider.rs

251 lines
10 KiB
Rust

//! [`WolfSslProvider`] — the main provider struct implementing
//! [`CryptoProvider`] for the wolfSSL / wolfCrypt library.
//!
//! Capabilities are live-probed on first construction. Benchmark results
//! feed into the `efficiency_score` fields of [`ProviderCapabilities`].
use std::sync::OnceLock;
use zeroize::Zeroizing;
use ccc_crypto_core::{
algorithms::{AeadAlgorithm, HashAlgorithm, KdfAlgorithm, KemAlgorithm, MacAlgorithm},
capabilities::ProviderCapabilities,
error::CryptoError,
provider::{
AeadProvider, CryptoProvider, HashProvider, KdfProvider, KemProvider, MacProvider,
},
types::{AlgoTestResult, 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",
},
];
// ──────────────────────────────────────────────────────────────────────────────
// WolfSslProvider
// ──────────────────────────────────────────────────────────────────────────────
/// The wolfSSL / wolfCrypt crypto provider.
///
/// Constructed by [`crate::init()`] and registered into the global
/// [`ProviderRegistry`][ccc_crypto_core::registry::ProviderRegistry].
///
/// Capabilities and benchmark results are computed lazily on first access to
/// avoid slowing down startup if the provider is never queried.
pub struct WolfSslProvider {
/// Lazy-initialised capabilities + benchmark results.
caps: OnceLock<ProviderCapabilities>,
bench: OnceLock<BenchmarkReport>,
}
impl WolfSslProvider {
/// Create a new wolfSSL provider.
///
/// Does not run probes or benchmarks at construction time — those are
/// deferred to the first call to [`capabilities()`] / [`benchmark()`].
pub fn new() -> Self {
Self {
caps: OnceLock::new(),
bench: OnceLock::new(),
}
}
/// Return the cached benchmark report, running the benchmark if needed.
fn get_or_run_benchmark(&self) -> &BenchmarkReport {
self.bench.get_or_init(|| {
log::info!("[ccc-crypto-wolfssl] running throughput benchmark…");
let report = capabilities::run_benchmark();
log::info!("[ccc-crypto-wolfssl] benchmark complete ({} algos)", report.results.len());
report
})
}
}
impl Default for WolfSslProvider {
fn default() -> Self { Self::new() }
}
// ──────────────────────────────────────────────────────────────────────────────
// Primitive trait implementations — thin delegation to module functions
// ──────────────────────────────────────────────────────────────────────────────
impl AeadProvider for WolfSslProvider {
fn encrypt_aead(
&self, algo: AeadAlgorithm, key: &[u8], nonce: &[u8],
plaintext: &[u8], aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
aead::encrypt(algo, key, nonce, plaintext, aad)
}
fn decrypt_aead(
&self, algo: AeadAlgorithm, key: &[u8], nonce: &[u8],
ciphertext_and_tag: &[u8], aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
aead::decrypt(algo, key, nonce, ciphertext_and_tag, aad)
}
}
impl KdfProvider for WolfSslProvider {
fn derive_key(
&self, algo: KdfAlgorithm, ikm: &[u8], salt: &[u8], info: &[u8], length: usize,
) -> Result<Zeroizing<Vec<u8>>, CryptoError> {
kdf::derive_key(algo, ikm, salt, info, length)
}
}
impl MacProvider for WolfSslProvider {
fn compute_mac(
&self, algo: MacAlgorithm, key: &[u8], data: &[u8],
) -> Result<Vec<u8>, CryptoError> {
mac::compute_mac(algo, key, data)
}
fn verify_mac(
&self, algo: MacAlgorithm, key: &[u8], data: &[u8], mac_bytes: &[u8],
) -> Result<bool, CryptoError> {
mac::verify_mac(algo, key, data, mac_bytes)
}
}
impl HashProvider for WolfSslProvider {
fn hash(&self, algo: HashAlgorithm, data: &[u8]) -> Result<Vec<u8>, CryptoError> {
hash::hash(algo, data)
}
}
/// `WolfSslProvider` also implements `KemProvider` but it is not part of the
/// `CryptoProvider` supertrait. Bridge functions call it directly.
impl KemProvider for WolfSslProvider {
fn generate_keypair(&self, algo: KemAlgorithm) -> Result<KemKeyPair, CryptoError> {
kem::generate_keypair(algo)
}
fn encapsulate(
&self, algo: KemAlgorithm, public_key: &[u8],
) -> Result<KemEncapResult, CryptoError> {
kem::encapsulate(algo, public_key)
}
fn decapsulate(
&self, algo: KemAlgorithm, private_key: &[u8], ciphertext: &[u8],
) -> Result<Zeroizing<Vec<u8>>, CryptoError> {
kem::decapsulate(algo, private_key, ciphertext)
}
}
// ──────────────────────────────────────────────────────────────────────────────
// CryptoProvider umbrella impl
// ──────────────────────────────────────────────────────────────────────────────
impl CryptoProvider for WolfSslProvider {
fn provider_name(&self) -> &'static str { "wolfssl" }
fn capabilities(&self) -> ProviderCapabilities {
self.caps.get_or_init(|| {
let bench = self.get_or_run_benchmark();
capabilities::probe_capabilities(Some(bench))
}).clone()
}
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)
}
fn benchmark(&self) -> BenchmarkReport {
self.get_or_run_benchmark().clone()
}
}
// ──────────────────────────────────────────────────────────────────────────────
// 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()),
},
}
}