use pbkdf2::{self, password_hash::PasswordHasher}; use base64::{Engine as _}; use generic_array::typenum::{UInt, B1, B0, UTerm, U32}; use wasm_bindgen::prelude::*; use aes_gcm::{ aead::{Aead, KeyInit, generic_array::GenericArray}, Aes256Gcm }; #[wasm_bindgen] pub struct Crypto { iv: IV, c: Aes256Gcm } type Key = GenericArray; type IV = GenericArray, B1>, B0>, B0>>; #[wasm_bindgen] impl Crypto { #[wasm_bindgen(constructor)] pub fn new(password: &str, salt: &str) -> Self { super::utils::set_panic_hook(); let key = Self::_pbkdf2(password, salt, 1000, 32); let iv = Self::_pbkdf2(password, salt, 5000, 12); println!("Key {}\nIV {}", hex::encode(&key), hex::encode(&iv)); let iv: IV = GenericArray::clone_from_slice(&iv); let key: &Key = GenericArray::from_slice(&key); let c = Aes256Gcm::new(key); Crypto { iv: iv, c:c } } pub fn sha256(input: &str) -> String { sha256::digest(input) } fn _pbkdf2(password: &str, salt: &str, rounds: u32, output_length: usize) -> Vec { let params = pbkdf2::Params { rounds: rounds, output_length: output_length }; let salt = base64::engine::general_purpose::STANDARD_NO_PAD.encode(salt); let salt = pbkdf2::password_hash::Salt::new(&salt).unwrap(); let res = pbkdf2::Pbkdf2.hash_password_customized(password.as_bytes(), None, None, params, salt).unwrap(); res.hash.unwrap().as_bytes().to_owned() } pub fn encrypt(&self, plaintext: &str) -> String { base64::engine::general_purpose::STANDARD_NO_PAD.encode(self.c.encrypt(&self.iv, plaintext.as_bytes()).unwrap()) } pub fn decrypt(&self, ciphertext: &str) -> String { let ciphertext = base64::engine::general_purpose::STANDARD_NO_PAD.decode(ciphertext).unwrap(); String::from_utf8(self.c.decrypt(&self.iv, &*ciphertext).unwrap()).unwrap() } }