infisical_api/utils/
aes256gcm.rs

1use 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    // The authentication tag is automatically appended by cipher.encrypt but we need to pass it to
16    // infisical. So here we extract it as a slice of the ciphertext.
17    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}