use aes::{Aes128, Aes192, Aes256};
use cbc::cipher::block_padding::Pkcs7;
use cbc::cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit};
use cbc::{Decryptor, Encryptor};
use js::context::JSContext;
use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::KeyUsage;
use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::root::DomRoot;
use crate::dom::cryptokey::{CryptoKey, Handle};
use crate::dom::globalscope::GlobalScope;
use crate::dom::subtlecrypto::aes_common::AesAlgorithm;
use crate::dom::subtlecrypto::{
ExportedKey, SubtleAesCbcParams, SubtleAesDerivedKeyParams, SubtleAesKeyGenParams, aes_common,
};
pub(crate) fn encrypt(
normalized_algorithm: &SubtleAesCbcParams,
key: &CryptoKey,
plaintext: &[u8],
) -> Result<Vec<u8>, Error> {
if normalized_algorithm.iv.len() != 16 {
return Err(Error::Operation(Some(
"The initialization vector length is not 16 bytes".into(),
)));
}
let iv = normalized_algorithm
.iv
.as_slice()
.try_into()
.map_err(|_| Error::Operation(Some("Invalid AES-CBC IV".into())))?;
let ciphertext = match key.handle() {
Handle::Aes128Key(key) => {
let encryptor = Encryptor::<Aes128>::new(key, &iv);
encryptor.encrypt_padded_vec::<Pkcs7>(plaintext)
},
Handle::Aes192Key(key) => {
let encryptor = Encryptor::<Aes192>::new(key, &iv);
encryptor.encrypt_padded_vec::<Pkcs7>(plaintext)
},
Handle::Aes256Key(key) => {
let encryptor = Encryptor::<Aes256>::new(key, &iv);
encryptor.encrypt_padded_vec::<Pkcs7>(plaintext)
},
_ => {
return Err(Error::Operation(Some(
"The key handle is not representing an AES key".to_string(),
)));
},
};
Ok(ciphertext)
}
pub(crate) fn decrypt(
normalized_algorithm: &SubtleAesCbcParams,
key: &CryptoKey,
ciphertext: &[u8],
) -> Result<Vec<u8>, Error> {
if normalized_algorithm.iv.len() != 16 {
return Err(Error::Operation(Some(
"The initialization vector length is not 16 bytes".into(),
)));
}
if ciphertext.is_empty() {
return Err(Error::Operation(Some("The ciphertext is empty".into())));
}
if !ciphertext.len().is_multiple_of(16) {
return Err(Error::Operation(Some(
"The ciphertext length is not a multiple of 16 bytes".into(),
)));
}
let iv = normalized_algorithm
.iv
.as_slice()
.try_into()
.map_err(|_| Error::Operation(Some("Invalid AES-CBC IV".into())))?;
let plaintext = match key.handle() {
Handle::Aes128Key(key) => {
let decryptor = Decryptor::<Aes128>::new(key, &iv);
decryptor.decrypt_padded_vec::<Pkcs7>(ciphertext)
},
Handle::Aes192Key(key) => {
let decryptor = Decryptor::<Aes192>::new(key, &iv);
decryptor.decrypt_padded_vec::<Pkcs7>(ciphertext)
},
Handle::Aes256Key(key) => {
let decryptor = Decryptor::<Aes256>::new(key, &iv);
decryptor.decrypt_padded_vec::<Pkcs7>(ciphertext)
},
_ => {
return Err(Error::Operation(Some(
"The key handle is not representing an AES key".to_string(),
)));
},
}
.map_err(|_| Error::Operation(Some("Failed to perform AES-CBC decryption".into())))?;
Ok(plaintext)
}
pub(crate) fn generate_key(
cx: &mut JSContext,
global: &GlobalScope,
normalized_algorithm: &SubtleAesKeyGenParams,
extractable: bool,
usages: Vec<KeyUsage>,
) -> Result<DomRoot<CryptoKey>, Error> {
aes_common::generate_key(
AesAlgorithm::AesCbc,
cx,
global,
normalized_algorithm,
extractable,
usages,
)
}
pub(crate) fn import_key(
cx: &mut JSContext,
global: &GlobalScope,
format: KeyFormat,
key_data: &[u8],
extractable: bool,
usages: Vec<KeyUsage>,
) -> Result<DomRoot<CryptoKey>, Error> {
aes_common::import_key(
AesAlgorithm::AesCbc,
cx,
global,
format,
key_data,
extractable,
usages,
)
}
pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
aes_common::export_key(AesAlgorithm::AesCbc, format, key)
}
pub(crate) fn get_key_length(
normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
) -> Result<Option<u32>, Error> {
aes_common::get_key_length(normalized_derived_key_algorithm)
}