#![allow(non_upper_case_globals)]
#![allow(clippy::unused_unit)]
use crate::{
statics::{CoverCryptX25519Aes256, EncryptedHeader, PublicKey, UserSecretKey, DEM},
CoverCrypt,
};
use abe_policy::AccessPolicy;
use cosmian_crypto_core::{
bytes_ser_de::{Deserializer, Serializable, Serializer},
symmetric_crypto::{Dem, SymKey},
KeyTrait,
};
use js_sys::Uint8Array;
use wasm_bindgen::prelude::*;
pub const MAX_CLEAR_TEXT_SIZE: usize = 1 << 30;
#[wasm_bindgen]
pub fn webassembly_encrypt_hybrid_header(
policy_bytes: Vec<u8>,
access_policy: String,
public_key_bytes: Uint8Array,
header_metadata: Uint8Array,
authentication_data: Uint8Array,
) -> Result<Uint8Array, JsValue> {
let policy = serde_json::from_slice(&policy_bytes)
.map_err(|e| JsValue::from_str(&format!("Error deserializing policy: {e}")))?;
let access_policy = AccessPolicy::from_boolean_expression(&access_policy)
.map_err(|e| JsValue::from_str(&format!("Error reading access policy: {e}")))?;
let public_key = PublicKey::try_from_bytes(&public_key_bytes.to_vec())
.map_err(|e| JsValue::from_str(&format!("Error deserializing public key: {e}")))?;
let header_metadata = if header_metadata.is_null() {
None
} else {
Some(header_metadata.to_vec())
};
let authentication_data = if authentication_data.is_null() {
None
} else {
Some(authentication_data.to_vec())
};
let (symmetric_key, encrypted_header) = EncryptedHeader::generate(
&CoverCryptX25519Aes256::default(),
&policy,
&public_key,
&access_policy,
header_metadata.as_deref(),
authentication_data.as_deref(),
)
.map_err(|e| JsValue::from_str(&format!("Error encrypting header: {e}")))?;
let symmetric_key_bytes = symmetric_key.into_bytes();
let encrypted_header_bytes = encrypted_header
.try_to_bytes()
.map_err(|e| JsValue::from_str(&format!("Error serializing encrypted header: {e}")))?;
let mut res = Vec::with_capacity(symmetric_key_bytes.len() + encrypted_header_bytes.len());
res.extend_from_slice(&symmetric_key_bytes);
res.extend_from_slice(&encrypted_header_bytes);
Ok(Uint8Array::from(res.as_slice()))
}
#[wasm_bindgen]
pub fn webassembly_decrypt_hybrid_header(
usk_bytes: Uint8Array,
encrypted_header_bytes: Uint8Array,
authentication_data: Uint8Array,
) -> Result<Uint8Array, JsValue> {
let usk = UserSecretKey::try_from_bytes(usk_bytes.to_vec().as_slice())
.map_err(|e| JsValue::from_str(&format!("Error deserializing user decryption key: {e}")))?;
let authentication_data = if authentication_data.is_null() {
None
} else {
Some(authentication_data.to_vec())
};
let encrypted_header = EncryptedHeader::try_from_bytes(
encrypted_header_bytes.to_vec().as_slice(),
)
.map_err(|e| JsValue::from_str(&format!("Error deserializing encrypted header: {e}")))?;
let cleartext_header = encrypted_header
.decrypt(
&CoverCryptX25519Aes256::default(),
&usk,
authentication_data.as_deref(),
)
.map_err(|e| JsValue::from_str(&format!("Error decrypting hybrid header: {e}")))?;
Ok(Uint8Array::from(
cleartext_header
.try_to_bytes()
.map_err(|e| JsValue::from_str(&format!("Error serializing decrypted header: {e}")))?
.as_slice(),
))
}
#[wasm_bindgen]
pub fn webassembly_encrypt_symmetric_block(
symmetric_key_bytes: Uint8Array,
plaintext_bytes: Uint8Array,
authentication_data: Uint8Array,
) -> Result<Uint8Array, JsValue> {
if plaintext_bytes.length() == 0 {
return Err(JsValue::from_str("Plaintext value is empty"));
}
let symmetric_key =
<DEM as Dem<{ DEM::KEY_LENGTH }>>::Key::try_from_bytes(&symmetric_key_bytes.to_vec())
.map_err(|e| JsValue::from_str(&format!("Error parsing symmetric key: {e}")))?;
let authentication_data = if authentication_data.is_null() {
None
} else {
Some(authentication_data.to_vec())
};
let ciphertext = CoverCryptX25519Aes256::default()
.encrypt(
&symmetric_key,
&plaintext_bytes.to_vec(),
authentication_data.as_deref(),
)
.map_err(|e| JsValue::from_str(&format!("Error encrypting block: {e}")))?;
Ok(Uint8Array::from(&ciphertext[..]))
}
#[wasm_bindgen]
pub fn webassembly_decrypt_symmetric_block(
symmetric_key_bytes: Uint8Array,
encrypted_bytes: Uint8Array,
authentication_data: Uint8Array,
) -> Result<Uint8Array, JsValue> {
let symmetric_key =
<DEM as Dem<{ DEM::KEY_LENGTH }>>::Key::try_from_bytes(&symmetric_key_bytes.to_vec())
.map_err(|e| JsValue::from_str(&format!("Error parsing symmetric key: {e}")))?;
let authentication_data = if authentication_data.is_null() {
None
} else {
Some(authentication_data.to_vec())
};
let cleartext = CoverCryptX25519Aes256::default()
.decrypt(
&symmetric_key,
&encrypted_bytes.to_vec(),
authentication_data.as_deref(),
)
.map_err(|e| JsValue::from_str(&format!("Error decrypting block: {e}")))?;
Ok(Uint8Array::from(&cleartext[..]))
}
#[wasm_bindgen]
pub fn webassembly_hybrid_encrypt(
policy_bytes: Vec<u8>,
access_policy: String,
pk: Uint8Array,
plaintext: Uint8Array,
header_metadata: Uint8Array,
authentication_data: Uint8Array,
) -> Result<Uint8Array, JsValue> {
let policy = serde_json::from_slice(&policy_bytes)
.map_err(|e| JsValue::from_str(&format!("Error parsing policy: {e}")))?;
let access_policy = AccessPolicy::from_boolean_expression(&access_policy)
.map_err(|e| JsValue::from_str(&format!("Error reading access policy: {e}")))?;
let pk = PublicKey::try_from_bytes(&pk.to_vec())
.map_err(|e| JsValue::from_str(&format!("Error parsing public key: {e}")))?;
let header_metadata = if header_metadata.is_null() {
None
} else {
Some(header_metadata.to_vec())
};
let authentication_data = if authentication_data.is_null() {
None
} else {
Some(authentication_data.to_vec())
};
let cover_crypt = CoverCryptX25519Aes256::default();
let (symmetric_key, encrypted_header) = EncryptedHeader::generate(
&cover_crypt,
&policy,
&pk,
&access_policy,
header_metadata.as_deref(),
authentication_data.as_deref(),
)
.map_err(|e| JsValue::from_str(&format!("Error encrypting header: {e}")))?;
let ciphertext = cover_crypt
.encrypt(
&symmetric_key,
&plaintext.to_vec(),
authentication_data.as_deref(),
)
.map_err(|e| JsValue::from_str(&format!("Error encrypting symmetric plaintext: {e}")))?;
let mut ser = Serializer::with_capacity(encrypted_header.length() + ciphertext.len());
ser.write(&encrypted_header)
.map_err(|e| JsValue::from_str(&format!("Error serializing encrypted header: {e}")))?;
ser.write_array(&ciphertext)
.map_err(|e| JsValue::from_str(&format!("Error writing ciphertext: {e}")))?;
Ok(Uint8Array::from(ser.finalize().as_slice()))
}
#[wasm_bindgen]
pub fn webassembly_hybrid_decrypt(
usk_bytes: Uint8Array,
encrypted_bytes: Uint8Array,
authentication_data: Uint8Array,
) -> Result<Uint8Array, JsValue> {
let encrypted_bytes = encrypted_bytes.to_vec();
let mut de = Deserializer::new(&encrypted_bytes);
let header = de
.read::<EncryptedHeader>()
.map_err(|e| JsValue::from_str(&format!("Error parsing encrypted header: {e}")))?;
let ciphertext = de.finalize();
let usk = UserSecretKey::try_from_bytes(usk_bytes.to_vec().as_slice())
.map_err(|e| JsValue::from_str(&format!("Error parsing user secret key: {e}")))?;
let authentication_data = if authentication_data.is_null() {
None
} else {
Some(authentication_data.to_vec())
};
let cover_crypt = CoverCryptX25519Aes256::default();
let cleartext_header = header
.decrypt(&cover_crypt, &usk, authentication_data.as_deref())
.map_err(|e| JsValue::from_str(&format!("Error decrypting header: {e}")))?;
let cleartext = cover_crypt
.decrypt(
&cleartext_header.symmetric_key,
ciphertext.as_slice(),
authentication_data.as_deref(),
)
.map_err(|e| JsValue::from_str(&format!("Error decrypting ciphertext: {e}")))?;
let mut ser = Serializer::new();
ser.write_vec(cleartext_header.metadata.as_slice())
.map_err(|e| {
JsValue::from_str(&format!(
"Cannot serialize the decrypted header metadata into response : {e}"
))
})?;
ser.write_array(cleartext.as_slice()).map_err(|e| {
JsValue::from_str(&format!(
"Cannot serialize the decrypted plaintext into response : {e}"
))
})?;
Ok(Uint8Array::from(ser.finalize().as_slice()))
}