60 lines
1.9 KiB
Rust
60 lines
1.9 KiB
Rust
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<u8, U32>;
|
|
type IV = GenericArray<u8, UInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>, B0>>;
|
|
|
|
#[wasm_bindgen]
|
|
impl Crypto {
|
|
#[wasm_bindgen(constructor)]
|
|
pub fn new(password: &str, salt: &str) -> Self {
|
|
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<u8> {
|
|
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()
|
|
}
|
|
} |