//! [`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, bench: OnceLock, } 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, 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, 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>, CryptoError> { kdf::derive_key(algo, ikm, salt, info, length) } } impl MacProvider for WolfSslProvider { fn compute_mac( &self, algo: MacAlgorithm, key: &[u8], data: &[u8], ) -> Result, CryptoError> { mac::compute_mac(algo, key, data) } fn verify_mac( &self, algo: MacAlgorithm, key: &[u8], data: &[u8], mac_bytes: &[u8], ) -> Result { mac::verify_mac(algo, key, data, mac_bytes) } } impl HashProvider for WolfSslProvider { fn hash(&self, algo: HashAlgorithm, data: &[u8]) -> Result, 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 { kem::generate_keypair(algo) } fn encapsulate( &self, algo: KemAlgorithm, public_key: &[u8], ) -> Result { kem::encapsulate(algo, public_key) } fn decapsulate( &self, algo: KemAlgorithm, private_key: &[u8], ciphertext: &[u8], ) -> Result>, 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 = 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 { (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()), }, } }