aboutsummaryrefslogtreecommitdiff
path: root/crates/secd/src/util/crypter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/secd/src/util/crypter.rs')
-rw-r--r--crates/secd/src/util/crypter.rs87
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());
+ }
+}