1use crate::BSVErrors;
2use aes::{
3 cipher::{NewCipher, StreamCipher, StreamCipherSeek},
4 Aes128, Aes128Ctr, Aes256, Aes256Ctr,
5};
6use block_modes::{block_padding::Pkcs7, BlockMode, Cbc};
7#[cfg(target_arch = "wasm32")]
8use wasm_bindgen::{prelude::*, throw_str};
9
10#[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-encryption"), wasm_bindgen)]
11pub struct AES {}
12
13#[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-encryption"), wasm_bindgen)]
14#[allow(non_camel_case_types)]
15#[derive(Debug, Clone, Copy)]
16pub enum AESAlgorithms {
17 AES128_CBC,
18 AES256_CBC,
19 AES128_CTR,
20 AES256_CTR,
21}
22
23impl AES {
24 pub fn encrypt_impl(key: &[u8], iv: &[u8], message: &[u8], algo: AESAlgorithms) -> Result<Vec<u8>, BSVErrors> {
25 let result = match algo {
26 AESAlgorithms::AES128_CBC => Cbc::<Aes128, Pkcs7>::new_from_slices(key, iv)?.encrypt_vec(message),
27 AESAlgorithms::AES256_CBC => Cbc::<Aes256, Pkcs7>::new_from_slices(key, iv)?.encrypt_vec(message),
28 AESAlgorithms::AES128_CTR => AES::aes_ctr::<Aes128Ctr>(key, iv, message),
29 AESAlgorithms::AES256_CTR => AES::aes_ctr::<Aes256Ctr>(key, iv, message),
30 };
31
32 Ok(result)
33 }
34
35 pub fn decrypt_impl(key: &[u8], iv: &[u8], message: &[u8], algo: AESAlgorithms) -> Result<Vec<u8>, BSVErrors> {
36 let result = match algo {
37 AESAlgorithms::AES128_CBC => Cbc::<Aes128, Pkcs7>::new_from_slices(key, iv)?.decrypt_vec(message)?,
38 AESAlgorithms::AES256_CBC => Cbc::<Aes256, Pkcs7>::new_from_slices(key, iv)?.decrypt_vec(message)?,
39 AESAlgorithms::AES128_CTR => AES::aes_ctr::<Aes128Ctr>(key, iv, message),
40 AESAlgorithms::AES256_CTR => AES::aes_ctr::<Aes256Ctr>(key, iv, message),
41 };
42 Ok(result)
43 }
44
45 fn aes_ctr<T: NewCipher + StreamCipherSeek + StreamCipher>(key: &[u8], iv: &[u8], message: &[u8]) -> Vec<u8> {
46 let data = &mut message.to_vec();
47 let mut cipher = T::new(key.into(), iv.into());
48 cipher.seek(0);
49 cipher.apply_keystream(data);
50 data.to_vec()
51 }
52}
53
54#[cfg(target_arch = "wasm32")]
55#[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-encryption"), wasm_bindgen)]
56impl AES {
57 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-encryption"), wasm_bindgen(js_name = encrypt))]
58 pub fn encrypt(key: &[u8], iv: &[u8], message: &[u8], algo: AESAlgorithms) -> Result<Vec<u8>, JsValue> {
59 match AES::encrypt_impl(key, iv, message, algo) {
60 Ok(v) => Ok(v),
61 Err(e) => Err(JsValue::from_str(&e.to_string())),
62 }
63 }
64
65 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen-encryption"), wasm_bindgen(js_name = decrypt))]
66 pub fn decrypt(key: &[u8], iv: &[u8], message: &[u8], algo: AESAlgorithms) -> Result<Vec<u8>, JsValue> {
67 match AES::decrypt_impl(key, iv, message, algo) {
68 Ok(v) => Ok(v),
69 Err(e) => Err(JsValue::from_str(&e.to_string())),
70 }
71 }
72}
73
74#[cfg(not(target_arch = "wasm32"))]
75impl AES {
76 pub fn encrypt(key: &[u8], iv: &[u8], message: &[u8], algo: AESAlgorithms) -> Result<Vec<u8>, BSVErrors> {
77 AES::encrypt_impl(key, iv, message, algo)
78 }
79
80 pub fn decrypt(key: &[u8], iv: &[u8], message: &[u8], algo: AESAlgorithms) -> Result<Vec<u8>, BSVErrors> {
81 AES::decrypt_impl(key, iv, message, algo)
82 }
83}