street_cred/encryption/
message_encryptor.rs1use crate::CipherGeneration;
2use crate::serialization::RubyMarshal;
3use aes_gcm::{
4 Aes128Gcm,
5 aead::{Aead, KeyInit, generic_array::GenericArray},
6};
7use anyhow::anyhow;
8use base64::{Engine as _, engine::general_purpose};
9
10pub struct MessageEncryption {
27 message: Vec<u8>,
28 key: String,
29 aad: String,
30}
31
32impl MessageEncryption {
33 pub fn new(message: Vec<u8>, key: &str, aad: &str) -> Self {
50 MessageEncryption {
51 message,
52 key: key.to_string(),
53 aad: aad.to_string(),
54 }
55 }
56
57 pub fn decrypt(&self, iv: &str, tag: &str) -> anyhow::Result<String> {
84 if let (Ok(key), Ok(iv), Ok(message), Ok(tag)) = (
85 hex_to_bytes(&self.key),
86 general_purpose::STANDARD.decode(iv),
87 general_purpose::STANDARD.decode(&self.message),
88 general_purpose::STANDARD.decode(tag),
89 ) {
90 let key = GenericArray::from_slice(&key);
91 let iv = GenericArray::from_slice(&iv);
92 let decipher = Aes128Gcm::new(key);
93
94 let mut ciphertext = message;
95 ciphertext.extend_from_slice(&tag);
96
97 let payload = aes_gcm::aead::Payload {
98 msg: &ciphertext,
99 aad: self.aad.as_bytes(),
100 };
101
102 let plaintext = decipher.decrypt(iv, payload);
103
104 if let Ok(plaintext) = plaintext {
105 let content = RubyMarshal::deserialize(plaintext)?;
106
107 return Ok(String::from_utf8(content)?);
108 }
109 }
110
111 Err(anyhow!("Decryption not successful"))
112 }
113
114 pub fn encrypt(&self) -> anyhow::Result<String> {
133 if let Ok(key) = hex_to_bytes(&self.key) {
134 let key = GenericArray::from_slice(&key);
135 let random_iv = CipherGeneration::random_iv();
136 let random_iv = GenericArray::from_slice(&random_iv);
137 let cipher = Aes128Gcm::new(key);
138
139 let serialized_message = RubyMarshal::serialize(std::str::from_utf8(&self.message)?)?;
140
141 let payload = aes_gcm::aead::Payload {
142 msg: &serialized_message,
143 aad: self.aad.as_bytes(),
144 };
145
146 let encrypted = cipher.encrypt(random_iv, payload);
147
148 if let Ok(encrypted) = encrypted {
149 let (ct, tag) = encrypted.split_at(encrypted.len() - 16);
150
151 let encryption_result = format!(
152 "{}--{}--{}",
153 general_purpose::STANDARD.encode(ct),
154 general_purpose::STANDARD.encode(random_iv),
155 general_purpose::STANDARD.encode(tag)
156 );
157
158 return Ok(encryption_result);
159 }
160 }
161
162 Err(anyhow!("Encryption not successful"))
163 }
164
165 pub fn split_encrypted_contents(contents: &str) -> anyhow::Result<Vec<&str>> {
184 let contents = contents.split("--").fold(Vec::new(), |mut acc, content| {
185 acc.push(content);
186
187 acc
188 });
189
190 if contents.len() == 3 {
191 Ok(contents)
192 } else {
193 Err(anyhow!("Invalid encrypted contents"))
194 }
195 }
196}
197
198fn hex_to_bytes(raw_hex: &str) -> Result<Vec<u8>, hex::FromHexError> {
199 hex::decode(raw_hex)
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_encrypt_decrypt_cycle() {
208 let key = "8872ebc11db3ea2ed08cc629d199b164";
209 let aad = "";
210 let plaintext_message = b"banana: true
211apple: false
212orange: false";
213
214 let encryptor = MessageEncryption::new(plaintext_message.to_vec(), key, aad);
215
216 let encrypted_result = match encryptor.encrypt() {
217 Ok(encrypted_contents) => encrypted_contents,
218 Err(..) => panic!("first encryption failed"),
219 };
220
221 let split_data = MessageEncryption::split_encrypted_contents(&encrypted_result).unwrap();
222
223 let new_message = split_data[0];
224 let new_iv = split_data[1];
225 let new_aad = split_data[2];
226
227 let decryptor = MessageEncryption::new(new_message.as_bytes().to_vec(), key, aad);
228
229 let decrypted_result = decryptor.decrypt(new_iv, new_aad);
230
231 let encryptor = match decrypted_result {
232 Ok(decrypted_contents) => {
233 MessageEncryption::new(decrypted_contents.as_bytes().to_vec(), key, aad)
234 }
235 Err(why) => panic!("first decryption failed {}", why),
236 };
237
238 let encrypted_result = match encryptor.encrypt() {
239 Ok(encrypted_contents) => encrypted_contents,
240 Err(why) => panic!("second encryption failed {}", why),
241 };
242
243 let split_data = MessageEncryption::split_encrypted_contents(&encrypted_result).unwrap();
244 let new_message = split_data[0];
245 let new_iv = split_data[1];
246 let new_aad = split_data[2];
247
248 let decryptor = MessageEncryption::new(new_message.as_bytes().to_vec(), key, aad);
249
250 let decrypted_result = decryptor.decrypt(new_iv, new_aad);
251
252 match decrypted_result {
253 Ok(decrypted_contents) => {
254 assert_eq!(decrypted_contents.as_bytes(), plaintext_message);
255 }
256 Err(_) => panic!("second decryption failed"),
257 };
258 }
259
260 #[test]
261 fn test_encryption_decryption_with_aad() {
262 let key = "8872ebc11db3ea2ed08cc629d199b164";
263 let aad = "some value";
264 let plaintext_message = "banana: true
265 apple: false
266 orange: false";
267
268 let encryptor = MessageEncryption::new(plaintext_message.as_bytes().to_vec(), key, aad);
269
270 let encrypted_result = match encryptor.encrypt() {
271 Ok(encrypted_contents) => encrypted_contents,
272 Err(..) => panic!("first encryption failed"),
273 };
274
275 let split_data = MessageEncryption::split_encrypted_contents(&encrypted_result).unwrap();
276
277 let new_message = split_data[0];
278 let new_iv = split_data[1];
279 let new_aad = split_data[2];
280
281 let decryptor = MessageEncryption::new(new_message.as_bytes().to_vec(), key, aad);
282
283 let result = decryptor.decrypt(new_iv, new_aad);
284
285 assert_eq!(plaintext_message, result.unwrap());
286 }
287
288 #[test]
289 fn test_decryption_fails_with_incorrect_iv() {
290 let key = "94b6b40cabf62ee59c9aa13a86f0e7d7";
291 let aad = "";
292 let encrypted_message = b"1alR88JGbSy1wz44cgVgZC3mH2Fg9HjRFtl6NwRoOfpqNzJ61Ub48O1YhJUqaszJgJ8=";
293 let decryptor = MessageEncryption::new(encrypted_message.to_vec(), key, aad);
294
295 let result = decryptor.decrypt("123456789012345", "pksKcg/so9Pq3UMHjfnVsg==");
296
297 assert!(result.is_err());
298 }
299
300 #[test]
301 fn test_encryption_fails_with_non_hex_key() {
302 let key = "8872ebc11db3ea2";
303 let aad = "";
304 let plaintext_message = b"banana: true
305apple: false
306orange: false";
307
308 let encryptor = MessageEncryption::new(plaintext_message.to_vec(), key, aad);
309
310 let result = encryptor.encrypt();
311
312 assert!(result.is_err());
313 }
314
315 #[test]
316 fn test_invalid_aad_for_decrypt() {
317 let invalid_aad = "66ag";
318 let aad = "";
319 let key = "8872ebc11db3ea2";
320 let plaintext_message = b"banana: true
321apple: false
322orange: false";
323
324 let decryptor = MessageEncryption::new(plaintext_message.to_vec(), key, aad);
325
326 let result = decryptor.decrypt("", invalid_aad);
327
328 assert!(result.is_err());
329 }
330}