#[cfg(feature = "wasm")]
extern crate alloc;
#[cfg(feature = "wasm")]
use alloc::boxed::Box;
#[cfg(feature = "wasm")]
use js_sys::Uint8Array;
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;
use crate::api::{
AlgorithmCategory,
};
use crate::contexts::{
AeadContext,
HashContext,
KemContext,
SignatureContext,
};
use crate::providers::LibQCryptoProvider;
use crate::security::SecurityValidator;
use crate::traits::{
AeadKey,
Nonce,
};
use crate::wasm::conversions::WASM_SIGNATURE_ALGORITHM_IDS;
use crate::wasm::error::{
convert_result,
parse_algorithm_wasm,
secure_serialize,
};
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct SecureWasmKemContext {
inner: KemContext,
security_validator: SecurityValidator,
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl SecureWasmKemContext {
#[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
pub fn new() -> Result<SecureWasmKemContext, JsValue> {
let provider = Box::new(LibQCryptoProvider::new()?);
let inner = KemContext::with_provider(provider);
let security_validator = SecurityValidator::new()?;
Ok(SecureWasmKemContext {
inner,
security_validator,
})
}
pub fn generate_keypair(
&mut self,
algorithm: &str,
randomness: Option<Uint8Array>,
) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Kem),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let randomness_bytes = randomness.map(|rand| rand.to_vec());
let keypair = convert_result(
self.inner
.generate_keypair(algorithm, randomness_bytes.as_deref()),
)?;
match secure_serialize(&keypair) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn encapsulate(
&self,
algorithm: &str,
public_key: &Uint8Array,
randomness: Option<Uint8Array>,
) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Kem),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let public_key_bytes = public_key.to_vec();
let randomness_bytes = randomness.map(|rand| rand.to_vec());
match convert_result(self.security_validator.validate_key_size(
algorithm,
&public_key_bytes,
false,
)) {
Ok(_) => {}
Err(error) => return Err(error),
}
let public_key = crate::traits::KemPublicKey::new(public_key_bytes.to_vec());
let result = convert_result(self.inner.encapsulate(
algorithm,
&public_key,
randomness_bytes.as_deref(),
))?;
match secure_serialize(&result) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn decapsulate(
&self,
algorithm: &str,
private_key: &Uint8Array,
ciphertext: &Uint8Array,
) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Kem),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let private_key_bytes = private_key.to_vec();
let ciphertext_bytes = ciphertext.to_vec();
match convert_result(self.security_validator.validate_key_size(
algorithm,
&private_key_bytes,
true,
)) {
Ok(_) => {}
Err(error) => return Err(error),
}
let secret_key = crate::traits::KemSecretKey::new(private_key_bytes.to_vec());
let result = convert_result(self.inner.decapsulate(
algorithm,
&secret_key,
&ciphertext_bytes,
))?;
match secure_serialize(&result) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn get_supported_algorithms(&self) -> Result<JsValue, JsValue> {
let algorithms = alloc::vec!["ml-kem-512", "ml-kem-768", "ml-kem-1024"];
match secure_serialize(&algorithms) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct SecureWasmSignatureContext {
inner: SignatureContext,
security_validator: SecurityValidator,
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl SecureWasmSignatureContext {
#[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
pub fn new() -> Result<SecureWasmSignatureContext, JsValue> {
let provider = Box::new(LibQCryptoProvider::new()?);
let inner = SignatureContext::with_provider(provider);
let security_validator = SecurityValidator::new()?;
Ok(SecureWasmSignatureContext {
inner,
security_validator,
})
}
pub fn generate_keypair(
&mut self,
algorithm: &str,
randomness: Option<Uint8Array>,
) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Signature),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let randomness_bytes = randomness.map(|rand| rand.to_vec());
let keypair = convert_result(
self.inner
.generate_keypair(algorithm, randomness_bytes.as_deref()),
)?;
match secure_serialize(&keypair) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn sign(
&self,
algorithm: &str,
private_key: &Uint8Array,
message: &Uint8Array,
randomness: Option<Uint8Array>,
) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Signature),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let private_key_bytes = private_key.to_vec();
let message_bytes = message.to_vec();
let randomness_bytes = randomness.map(|rand| rand.to_vec());
match convert_result(self.security_validator.validate_key_size(
algorithm,
&private_key_bytes,
true,
)) {
Ok(_) => {}
Err(error) => return Err(error),
}
match convert_result(
self.security_validator
.validate_signature_message(&message_bytes),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let secret_key = crate::traits::SigSecretKey::new(private_key_bytes.to_vec());
let signature = convert_result(self.inner.sign(
algorithm,
&secret_key,
&message_bytes,
randomness_bytes.as_deref(),
))?;
match secure_serialize(&signature) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn verify(
&self,
algorithm: &str,
public_key: &Uint8Array,
message: &Uint8Array,
signature: &Uint8Array,
) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Signature),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let public_key_bytes = public_key.to_vec();
let message_bytes = message.to_vec();
let signature_bytes = signature.to_vec();
match convert_result(self.security_validator.validate_key_size(
algorithm,
&public_key_bytes,
false,
)) {
Ok(_) => {}
Err(error) => return Err(error),
}
match convert_result(
self.security_validator
.validate_signature_message(&message_bytes),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let public_key = crate::traits::SigPublicKey::new(public_key_bytes.to_vec());
let is_valid = convert_result(self.inner.verify(
algorithm,
&public_key,
&message_bytes,
&signature_bytes,
))?;
match secure_serialize(&is_valid) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn get_supported_algorithms(&self) -> Result<JsValue, JsValue> {
match secure_serialize(&WASM_SIGNATURE_ALGORITHM_IDS) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct SecureWasmHashContext {
inner: HashContext,
security_validator: SecurityValidator,
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl SecureWasmHashContext {
#[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
pub fn new() -> Result<SecureWasmHashContext, JsValue> {
let provider = Box::new(LibQCryptoProvider::new()?);
let inner = HashContext::with_provider(provider);
let security_validator = SecurityValidator::new()?;
Ok(SecureWasmHashContext {
inner,
security_validator,
})
}
pub fn hash(&mut self, algorithm: &str, data: &Uint8Array) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Hash),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let data_bytes = data.to_vec();
match convert_result(self.security_validator.validate_hash_input(&data_bytes)) {
Ok(_) => {}
Err(error) => return Err(error),
}
let hash = convert_result(self.inner.hash(algorithm, &data_bytes))?;
match secure_serialize(&hash) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn get_supported_algorithms(&self) -> Result<JsValue, JsValue> {
let algorithms = alloc::vec![
"sha3-224", "sha3-256", "sha3-384", "sha3-512", "shake128", "shake256",
];
match secure_serialize(&algorithms) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct SecureWasmAeadContext {
inner: AeadContext,
security_validator: SecurityValidator,
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl SecureWasmAeadContext {
#[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
pub fn new() -> Result<SecureWasmAeadContext, JsValue> {
let provider = Box::new(LibQCryptoProvider::new()?);
let inner = AeadContext::with_provider(provider);
let security_validator = SecurityValidator::new()?;
Ok(SecureWasmAeadContext {
inner,
security_validator,
})
}
pub fn encrypt(
&mut self,
algorithm: &str,
key: &Uint8Array,
nonce: &Uint8Array,
plaintext: &Uint8Array,
associated_data: Option<Uint8Array>,
) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Aead),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let key_bytes = key.to_vec();
let nonce_bytes = nonce.to_vec();
let plaintext_bytes = plaintext.to_vec();
let associated_data_bytes = associated_data.map(|ad| ad.to_vec());
match convert_result(
self.security_validator
.validate_key_size(algorithm, &key_bytes, true),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
match convert_result(self.security_validator.validate_nonce(&nonce_bytes)) {
Ok(_) => {}
Err(error) => return Err(error),
}
match convert_result(
self.security_validator
.validate_aead_message(&plaintext_bytes),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let aead_key = AeadKey::new(key_bytes.to_vec());
let aead_nonce = Nonce::new(nonce_bytes.to_vec());
let ciphertext = convert_result(self.inner.encrypt(
algorithm,
&aead_key,
&aead_nonce,
&plaintext_bytes,
associated_data_bytes.as_deref(),
))?;
match secure_serialize(&ciphertext) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn decrypt(
&self,
algorithm: &str,
key: &Uint8Array,
nonce: &Uint8Array,
ciphertext: &Uint8Array,
associated_data: Option<Uint8Array>,
) -> Result<JsValue, JsValue> {
let algorithm = parse_algorithm_wasm(algorithm)?;
match convert_result(
self.security_validator
.validate_algorithm_category(algorithm, AlgorithmCategory::Aead),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let key_bytes = key.to_vec();
let nonce_bytes = nonce.to_vec();
let ciphertext_bytes = ciphertext.to_vec();
let associated_data_bytes = associated_data.map(|ad| ad.to_vec());
match convert_result(
self.security_validator
.validate_key_size(algorithm, &key_bytes, true),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
match convert_result(self.security_validator.validate_nonce(&nonce_bytes)) {
Ok(_) => {}
Err(error) => return Err(error),
}
match convert_result(
self.security_validator
.validate_aead_message(&ciphertext_bytes),
) {
Ok(_) => {}
Err(error) => return Err(error),
}
let aead_key = AeadKey::new(key_bytes.to_vec());
let aead_nonce = Nonce::new(nonce_bytes.to_vec());
let plaintext = convert_result(self.inner.decrypt(
algorithm,
&aead_key,
&aead_nonce,
&ciphertext_bytes,
associated_data_bytes.as_deref(),
))?;
match secure_serialize(&plaintext) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
pub fn get_supported_algorithms(&self) -> Result<JsValue, JsValue> {
let algorithms = alloc::vec!["saturnin", "shake256-aead"];
match secure_serialize(&algorithms) {
Ok(value) => Ok(value),
Err(error) => Err(error),
}
}
}