1use super::Error;
16use super::{base64_decode, base64_encode};
17use aes_gcm_siv::{
18 Aes256GcmSiv, Nonce,
19 aead::{Aead, KeyInit},
20};
21use std::sync::LazyLock;
22
23type Result<T, E = Error> = std::result::Result<T, E>;
24
25#[allow(deprecated)]
28static PINGAP_NONCE: LazyLock<&Nonce> =
29 LazyLock::new(|| Nonce::from_slice(b"pingap nonce"));
30
31fn generate_key(key: &str) -> Vec<u8> {
41 let key_size = 32;
42 let buf = key.as_bytes();
43 let pos = buf.len();
44 if pos > key_size {
45 return buf[0..key_size].to_vec();
46 }
47 if pos == key_size {
48 return buf.to_vec();
49 }
50 let mut block: Vec<u8> = vec![0; key_size];
51 block[..pos].copy_from_slice(buf);
52 block
53}
54
55pub fn aes_encrypt(key: &str, data: &str) -> Result<String> {
65 let cipher =
66 Aes256GcmSiv::new_from_slice(&generate_key(key)).map_err(|e| {
67 Error::Invalid {
68 message: e.to_string(),
69 }
70 })?;
71 let cipher_text =
72 cipher
73 .encrypt(&PINGAP_NONCE, data.as_bytes())
74 .map_err(|e| Error::Aes {
75 message: e.to_string(),
76 })?;
77 Ok(base64_encode(&cipher_text))
78}
79
80pub fn aes_decrypt(key: &str, data: &str) -> Result<String> {
90 let cipher =
91 Aes256GcmSiv::new_from_slice(&generate_key(key)).map_err(|e| {
92 Error::Invalid {
93 message: e.to_string(),
94 }
95 })?;
96 let cipher_text =
97 base64_decode(data).map_err(|e| Error::Base64Decode { source: e })?;
98 let plaintext = cipher
99 .decrypt(&PINGAP_NONCE, cipher_text.as_ref())
100 .map_err(|e| Error::Aes {
101 message: e.to_string(),
102 })?;
103
104 let data = std::str::from_utf8(&plaintext).map_err(|e| Error::Invalid {
105 message: e.to_string(),
106 })?;
107 Ok(data.to_string())
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use pretty_assertions::assert_eq;
114
115 #[test]
116 fn test_aes_encrypt() {
117 for key in [
118 "12345678901234567890123456789012",
119 "12345678901234567890123456789012ABC",
120 "1234567890123456789012345678901",
121 ] {
122 let data = "hello";
123 let result = aes_encrypt(key, data);
124 assert_eq!(result.is_ok(), true);
125
126 let result = aes_decrypt(key, &result.unwrap());
127 assert_eq!(result.is_ok(), true);
128 assert_eq!(result.unwrap(), data);
129 }
130 }
131}