Skip to main content

lib_q_core/providers/
aead_provider.rs

1//! AEAD stub provider (core only)
2//!
3//! [`LibQAeadStubProvider`] validates inputs then returns [`NotImplemented`](crate::error::Error::NotImplemented).
4//! Registry-backed AEAD lives in the `lib-q-aead` crate as `LibQAeadProvider`.
5
6#[cfg(feature = "alloc")]
7use alloc::{
8    string::ToString,
9    vec::Vec,
10};
11
12use crate::api::{
13    AeadOperations,
14    Algorithm,
15};
16use crate::error::Result;
17use crate::security::SecurityValidator;
18use crate::traits::{
19    AeadKey,
20    Nonce,
21};
22
23/// Stub AEAD provider bundled with `lib-q-core` (no algorithm implementations).
24///
25/// Use `lib_q_aead::LibQAeadProvider` or the `lib-q` crate’s `libq::aead::context()` for real AEAD.
26#[cfg(feature = "alloc")]
27#[derive(Clone)]
28pub struct LibQAeadStubProvider {
29    security_validator: SecurityValidator,
30}
31
32#[cfg(feature = "alloc")]
33impl LibQAeadStubProvider {
34    /// Create a new stub AEAD provider.
35    pub fn new() -> Result<Self> {
36        Ok(Self {
37            security_validator: SecurityValidator::new()?,
38        })
39    }
40}
41
42#[cfg(feature = "alloc")]
43impl AeadOperations for LibQAeadStubProvider {
44    fn encrypt(
45        &self,
46        algorithm: Algorithm,
47        key: &AeadKey,
48        nonce: &Nonce,
49        plaintext: &[u8],
50        associated_data: Option<&[u8]>,
51    ) -> Result<Vec<u8>> {
52        // Validate algorithm category
53        self.security_validator
54            .validate_algorithm_category(algorithm, crate::api::AlgorithmCategory::Aead)?;
55
56        // Validate key
57        self.security_validator
58            .validate_key_material(key.as_bytes())?;
59
60        // Validate nonce
61        self.security_validator.validate_nonce(nonce.as_bytes())?;
62
63        // Validate plaintext
64        self.security_validator.validate_aead_message(plaintext)?;
65
66        // Validate associated data if present
67        if let Some(ad) = associated_data {
68            self.security_validator.validate_aead_message(ad)?;
69        }
70
71        Err(crate::error::Error::NotImplemented {
72            feature: "AEAD — use `lib_q_aead::LibQAeadProvider`, `libq::aead::context()`, or `AeadContext::with_aead_operations`"
73                .to_string(),
74        })
75    }
76
77    fn decrypt(
78        &self,
79        algorithm: Algorithm,
80        key: &AeadKey,
81        nonce: &Nonce,
82        ciphertext: &[u8],
83        associated_data: Option<&[u8]>,
84    ) -> Result<Vec<u8>> {
85        // Validate algorithm category
86        self.security_validator
87            .validate_algorithm_category(algorithm, crate::api::AlgorithmCategory::Aead)?;
88
89        // Validate key
90        self.security_validator
91            .validate_key_material(key.as_bytes())?;
92
93        // Validate nonce
94        self.security_validator.validate_nonce(nonce.as_bytes())?;
95
96        // Validate ciphertext
97        self.security_validator
98            .validate_ciphertext(algorithm, ciphertext)?;
99
100        // Validate associated data if present
101        if let Some(ad) = associated_data {
102            self.security_validator.validate_aead_message(ad)?;
103        }
104
105        Err(crate::error::Error::NotImplemented {
106            feature: "AEAD — use `lib_q_aead::LibQAeadProvider`, `libq::aead::context()`, or `AeadContext::with_aead_operations`"
107                .to_string(),
108        })
109    }
110}
111
112#[cfg(test)]
113#[cfg(feature = "alloc")]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_aead_stub_provider_creation() {
119        let provider = LibQAeadStubProvider::new();
120        assert!(
121            provider.is_ok(),
122            "LibQAeadStubProvider should be created successfully"
123        );
124    }
125
126    #[test]
127    fn test_aead_stub_unsupported_algorithm() {
128        let provider = LibQAeadStubProvider::new().unwrap();
129        let key = AeadKey::new(vec![0u8; 32]);
130        let nonce = Nonce::new(vec![0u8; 16]);
131        let result = provider.encrypt(Algorithm::MlKem512, &key, &nonce, b"test", None);
132        assert!(
133            result.is_err(),
134            "Should return error for unsupported algorithm"
135        );
136
137        if let Err(crate::error::Error::InvalidAlgorithm { .. }) = result {
138            // Expected error type
139        } else {
140            panic!("Expected InvalidAlgorithm error");
141        }
142    }
143
144    #[test]
145    fn test_aead_stub_unregistered_aead_algorithm() {
146        let provider = LibQAeadStubProvider::new().unwrap();
147        // High-entropy material so validation reaches NotImplemented (repeating blocks fail earlier).
148        let key = AeadKey::new(vec![
149            0xA3, 0x17, 0x5B, 0xE2, 0x94, 0x0D, 0x68, 0xF1, 0x3C, 0x86, 0xD5, 0x4A, 0x72, 0xBE,
150            0x09, 0xC7, 0x58, 0xE4, 0x1F, 0x8B, 0xA0, 0x63, 0xD9, 0x2E, 0x7D, 0x45, 0xFB, 0x16,
151            0xCA, 0x30, 0x9E, 0x54,
152        ]);
153        let nonce = Nonce::new(vec![
154            0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x6F, 0x70, 0x81, 0x92, 0xA3, 0xB4, 0xC5, 0xD6, 0xE7,
155            0xF8, 0x09,
156        ]);
157
158        // Test Saturnin without feature flag
159        let result = provider.encrypt(Algorithm::Saturnin, &key, &nonce, b"test", None);
160        assert!(
161            result.is_err(),
162            "Should return error when feature flag is not enabled"
163        );
164
165        if let Err(crate::error::Error::NotImplemented { feature }) = result {
166            assert!(
167                feature.contains("LibQAeadProvider") || feature.contains("libq::aead::context"),
168                "Error should direct callers to lib-q-aead / libq::aead::context(): {feature}"
169            );
170        } else {
171            panic!("Expected NotImplemented error, got: {:?}", result);
172        }
173    }
174}