diff options
Diffstat (limited to '')
| -rw-r--r-- | crates/secd/src/util/crypter.rs | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/crates/secd/src/util/crypter.rs b/crates/secd/src/util/crypter.rs new file mode 100644 index 0000000..1717377 --- /dev/null +++ b/crates/secd/src/util/crypter.rs @@ -0,0 +1,87 @@ +use aes_gcm::{ + aead::{Aead, KeyInit, OsRng}, + Aes256Gcm, Nonce, +}; +use argon2::{ + password_hash::{self, SaltString}, + Argon2, PasswordHasher, +}; +use derive_more::Display; +use rand::Rng; +use sha2::{Digest, Sha256}; +use thiserror::Error; + +#[derive(Debug, Display, Error)] +pub enum CrypterError { + EncryptError(String), + DecryptError(String), + DecodeError(String), + HashError(String), +} + +pub struct Crypter { + pub key: Vec<u8>, +} + +impl Crypter { + pub fn new(key: &[u8]) -> Self { + Self { key: key.to_vec() } + } + + pub fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>, CrypterError> { + let mut hasher = Sha256::new(); + hasher.update(&self.key); + + let cipher = Aes256Gcm::new(&hasher.finalize()); + + let rbs = rand::thread_rng().gen::<[u8; 12]>(); + let iv = Nonce::from_slice(&rbs); + let crypt = cipher + .encrypt(&iv, data) + .map_err(|e| CrypterError::EncryptError(e.to_string()))?; + + let mut msg = iv.to_vec(); + msg.extend_from_slice(&crypt); + Ok(msg) + } + + pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, CrypterError> { + let mut hasher = Sha256::new(); + hasher.update(&self.key); + + let cipher = Aes256Gcm::new(&hasher.finalize()); + + let iv = Nonce::from_slice(&data[0..=11]); + let data = &data[12..]; + Ok(cipher + .decrypt(&iv, data) + .map_err(|e| CrypterError::DecryptError(e.to_string()))?) + } + + pub fn hash(&self, data: &[u8]) -> Result<String, CrypterError> { + let salt = SaltString::generate(&mut OsRng); + let hasher = Argon2::default(); + Ok(hasher + .hash_password(data, &salt) + .map_err(|e| CrypterError::HashError(e.to_string()))? + .to_string()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn encrypt_data_test() { + let crypter = Crypter { + key: "testkey".to_string().into_bytes(), + }; + + let plaintext = "This is a secret."; + let enc = crypter.encrypt(&plaintext.as_bytes()).unwrap(); + + let res = crypter.decrypt(&enc).unwrap(); + assert_eq!(plaintext, std::str::from_utf8(&res).unwrap()); + } +} |
