shared/utils/crypto/
aes.rs1use aes_gcm::{
2 AeadCore, Aes256Gcm, KeyInit, Nonce,
3 aead::{Aead, OsRng},
4};
5use base64::{Engine, prelude::BASE64_URL_SAFE_NO_PAD};
6use secrecy::{ExposeSecret, SecretString};
7
8use crate::error::{CoreError, Result};
9
10#[derive(Clone, Default)]
11pub struct Aes {
12 pub secret_key: String,
13}
14
15impl Aes {
16 pub fn new(secret_key: &SecretString) -> Self {
17 Self {
18 secret_key: secret_key.expose_secret().to_string(),
19 }
20 }
21}
22
23impl Aes {
24 pub fn encrypt(self, msg: &str) -> Result<String> {
25 let nonce = Aes256Gcm::generate_nonce(OsRng); let key_bytes = hex::decode(&self.secret_key).expect("Invalid hex key");
28 let key: &[u8; 32] = key_bytes.as_slice().try_into().expect("Invalid key length");
29
30 let cipher = Aes256Gcm::new(key.into());
31
32 let ciphertext = cipher
34 .encrypt(&nonce, msg.as_bytes())
35 .map_err(|_| CoreError::Internal(crate::error::InternalError::Hashing))?;
36
37 let mut signature = Vec::with_capacity(12 + ciphertext.len());
39 signature.extend_from_slice(&nonce[..]); signature.extend_from_slice(&ciphertext);
41
42 Ok(BASE64_URL_SAFE_NO_PAD.encode(&signature))
43 }
44
45 pub fn decrypt(self, ciphertext: &str) -> Result<String> {
46 let bytes = BASE64_URL_SAFE_NO_PAD
47 .decode(ciphertext.as_bytes())
48 .map_err(|_| CoreError::Internal(crate::error::InternalError::Hashing))?;
49
50 let (nonce_bytes, ciphertext_bytes) = bytes.split_at(12);
51 let nonce = Nonce::from(
52 <[u8; 12]>::try_from(nonce_bytes)
53 .map_err(|_| CoreError::Internal(crate::error::InternalError::Hashing))?,
54 );
55
56 let key_bytes = hex::decode(&self.secret_key).expect("Invalid hex key");
57 let key: &[u8; 32] = key_bytes.as_slice().try_into().expect("Invalid key length");
58 let cipher = Aes256Gcm::new(key.into());
59
60 let data = cipher
61 .decrypt(&nonce, ciphertext_bytes)
62 .map_err(|_| CoreError::Internal(crate::error::InternalError::Hashing))?;
63 String::from_utf8(data)
64 .map_err(|_| CoreError::Internal(crate::error::InternalError::Hashing))
65 }
66}