Skip to main content

lib_q_core/wasm/
secure_contexts.rs

1//! Secure WASM Contexts
2//!
3//! This module provides secure, production-ready WASM contexts that implement
4//! proper error handling, security validation, and consistent API design.
5//!
6//! These contexts provide a unified interface for post-quantum cryptographic
7//! operations in WebAssembly environments with comprehensive security validation
8//! and protection against common attack vectors.
9
10#[cfg(feature = "wasm")]
11extern crate alloc;
12#[cfg(feature = "wasm")]
13use alloc::boxed::Box;
14
15#[cfg(feature = "wasm")]
16use js_sys::Uint8Array;
17#[cfg(feature = "wasm")]
18use wasm_bindgen::prelude::*;
19
20use crate::api::{
21    // Algorithm,
22    AlgorithmCategory,
23};
24use crate::contexts::{
25    AeadContext,
26    HashContext,
27    KemContext,
28    SignatureContext,
29};
30// use crate::error::Result;
31use crate::providers::LibQCryptoProvider;
32use crate::security::SecurityValidator;
33use crate::traits::{
34    AeadKey,
35    Nonce,
36    // SigPublicKey,
37};
38use crate::wasm::conversions::WASM_SIGNATURE_ALGORITHM_IDS;
39use crate::wasm::error::{
40    convert_result,
41    // error_to_js_value,
42    parse_algorithm_wasm,
43    secure_serialize,
44};
45
46/// Secure WASM KEM Context
47///
48/// This context provides secure KEM operations with:
49/// - Consistent error handling using Result<T, JsValue>
50/// - Security validation for all inputs
51/// - Protection against timing attacks
52/// - Memory safety with automatic cleanup
53#[cfg_attr(feature = "wasm", wasm_bindgen)]
54pub struct SecureWasmKemContext {
55    inner: KemContext,
56    security_validator: SecurityValidator,
57}
58
59#[cfg_attr(feature = "wasm", wasm_bindgen)]
60impl SecureWasmKemContext {
61    /// Create a new secure WASM KEM context
62    #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
63    pub fn new() -> Result<SecureWasmKemContext, JsValue> {
64        let provider = Box::new(LibQCryptoProvider::new()?);
65        let inner = KemContext::with_provider(provider);
66        let security_validator = SecurityValidator::new()?;
67
68        Ok(SecureWasmKemContext {
69            inner,
70            security_validator,
71        })
72    }
73
74    /// Generate a KEM keypair
75    pub fn generate_keypair(
76        &mut self,
77        algorithm: &str,
78        randomness: Option<Uint8Array>,
79    ) -> Result<JsValue, JsValue> {
80        // Parse and validate algorithm
81        let algorithm = parse_algorithm_wasm(algorithm)?;
82
83        // Validate algorithm category
84        match convert_result(
85            self.security_validator
86                .validate_algorithm_category(algorithm, AlgorithmCategory::Kem),
87        ) {
88            Ok(_) => {}
89            Err(error) => return Err(error),
90        }
91
92        // Convert randomness if provided
93        let randomness_bytes = randomness.map(|rand| rand.to_vec());
94
95        // Generate keypair
96        let keypair = convert_result(
97            self.inner
98                .generate_keypair(algorithm, randomness_bytes.as_deref()),
99        )?;
100
101        // Serialize and return
102        match secure_serialize(&keypair) {
103            Ok(value) => Ok(value),
104            Err(error) => Err(error),
105        }
106    }
107
108    /// Encapsulate a shared secret
109    pub fn encapsulate(
110        &self,
111        algorithm: &str,
112        public_key: &Uint8Array,
113        randomness: Option<Uint8Array>,
114    ) -> Result<JsValue, JsValue> {
115        // Parse and validate algorithm
116        let algorithm = parse_algorithm_wasm(algorithm)?;
117
118        // Validate algorithm category
119        match convert_result(
120            self.security_validator
121                .validate_algorithm_category(algorithm, AlgorithmCategory::Kem),
122        ) {
123            Ok(_) => {}
124            Err(error) => return Err(error),
125        }
126
127        // Convert inputs
128        let public_key_bytes = public_key.to_vec();
129        let randomness_bytes = randomness.map(|rand| rand.to_vec());
130
131        // Validate key size
132        match convert_result(self.security_validator.validate_key_size(
133            algorithm,
134            &public_key_bytes,
135            false,
136        )) {
137            Ok(_) => {}
138            Err(error) => return Err(error),
139        }
140
141        // Create proper key type
142        let public_key = crate::traits::KemPublicKey::new(public_key_bytes.to_vec());
143
144        // Encapsulate
145        let result = convert_result(self.inner.encapsulate(
146            algorithm,
147            &public_key,
148            randomness_bytes.as_deref(),
149        ))?;
150
151        // Serialize and return
152        match secure_serialize(&result) {
153            Ok(value) => Ok(value),
154            Err(error) => Err(error),
155        }
156    }
157
158    /// Decapsulate a shared secret
159    pub fn decapsulate(
160        &self,
161        algorithm: &str,
162        private_key: &Uint8Array,
163        ciphertext: &Uint8Array,
164    ) -> Result<JsValue, JsValue> {
165        // Parse and validate algorithm
166        let algorithm = parse_algorithm_wasm(algorithm)?;
167
168        // Validate algorithm category
169        match convert_result(
170            self.security_validator
171                .validate_algorithm_category(algorithm, AlgorithmCategory::Kem),
172        ) {
173            Ok(_) => {}
174            Err(error) => return Err(error),
175        }
176
177        // Convert inputs
178        let private_key_bytes = private_key.to_vec();
179        let ciphertext_bytes = ciphertext.to_vec();
180
181        // Validate key size
182        match convert_result(self.security_validator.validate_key_size(
183            algorithm,
184            &private_key_bytes,
185            true,
186        )) {
187            Ok(_) => {}
188            Err(error) => return Err(error),
189        }
190
191        // Create proper key type
192        let secret_key = crate::traits::KemSecretKey::new(private_key_bytes.to_vec());
193
194        // Decapsulate
195        let result = convert_result(self.inner.decapsulate(
196            algorithm,
197            &secret_key,
198            &ciphertext_bytes,
199        ))?;
200
201        // Serialize and return
202        match secure_serialize(&result) {
203            Ok(value) => Ok(value),
204            Err(error) => Err(error),
205        }
206    }
207
208    /// Get supported algorithms
209    pub fn get_supported_algorithms(&self) -> Result<JsValue, JsValue> {
210        let algorithms = alloc::vec!["ml-kem-512", "ml-kem-768", "ml-kem-1024"];
211        match secure_serialize(&algorithms) {
212            Ok(value) => Ok(value),
213            Err(error) => Err(error),
214        }
215    }
216}
217
218/// Secure WASM Signature Context
219///
220/// This context provides secure signature operations with:
221/// - Consistent error handling using Result<T, JsValue>
222/// - Security validation for all inputs
223/// - Protection against timing attacks
224/// - Memory safety with automatic cleanup
225#[cfg_attr(feature = "wasm", wasm_bindgen)]
226pub struct SecureWasmSignatureContext {
227    inner: SignatureContext,
228    security_validator: SecurityValidator,
229}
230
231#[cfg_attr(feature = "wasm", wasm_bindgen)]
232impl SecureWasmSignatureContext {
233    /// Create a new secure WASM signature context
234    #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
235    pub fn new() -> Result<SecureWasmSignatureContext, JsValue> {
236        let provider = Box::new(LibQCryptoProvider::new()?);
237        let inner = SignatureContext::with_provider(provider);
238        let security_validator = SecurityValidator::new()?;
239
240        Ok(SecureWasmSignatureContext {
241            inner,
242            security_validator,
243        })
244    }
245
246    /// Generate a signature keypair
247    pub fn generate_keypair(
248        &mut self,
249        algorithm: &str,
250        randomness: Option<Uint8Array>,
251    ) -> Result<JsValue, JsValue> {
252        // Parse and validate algorithm
253        let algorithm = parse_algorithm_wasm(algorithm)?;
254
255        // Validate algorithm category
256        match convert_result(
257            self.security_validator
258                .validate_algorithm_category(algorithm, AlgorithmCategory::Signature),
259        ) {
260            Ok(_) => {}
261            Err(error) => return Err(error),
262        }
263
264        // Convert randomness if provided
265        let randomness_bytes = randomness.map(|rand| rand.to_vec());
266
267        // Generate keypair
268        let keypair = convert_result(
269            self.inner
270                .generate_keypair(algorithm, randomness_bytes.as_deref()),
271        )?;
272
273        // Serialize and return
274        match secure_serialize(&keypair) {
275            Ok(value) => Ok(value),
276            Err(error) => Err(error),
277        }
278    }
279
280    /// Sign a message
281    pub fn sign(
282        &self,
283        algorithm: &str,
284        private_key: &Uint8Array,
285        message: &Uint8Array,
286        randomness: Option<Uint8Array>,
287    ) -> Result<JsValue, JsValue> {
288        // Parse and validate algorithm
289        let algorithm = parse_algorithm_wasm(algorithm)?;
290
291        // Validate algorithm category
292        match convert_result(
293            self.security_validator
294                .validate_algorithm_category(algorithm, AlgorithmCategory::Signature),
295        ) {
296            Ok(_) => {}
297            Err(error) => return Err(error),
298        }
299
300        // Convert inputs
301        let private_key_bytes = private_key.to_vec();
302        let message_bytes = message.to_vec();
303        let randomness_bytes = randomness.map(|rand| rand.to_vec());
304
305        // Validate key size
306        match convert_result(self.security_validator.validate_key_size(
307            algorithm,
308            &private_key_bytes,
309            true,
310        )) {
311            Ok(_) => {}
312            Err(error) => return Err(error),
313        }
314
315        // Validate message size
316        match convert_result(
317            self.security_validator
318                .validate_signature_message(&message_bytes),
319        ) {
320            Ok(_) => {}
321            Err(error) => return Err(error),
322        }
323
324        // Create proper key type
325        let secret_key = crate::traits::SigSecretKey::new(private_key_bytes.to_vec());
326
327        // Sign
328        let signature = convert_result(self.inner.sign(
329            algorithm,
330            &secret_key,
331            &message_bytes,
332            randomness_bytes.as_deref(),
333        ))?;
334
335        // Serialize and return
336        match secure_serialize(&signature) {
337            Ok(value) => Ok(value),
338            Err(error) => Err(error),
339        }
340    }
341
342    /// Verify a signature
343    pub fn verify(
344        &self,
345        algorithm: &str,
346        public_key: &Uint8Array,
347        message: &Uint8Array,
348        signature: &Uint8Array,
349    ) -> Result<JsValue, JsValue> {
350        // Parse and validate algorithm
351        let algorithm = parse_algorithm_wasm(algorithm)?;
352
353        // Validate algorithm category
354        match convert_result(
355            self.security_validator
356                .validate_algorithm_category(algorithm, AlgorithmCategory::Signature),
357        ) {
358            Ok(_) => {}
359            Err(error) => return Err(error),
360        }
361
362        // Convert inputs
363        let public_key_bytes = public_key.to_vec();
364        let message_bytes = message.to_vec();
365        let signature_bytes = signature.to_vec();
366
367        // Validate key size
368        match convert_result(self.security_validator.validate_key_size(
369            algorithm,
370            &public_key_bytes,
371            false,
372        )) {
373            Ok(_) => {}
374            Err(error) => return Err(error),
375        }
376
377        // Validate message size
378        match convert_result(
379            self.security_validator
380                .validate_signature_message(&message_bytes),
381        ) {
382            Ok(_) => {}
383            Err(error) => return Err(error),
384        }
385
386        // Create proper key type
387        let public_key = crate::traits::SigPublicKey::new(public_key_bytes.to_vec());
388
389        // Verify
390        let is_valid = convert_result(self.inner.verify(
391            algorithm,
392            &public_key,
393            &message_bytes,
394            &signature_bytes,
395        ))?;
396
397        // Serialize and return
398        match secure_serialize(&is_valid) {
399            Ok(value) => Ok(value),
400            Err(error) => Err(error),
401        }
402    }
403
404    /// Get supported algorithms
405    pub fn get_supported_algorithms(&self) -> Result<JsValue, JsValue> {
406        match secure_serialize(&WASM_SIGNATURE_ALGORITHM_IDS) {
407            Ok(value) => Ok(value),
408            Err(error) => Err(error),
409        }
410    }
411}
412
413/// Secure WASM Hash Context
414///
415/// This context provides secure hash operations with:
416/// - Consistent error handling using Result<T, JsValue>
417/// - Security validation for all inputs
418/// - Protection against timing attacks
419/// - Memory safety with automatic cleanup
420#[cfg_attr(feature = "wasm", wasm_bindgen)]
421pub struct SecureWasmHashContext {
422    inner: HashContext,
423    security_validator: SecurityValidator,
424}
425
426#[cfg_attr(feature = "wasm", wasm_bindgen)]
427impl SecureWasmHashContext {
428    /// Create a new secure WASM hash context
429    #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
430    pub fn new() -> Result<SecureWasmHashContext, JsValue> {
431        let provider = Box::new(LibQCryptoProvider::new()?);
432        let inner = HashContext::with_provider(provider);
433        let security_validator = SecurityValidator::new()?;
434
435        Ok(SecureWasmHashContext {
436            inner,
437            security_validator,
438        })
439    }
440
441    /// Hash data
442    pub fn hash(&mut self, algorithm: &str, data: &Uint8Array) -> Result<JsValue, JsValue> {
443        // Parse and validate algorithm
444        let algorithm = parse_algorithm_wasm(algorithm)?;
445
446        // Validate algorithm category
447        match convert_result(
448            self.security_validator
449                .validate_algorithm_category(algorithm, AlgorithmCategory::Hash),
450        ) {
451            Ok(_) => {}
452            Err(error) => return Err(error),
453        }
454
455        // Convert inputs
456        let data_bytes = data.to_vec();
457
458        // Validate message size
459        match convert_result(self.security_validator.validate_hash_input(&data_bytes)) {
460            Ok(_) => {}
461            Err(error) => return Err(error),
462        }
463
464        // Hash
465        let hash = convert_result(self.inner.hash(algorithm, &data_bytes))?;
466
467        // Serialize and return
468        match secure_serialize(&hash) {
469            Ok(value) => Ok(value),
470            Err(error) => Err(error),
471        }
472    }
473
474    /// Get supported algorithms
475    pub fn get_supported_algorithms(&self) -> Result<JsValue, JsValue> {
476        let algorithms = alloc::vec![
477            "sha3-224", "sha3-256", "sha3-384", "sha3-512", "shake128", "shake256",
478        ];
479        match secure_serialize(&algorithms) {
480            Ok(value) => Ok(value),
481            Err(error) => Err(error),
482        }
483    }
484}
485
486/// Secure WASM AEAD Context
487///
488/// This context provides secure AEAD operations with:
489/// - Consistent error handling using Result<T, JsValue>
490/// - Security validation for all inputs
491/// - Protection against timing attacks
492/// - Memory safety with automatic cleanup
493#[cfg_attr(feature = "wasm", wasm_bindgen)]
494pub struct SecureWasmAeadContext {
495    inner: AeadContext,
496    security_validator: SecurityValidator,
497}
498
499#[cfg_attr(feature = "wasm", wasm_bindgen)]
500impl SecureWasmAeadContext {
501    /// Create a new secure WASM AEAD context
502    #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
503    pub fn new() -> Result<SecureWasmAeadContext, JsValue> {
504        let provider = Box::new(LibQCryptoProvider::new()?);
505        let inner = AeadContext::with_provider(provider);
506        let security_validator = SecurityValidator::new()?;
507
508        Ok(SecureWasmAeadContext {
509            inner,
510            security_validator,
511        })
512    }
513
514    /// Encrypt data
515    pub fn encrypt(
516        &mut self,
517        algorithm: &str,
518        key: &Uint8Array,
519        nonce: &Uint8Array,
520        plaintext: &Uint8Array,
521        associated_data: Option<Uint8Array>,
522    ) -> Result<JsValue, JsValue> {
523        // Parse and validate algorithm
524        let algorithm = parse_algorithm_wasm(algorithm)?;
525
526        // Validate algorithm category
527        match convert_result(
528            self.security_validator
529                .validate_algorithm_category(algorithm, AlgorithmCategory::Aead),
530        ) {
531            Ok(_) => {}
532            Err(error) => return Err(error),
533        }
534
535        // Convert inputs
536        let key_bytes = key.to_vec();
537        let nonce_bytes = nonce.to_vec();
538        let plaintext_bytes = plaintext.to_vec();
539        let associated_data_bytes = associated_data.map(|ad| ad.to_vec());
540
541        // Validate key size
542        match convert_result(
543            self.security_validator
544                .validate_key_size(algorithm, &key_bytes, true),
545        ) {
546            Ok(_) => {}
547            Err(error) => return Err(error),
548        }
549
550        // Validate nonce
551        match convert_result(self.security_validator.validate_nonce(&nonce_bytes)) {
552            Ok(_) => {}
553            Err(error) => return Err(error),
554        }
555
556        // Validate message size
557        match convert_result(
558            self.security_validator
559                .validate_aead_message(&plaintext_bytes),
560        ) {
561            Ok(_) => {}
562            Err(error) => return Err(error),
563        }
564
565        // Create key and nonce objects
566        let aead_key = AeadKey::new(key_bytes.to_vec());
567        let aead_nonce = Nonce::new(nonce_bytes.to_vec());
568
569        // Encrypt
570        let ciphertext = convert_result(self.inner.encrypt(
571            algorithm,
572            &aead_key,
573            &aead_nonce,
574            &plaintext_bytes,
575            associated_data_bytes.as_deref(),
576        ))?;
577
578        // Serialize and return
579        match secure_serialize(&ciphertext) {
580            Ok(value) => Ok(value),
581            Err(error) => Err(error),
582        }
583    }
584
585    /// Decrypt data (Layer A `Result` ABI only; see [`crate::AeadDecryptSemantic`] for Layer B).
586    pub fn decrypt(
587        &self,
588        algorithm: &str,
589        key: &Uint8Array,
590        nonce: &Uint8Array,
591        ciphertext: &Uint8Array,
592        associated_data: Option<Uint8Array>,
593    ) -> Result<JsValue, JsValue> {
594        // Parse and validate algorithm
595        let algorithm = parse_algorithm_wasm(algorithm)?;
596
597        // Validate algorithm category
598        match convert_result(
599            self.security_validator
600                .validate_algorithm_category(algorithm, AlgorithmCategory::Aead),
601        ) {
602            Ok(_) => {}
603            Err(error) => return Err(error),
604        }
605
606        // Convert inputs
607        let key_bytes = key.to_vec();
608        let nonce_bytes = nonce.to_vec();
609        let ciphertext_bytes = ciphertext.to_vec();
610        let associated_data_bytes = associated_data.map(|ad| ad.to_vec());
611
612        // Validate key size
613        match convert_result(
614            self.security_validator
615                .validate_key_size(algorithm, &key_bytes, true),
616        ) {
617            Ok(_) => {}
618            Err(error) => return Err(error),
619        }
620
621        // Validate nonce
622        match convert_result(self.security_validator.validate_nonce(&nonce_bytes)) {
623            Ok(_) => {}
624            Err(error) => return Err(error),
625        }
626
627        // Validate message size
628        match convert_result(
629            self.security_validator
630                .validate_aead_message(&ciphertext_bytes),
631        ) {
632            Ok(_) => {}
633            Err(error) => return Err(error),
634        }
635
636        // Create key and nonce objects
637        let aead_key = AeadKey::new(key_bytes.to_vec());
638        let aead_nonce = Nonce::new(nonce_bytes.to_vec());
639
640        // Decrypt
641        let plaintext = convert_result(self.inner.decrypt(
642            algorithm,
643            &aead_key,
644            &aead_nonce,
645            &ciphertext_bytes,
646            associated_data_bytes.as_deref(),
647        ))?;
648
649        // Serialize and return
650        match secure_serialize(&plaintext) {
651            Ok(value) => Ok(value),
652            Err(error) => Err(error),
653        }
654    }
655
656    /// Get supported algorithms
657    pub fn get_supported_algorithms(&self) -> Result<JsValue, JsValue> {
658        let algorithms = alloc::vec!["saturnin", "shake256-aead"];
659        match secure_serialize(&algorithms) {
660            Ok(value) => Ok(value),
661            Err(error) => Err(error),
662        }
663    }
664}