infisical_api/utils/
aes256gcm.rs1use crate::error::Result;
2use crate::utils::base64;
3use aes_gcm::{
4 aead::{generic_array::typenum::U16, Aead, AeadCore, KeyInit, OsRng},
5 aes::Aes256,
6 AesGcm, Nonce,
7};
8
9pub fn encrypt(text: &str, secret: &str) -> Result<Encryption> {
10 let nonce = AesGcm::<Aes256, U16>::generate_nonce(&mut OsRng);
11 let cipher: AesGcm<Aes256, U16> =
12 AesGcm::new_from_slice(format!("{:0>len$.len$}", secret, len = 32).as_bytes())?;
13 let ciphertext = cipher.encrypt(&nonce, text.as_bytes())?;
14
15 let tag = &ciphertext[text.len()..];
18
19 Ok(Encryption {
20 text: base64::encode(&ciphertext[..text.len()]),
21 tag: base64::encode(tag),
22 nonce: base64::encode(nonce.as_slice()),
23 })
24}
25
26#[derive(Debug)]
27pub struct Encryption {
28 pub text: String,
29 pub tag: String,
30 pub nonce: String,
31}
32
33pub fn decrypt(text: &str, nonce: &str, tag: &str, secret: &str) -> Result<String> {
34 let nonce = base64::decode(nonce);
35 let tag = base64::decode(tag);
36 let text = base64::decode(text);
37 let nonce = Nonce::<U16>::from_slice(&nonce);
38
39 let mut ciphertext = text.clone();
40 ciphertext.extend(&tag);
41
42 let cipher: AesGcm<Aes256, U16> =
43 AesGcm::new_from_slice(format!("{:0>len$.len$}", secret, len = 32).as_bytes())?;
44
45 let result = cipher.decrypt(nonce, ciphertext.as_ref())?;
46 let result = String::from_utf8(result).map_err(crate::error::utf8)?;
47
48 Ok(result)
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn encrypt_is_successful() {
57 let val = "encrypt this text, please.";
58 let secret = "secretencryptionkeyienhtenh.,hHArstnitenaritn";
59
60 let encrypted_val = encrypt(&val, &secret).unwrap();
61 let decrypted_val = decrypt(
62 &encrypted_val.text,
63 &encrypted_val.nonce,
64 &encrypted_val.tag,
65 &secret,
66 )
67 .unwrap();
68
69 assert_eq!(decrypted_val, val, "Encryption did not provide the expected result upon decryption.\nResult: {}\nExpected: {}", decrypted_val, val);
70 }
71}