Skip to main content

mabi_opcua/security/
crypto.rs

1//! Cryptographic operations for OPC UA security.
2//!
3//! Provides encryption, decryption, signing, and hashing operations
4//! using pluggable algorithm implementations.
5
6use std::sync::Arc;
7
8use serde::{Deserialize, Serialize};
9use thiserror::Error;
10use tracing::{debug, trace, warn};
11
12use crate::config::SecurityPolicy;
13use super::policy::SecurityPolicyConfig;
14
15/// Cryptographic error types.
16#[derive(Debug, Error)]
17pub enum CryptoError {
18    #[error("Encryption failed: {0}")]
19    EncryptionFailed(String),
20
21    #[error("Decryption failed: {0}")]
22    DecryptionFailed(String),
23
24    #[error("Signing failed: {0}")]
25    SigningFailed(String),
26
27    #[error("Verification failed: {0}")]
28    VerificationFailed(String),
29
30    #[error("Invalid key: {0}")]
31    InvalidKey(String),
32
33    #[error("Invalid data: {0}")]
34    InvalidData(String),
35
36    #[error("Unsupported algorithm: {0}")]
37    UnsupportedAlgorithm(String),
38
39    #[error("Key generation failed: {0}")]
40    KeyGenerationFailed(String),
41}
42
43/// Result type for cryptographic operations.
44pub type CryptoResult<T> = Result<T, CryptoError>;
45
46/// Symmetric encryption algorithm identifiers.
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
48pub enum SymmetricAlgorithm {
49    /// No encryption.
50    None,
51    /// AES-128-CBC.
52    Aes128Cbc,
53    /// AES-256-CBC.
54    Aes256Cbc,
55}
56
57impl SymmetricAlgorithm {
58    /// Get the key length in bytes.
59    pub fn key_length(&self) -> usize {
60        match self {
61            Self::None => 0,
62            Self::Aes128Cbc => 16,
63            Self::Aes256Cbc => 32,
64        }
65    }
66
67    /// Get the block size in bytes.
68    pub fn block_size(&self) -> usize {
69        match self {
70            Self::None => 0,
71            Self::Aes128Cbc | Self::Aes256Cbc => 16,
72        }
73    }
74
75    /// Get the IV length in bytes.
76    pub fn iv_length(&self) -> usize {
77        self.block_size()
78    }
79}
80
81/// Asymmetric encryption algorithm identifiers.
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
83pub enum AsymmetricAlgorithm {
84    /// No encryption.
85    None,
86    /// RSA PKCS#1 v1.5.
87    RsaPkcs1,
88    /// RSA OAEP with SHA-1.
89    RsaOaepSha1,
90    /// RSA OAEP with SHA-256.
91    RsaOaepSha256,
92    /// RSA PSS with SHA-256.
93    RsaPssSha256,
94}
95
96/// Hash algorithm identifiers.
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
98pub enum HashAlgorithm {
99    /// SHA-1 (deprecated).
100    Sha1,
101    /// SHA-256.
102    Sha256,
103    /// SHA-384.
104    Sha384,
105    /// SHA-512.
106    Sha512,
107}
108
109impl HashAlgorithm {
110    /// Get the output length in bytes.
111    pub fn output_length(&self) -> usize {
112        match self {
113            Self::Sha1 => 20,
114            Self::Sha256 => 32,
115            Self::Sha384 => 48,
116            Self::Sha512 => 64,
117        }
118    }
119}
120
121/// Result of an encryption operation.
122#[derive(Debug, Clone)]
123pub struct EncryptionResult {
124    /// Encrypted data.
125    pub ciphertext: Vec<u8>,
126    /// Initialization vector (for symmetric encryption).
127    pub iv: Option<Vec<u8>>,
128}
129
130/// Result of a decryption operation.
131#[derive(Debug, Clone)]
132pub struct DecryptionResult {
133    /// Decrypted plaintext.
134    pub plaintext: Vec<u8>,
135}
136
137/// Result of a signing operation.
138#[derive(Debug, Clone)]
139pub struct SignatureResult {
140    /// Digital signature.
141    pub signature: Vec<u8>,
142}
143
144/// Crypto provider configuration.
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct CryptoProviderConfig {
147    /// Enable hardware acceleration if available.
148    pub enable_hw_acceleration: bool,
149    /// Random number generator seed (for testing).
150    pub rng_seed: Option<u64>,
151}
152
153impl Default for CryptoProviderConfig {
154    fn default() -> Self {
155        Self {
156            enable_hw_acceleration: true,
157            rng_seed: None,
158        }
159    }
160}
161
162/// Key material for cryptographic operations.
163#[derive(Debug, Clone)]
164pub struct KeyMaterial {
165    /// Signing key.
166    pub signing_key: Vec<u8>,
167    /// Encryption key.
168    pub encrypting_key: Vec<u8>,
169    /// Initialization vector.
170    pub iv: Vec<u8>,
171}
172
173impl KeyMaterial {
174    /// Create empty key material.
175    pub fn empty() -> Self {
176        Self {
177            signing_key: Vec::new(),
178            encrypting_key: Vec::new(),
179            iv: Vec::new(),
180        }
181    }
182
183    /// Check if key material is valid for the given policy.
184    pub fn is_valid_for(&self, policy: &SecurityPolicyConfig) -> bool {
185        if policy.policy == SecurityPolicy::None {
186            return true;
187        }
188
189        self.signing_key.len() >= policy.derived_signature_key_length as usize
190            && self.encrypting_key.len() >= policy.symmetric_key_length as usize
191            && self.iv.len() >= policy.symmetric_block_size as usize
192    }
193}
194
195/// Cryptographic provider for OPC UA security operations.
196///
197/// This is a pluggable interface that can be backed by different
198/// cryptographic libraries (ring, openssl, etc.).
199pub struct CryptoProvider {
200    config: CryptoProviderConfig,
201    policy_config: SecurityPolicyConfig,
202}
203
204impl CryptoProvider {
205    /// Create a new crypto provider with default config.
206    pub fn new(policy: SecurityPolicy) -> Self {
207        Self {
208            config: CryptoProviderConfig::default(),
209            policy_config: SecurityPolicyConfig::for_policy(policy),
210        }
211    }
212
213    /// Create with custom config.
214    pub fn with_config(policy: SecurityPolicy, config: CryptoProviderConfig) -> Self {
215        Self {
216            config,
217            policy_config: SecurityPolicyConfig::for_policy(policy),
218        }
219    }
220
221    /// Get the security policy.
222    pub fn policy(&self) -> SecurityPolicy {
223        self.policy_config.policy
224    }
225
226    /// Get the policy configuration.
227    pub fn policy_config(&self) -> &SecurityPolicyConfig {
228        &self.policy_config
229    }
230
231    // =========================================================================
232    // Symmetric Operations
233    // =========================================================================
234
235    /// Encrypt data using symmetric encryption.
236    pub fn symmetric_encrypt(
237        &self,
238        plaintext: &[u8],
239        key: &[u8],
240        iv: &[u8],
241    ) -> CryptoResult<EncryptionResult> {
242        if self.policy_config.policy == SecurityPolicy::None {
243            return Ok(EncryptionResult {
244                ciphertext: plaintext.to_vec(),
245                iv: None,
246            });
247        }
248
249        // Validate key and IV lengths
250        let expected_key_len = self.policy_config.symmetric_key_length as usize;
251        let expected_iv_len = self.policy_config.symmetric_block_size as usize;
252
253        if key.len() != expected_key_len {
254            return Err(CryptoError::InvalidKey(format!(
255                "Expected key length {}, got {}",
256                expected_key_len,
257                key.len()
258            )));
259        }
260
261        if iv.len() != expected_iv_len {
262            return Err(CryptoError::InvalidData(format!(
263                "Expected IV length {}, got {}",
264                expected_iv_len,
265                iv.len()
266            )));
267        }
268
269        // Apply PKCS7 padding
270        let block_size = self.policy_config.symmetric_block_size as usize;
271        let padded = pkcs7_pad(plaintext, block_size);
272
273        // Simulate AES-CBC encryption
274        // In production, this would use a real crypto library
275        let ciphertext = simulate_aes_cbc_encrypt(&padded, key, iv);
276
277        trace!(
278            plaintext_len = plaintext.len(),
279            ciphertext_len = ciphertext.len(),
280            "Symmetric encryption completed"
281        );
282
283        Ok(EncryptionResult {
284            ciphertext,
285            iv: Some(iv.to_vec()),
286        })
287    }
288
289    /// Decrypt data using symmetric encryption.
290    pub fn symmetric_decrypt(
291        &self,
292        ciphertext: &[u8],
293        key: &[u8],
294        iv: &[u8],
295    ) -> CryptoResult<DecryptionResult> {
296        if self.policy_config.policy == SecurityPolicy::None {
297            return Ok(DecryptionResult {
298                plaintext: ciphertext.to_vec(),
299            });
300        }
301
302        // Validate inputs
303        let block_size = self.policy_config.symmetric_block_size as usize;
304        if ciphertext.len() % block_size != 0 {
305            return Err(CryptoError::InvalidData(
306                "Ciphertext length must be multiple of block size".to_string(),
307            ));
308        }
309
310        // Simulate AES-CBC decryption
311        let decrypted = simulate_aes_cbc_decrypt(ciphertext, key, iv);
312
313        // Remove PKCS7 padding
314        let plaintext = pkcs7_unpad(&decrypted)
315            .map_err(|e| CryptoError::DecryptionFailed(e))?;
316
317        trace!(
318            ciphertext_len = ciphertext.len(),
319            plaintext_len = plaintext.len(),
320            "Symmetric decryption completed"
321        );
322
323        Ok(DecryptionResult { plaintext })
324    }
325
326    // =========================================================================
327    // Asymmetric Operations
328    // =========================================================================
329
330    /// Encrypt data using asymmetric encryption (RSA).
331    pub fn asymmetric_encrypt(
332        &self,
333        plaintext: &[u8],
334        public_key: &[u8],
335    ) -> CryptoResult<EncryptionResult> {
336        if self.policy_config.policy == SecurityPolicy::None {
337            return Ok(EncryptionResult {
338                ciphertext: plaintext.to_vec(),
339                iv: None,
340            });
341        }
342
343        // Validate public key
344        if public_key.is_empty() {
345            return Err(CryptoError::InvalidKey("Empty public key".to_string()));
346        }
347
348        // Simulate RSA encryption
349        // In production, would use actual RSA implementation
350        let ciphertext = simulate_rsa_encrypt(plaintext, public_key);
351
352        debug!(
353            plaintext_len = plaintext.len(),
354            ciphertext_len = ciphertext.len(),
355            "Asymmetric encryption completed"
356        );
357
358        Ok(EncryptionResult {
359            ciphertext,
360            iv: None,
361        })
362    }
363
364    /// Decrypt data using asymmetric encryption (RSA).
365    pub fn asymmetric_decrypt(
366        &self,
367        ciphertext: &[u8],
368        private_key: &[u8],
369    ) -> CryptoResult<DecryptionResult> {
370        if self.policy_config.policy == SecurityPolicy::None {
371            return Ok(DecryptionResult {
372                plaintext: ciphertext.to_vec(),
373            });
374        }
375
376        // Validate private key
377        if private_key.is_empty() {
378            return Err(CryptoError::InvalidKey("Empty private key".to_string()));
379        }
380
381        // Simulate RSA decryption
382        let plaintext = simulate_rsa_decrypt(ciphertext, private_key);
383
384        debug!(
385            ciphertext_len = ciphertext.len(),
386            plaintext_len = plaintext.len(),
387            "Asymmetric decryption completed"
388        );
389
390        Ok(DecryptionResult { plaintext })
391    }
392
393    // =========================================================================
394    // Signing Operations
395    // =========================================================================
396
397    /// Sign data using HMAC (symmetric).
398    pub fn hmac_sign(&self, data: &[u8], key: &[u8]) -> CryptoResult<SignatureResult> {
399        if self.policy_config.policy == SecurityPolicy::None {
400            return Ok(SignatureResult {
401                signature: Vec::new(),
402            });
403        }
404
405        // Simulate HMAC-SHA256
406        let signature = simulate_hmac_sha256(data, key);
407
408        trace!(data_len = data.len(), sig_len = signature.len(), "HMAC sign completed");
409
410        Ok(SignatureResult { signature })
411    }
412
413    /// Verify HMAC signature.
414    pub fn hmac_verify(&self, data: &[u8], key: &[u8], signature: &[u8]) -> CryptoResult<bool> {
415        if self.policy_config.policy == SecurityPolicy::None {
416            return Ok(true);
417        }
418
419        let expected = simulate_hmac_sha256(data, key);
420        let valid = constant_time_compare(&expected, signature);
421
422        trace!(valid, "HMAC verify completed");
423
424        Ok(valid)
425    }
426
427    /// Sign data using RSA.
428    pub fn rsa_sign(&self, data: &[u8], private_key: &[u8]) -> CryptoResult<SignatureResult> {
429        if self.policy_config.policy == SecurityPolicy::None {
430            return Ok(SignatureResult {
431                signature: Vec::new(),
432            });
433        }
434
435        // Simulate RSA signature
436        let signature = simulate_rsa_sign(data, private_key);
437
438        debug!(data_len = data.len(), sig_len = signature.len(), "RSA sign completed");
439
440        Ok(SignatureResult { signature })
441    }
442
443    /// Verify RSA signature.
444    pub fn rsa_verify(
445        &self,
446        data: &[u8],
447        public_key: &[u8],
448        signature: &[u8],
449    ) -> CryptoResult<bool> {
450        if self.policy_config.policy == SecurityPolicy::None {
451            return Ok(true);
452        }
453
454        // Simulate RSA verification
455        let valid = simulate_rsa_verify(data, public_key, signature);
456
457        debug!(valid, "RSA verify completed");
458
459        Ok(valid)
460    }
461
462    // =========================================================================
463    // Hashing Operations
464    // =========================================================================
465
466    /// Compute hash of data.
467    pub fn hash(&self, algorithm: HashAlgorithm, data: &[u8]) -> Vec<u8> {
468        match algorithm {
469            HashAlgorithm::Sha1 => simulate_sha1(data),
470            HashAlgorithm::Sha256 => simulate_sha256(data),
471            HashAlgorithm::Sha384 => simulate_sha384(data),
472            HashAlgorithm::Sha512 => simulate_sha512(data),
473        }
474    }
475
476    /// Compute SHA-256 hash.
477    pub fn sha256(&self, data: &[u8]) -> Vec<u8> {
478        self.hash(HashAlgorithm::Sha256, data)
479    }
480
481    // =========================================================================
482    // Key Derivation
483    // =========================================================================
484
485    /// Derive keys from shared secret using P_SHA256.
486    pub fn derive_keys(
487        &self,
488        secret: &[u8],
489        seed: &[u8],
490        signing_key_length: usize,
491        encrypting_key_length: usize,
492        iv_length: usize,
493    ) -> CryptoResult<KeyMaterial> {
494        if self.policy_config.policy == SecurityPolicy::None {
495            return Ok(KeyMaterial::empty());
496        }
497
498        // Derive key material using P_SHA256
499        let total_length = signing_key_length + encrypting_key_length + iv_length;
500        let derived = p_sha256(secret, seed, total_length);
501
502        let signing_key = derived[..signing_key_length].to_vec();
503        let encrypting_key = derived[signing_key_length..signing_key_length + encrypting_key_length].to_vec();
504        let iv = derived[signing_key_length + encrypting_key_length..].to_vec();
505
506        debug!(
507            signing_key_len = signing_key.len(),
508            encrypting_key_len = encrypting_key.len(),
509            iv_len = iv.len(),
510            "Key derivation completed"
511        );
512
513        Ok(KeyMaterial {
514            signing_key,
515            encrypting_key,
516            iv,
517        })
518    }
519
520    // =========================================================================
521    // Random Number Generation
522    // =========================================================================
523
524    /// Generate random bytes.
525    pub fn random_bytes(&self, length: usize) -> Vec<u8> {
526        if let Some(seed) = self.config.rng_seed {
527            // Deterministic for testing
528            deterministic_random(seed, length)
529        } else {
530            // True random
531            secure_random(length)
532        }
533    }
534
535    /// Generate a random nonce.
536    pub fn generate_nonce(&self) -> Vec<u8> {
537        self.random_bytes(self.policy_config.secure_channel_nonce_length as usize)
538    }
539}
540
541// =========================================================================
542// Padding Functions
543// =========================================================================
544
545/// Apply PKCS7 padding.
546fn pkcs7_pad(data: &[u8], block_size: usize) -> Vec<u8> {
547    let padding_len = block_size - (data.len() % block_size);
548    let mut padded = data.to_vec();
549    padded.extend(std::iter::repeat(padding_len as u8).take(padding_len));
550    padded
551}
552
553/// Remove PKCS7 padding.
554fn pkcs7_unpad(data: &[u8]) -> Result<Vec<u8>, String> {
555    if data.is_empty() {
556        return Err("Empty data".to_string());
557    }
558
559    let padding_len = *data.last().unwrap() as usize;
560    if padding_len == 0 || padding_len > data.len() || padding_len > 16 {
561        return Err("Invalid padding".to_string());
562    }
563
564    // Verify padding bytes
565    for &byte in &data[data.len() - padding_len..] {
566        if byte != padding_len as u8 {
567            return Err("Invalid padding bytes".to_string());
568        }
569    }
570
571    Ok(data[..data.len() - padding_len].to_vec())
572}
573
574/// Constant-time comparison to prevent timing attacks.
575fn constant_time_compare(a: &[u8], b: &[u8]) -> bool {
576    if a.len() != b.len() {
577        return false;
578    }
579
580    let mut result = 0u8;
581    for (x, y) in a.iter().zip(b.iter()) {
582        result |= x ^ y;
583    }
584    result == 0
585}
586
587// =========================================================================
588// Simulation Functions (Replace with real crypto in production)
589// =========================================================================
590
591/// Simulate AES-CBC encryption.
592fn simulate_aes_cbc_encrypt(plaintext: &[u8], key: &[u8], iv: &[u8]) -> Vec<u8> {
593    // XOR-based simulation for structure (NOT SECURE - use real AES in production)
594    let mut ciphertext = Vec::with_capacity(plaintext.len());
595    let block_size = 16;
596
597    let mut prev_block = iv.to_vec();
598    for chunk in plaintext.chunks(block_size) {
599        let mut block = vec![0u8; block_size];
600        for (i, &byte) in chunk.iter().enumerate() {
601            block[i] = byte ^ prev_block[i] ^ key[i % key.len()];
602        }
603        prev_block = block.clone();
604        ciphertext.extend(block);
605    }
606
607    ciphertext
608}
609
610/// Simulate AES-CBC decryption.
611fn simulate_aes_cbc_decrypt(ciphertext: &[u8], key: &[u8], iv: &[u8]) -> Vec<u8> {
612    let mut plaintext = Vec::with_capacity(ciphertext.len());
613    let block_size = 16;
614
615    let mut prev_block = iv.to_vec();
616    for chunk in ciphertext.chunks(block_size) {
617        let mut block = vec![0u8; block_size];
618        for (i, &byte) in chunk.iter().enumerate() {
619            block[i] = byte ^ prev_block[i] ^ key[i % key.len()];
620        }
621        prev_block = chunk.to_vec();
622        plaintext.extend(block);
623    }
624
625    plaintext
626}
627
628/// Simulate RSA encryption.
629fn simulate_rsa_encrypt(plaintext: &[u8], public_key: &[u8]) -> Vec<u8> {
630    // Simple XOR simulation (NOT SECURE)
631    plaintext
632        .iter()
633        .enumerate()
634        .map(|(i, &b)| b ^ public_key[i % public_key.len()])
635        .collect()
636}
637
638/// Simulate RSA decryption.
639fn simulate_rsa_decrypt(ciphertext: &[u8], private_key: &[u8]) -> Vec<u8> {
640    // Simple XOR simulation (NOT SECURE)
641    ciphertext
642        .iter()
643        .enumerate()
644        .map(|(i, &b)| b ^ private_key[i % private_key.len()])
645        .collect()
646}
647
648/// Simulate HMAC-SHA256.
649fn simulate_hmac_sha256(data: &[u8], key: &[u8]) -> Vec<u8> {
650    // Simple hash simulation
651    let mut hash = vec![0u8; 32];
652    for (i, &b) in data.iter().enumerate() {
653        hash[i % 32] ^= b ^ key[i % key.len()];
654    }
655    hash
656}
657
658/// Simulate RSA signing.
659fn simulate_rsa_sign(data: &[u8], private_key: &[u8]) -> Vec<u8> {
660    simulate_hmac_sha256(data, private_key)
661}
662
663/// Simulate RSA verification.
664fn simulate_rsa_verify(data: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
665    let expected = simulate_hmac_sha256(data, public_key);
666    constant_time_compare(&expected, signature)
667}
668
669/// Simulate SHA-1.
670fn simulate_sha1(data: &[u8]) -> Vec<u8> {
671    let mut hash = vec![0u8; 20];
672    for (i, &b) in data.iter().enumerate() {
673        hash[i % 20] = hash[i % 20].wrapping_add(b);
674    }
675    hash
676}
677
678/// Simulate SHA-256.
679fn simulate_sha256(data: &[u8]) -> Vec<u8> {
680    let mut hash = vec![0u8; 32];
681    for (i, &b) in data.iter().enumerate() {
682        hash[i % 32] = hash[i % 32].wrapping_add(b);
683    }
684    hash
685}
686
687/// Simulate SHA-384.
688fn simulate_sha384(data: &[u8]) -> Vec<u8> {
689    let mut hash = vec![0u8; 48];
690    for (i, &b) in data.iter().enumerate() {
691        hash[i % 48] = hash[i % 48].wrapping_add(b);
692    }
693    hash
694}
695
696/// Simulate SHA-512.
697fn simulate_sha512(data: &[u8]) -> Vec<u8> {
698    let mut hash = vec![0u8; 64];
699    for (i, &b) in data.iter().enumerate() {
700        hash[i % 64] = hash[i % 64].wrapping_add(b);
701    }
702    hash
703}
704
705/// P_SHA256 key derivation function.
706fn p_sha256(secret: &[u8], seed: &[u8], length: usize) -> Vec<u8> {
707    let mut result = Vec::with_capacity(length);
708    let mut a = seed.to_vec();
709
710    while result.len() < length {
711        a = simulate_hmac_sha256(&a, secret);
712        let mut combined = a.clone();
713        combined.extend_from_slice(seed);
714        let p = simulate_hmac_sha256(&combined, secret);
715        result.extend(p);
716    }
717
718    result.truncate(length);
719    result
720}
721
722/// Generate deterministic random bytes for testing.
723fn deterministic_random(seed: u64, length: usize) -> Vec<u8> {
724    let mut bytes = Vec::with_capacity(length);
725    let mut state = seed;
726
727    for _ in 0..length {
728        state = state.wrapping_mul(6364136223846793005).wrapping_add(1);
729        bytes.push((state >> 56) as u8);
730    }
731
732    bytes
733}
734
735/// Generate secure random bytes.
736fn secure_random(length: usize) -> Vec<u8> {
737    use std::time::{SystemTime, UNIX_EPOCH};
738
739    let seed = SystemTime::now()
740        .duration_since(UNIX_EPOCH)
741        .unwrap()
742        .as_nanos() as u64;
743
744    deterministic_random(seed, length)
745}
746
747#[cfg(test)]
748mod tests {
749    use super::*;
750
751    #[test]
752    fn test_pkcs7_padding() {
753        let data = b"hello";
754        let padded = pkcs7_pad(data, 16);
755        assert_eq!(padded.len(), 16);
756        assert_eq!(padded[5..], [11u8; 11]);
757
758        let unpadded = pkcs7_unpad(&padded).unwrap();
759        assert_eq!(unpadded, data);
760    }
761
762    #[test]
763    fn test_symmetric_encrypt_decrypt() {
764        let provider = CryptoProvider::new(SecurityPolicy::Basic256Sha256);
765        let key = vec![0u8; 32];
766        let iv = vec![0u8; 16];
767        let plaintext = b"Hello, OPC UA!";
768
769        let encrypted = provider.symmetric_encrypt(plaintext, &key, &iv).unwrap();
770        let decrypted = provider.symmetric_decrypt(&encrypted.ciphertext, &key, &iv).unwrap();
771
772        assert_eq!(decrypted.plaintext, plaintext);
773    }
774
775    #[test]
776    fn test_none_policy_passthrough() {
777        let provider = CryptoProvider::new(SecurityPolicy::None);
778        let data = b"test data";
779        let key = vec![0u8; 32];
780        let iv = vec![0u8; 16];
781
782        let encrypted = provider.symmetric_encrypt(data, &key, &iv).unwrap();
783        assert_eq!(encrypted.ciphertext, data);
784
785        let decrypted = provider.symmetric_decrypt(data, &key, &iv).unwrap();
786        assert_eq!(decrypted.plaintext, data);
787    }
788
789    #[test]
790    fn test_hmac_sign_verify() {
791        let provider = CryptoProvider::new(SecurityPolicy::Basic256Sha256);
792        let key = vec![0xAB; 32];
793        let data = b"Message to sign";
794
795        let signature = provider.hmac_sign(data, &key).unwrap();
796        let valid = provider.hmac_verify(data, &key, &signature.signature).unwrap();
797
798        assert!(valid);
799    }
800
801    #[test]
802    fn test_key_derivation() {
803        let provider = CryptoProvider::new(SecurityPolicy::Basic256Sha256);
804        let secret = vec![0x42; 32];
805        let seed = vec![0x13; 32];
806
807        let keys = provider.derive_keys(&secret, &seed, 32, 32, 16).unwrap();
808
809        assert_eq!(keys.signing_key.len(), 32);
810        assert_eq!(keys.encrypting_key.len(), 32);
811        assert_eq!(keys.iv.len(), 16);
812    }
813
814    #[test]
815    fn test_nonce_generation() {
816        let provider = CryptoProvider::new(SecurityPolicy::Basic256Sha256);
817        let nonce = provider.generate_nonce();
818
819        assert_eq!(nonce.len(), 32);
820    }
821
822    #[test]
823    fn test_constant_time_compare() {
824        assert!(constant_time_compare(b"test", b"test"));
825        assert!(!constant_time_compare(b"test", b"Test"));
826        assert!(!constant_time_compare(b"test", b"testing"));
827    }
828}