1use aes_gcm::{
2 aead::{Aead, KeyInit},
3 Aes256Gcm, Nonce,
4};
5use anyhow::{anyhow, bail, Result};
6use rand::{rngs::OsRng, TryRngCore};
7use std::fs;
8
9pub fn encrypt_bytes(plaintext: &[u8], key: &[u8]) -> Result<Vec<u8>> {
10 if key.len() != 32 {
11 bail!("Key must be exactly 32 bytes");
12 }
13
14 let cipher = Aes256Gcm::new(key.into());
15
16 let mut nonce_bytes = [0u8; 12];
18 OsRng.try_fill_bytes(&mut nonce_bytes)?;
19 let nonce = Nonce::from_slice(&nonce_bytes);
20
21 let ciphertext = cipher
23 .encrypt(nonce, plaintext)
24 .map_err(|e| anyhow!("Encryption failed: {}", e))?;
25
26 let mut output = nonce_bytes.to_vec();
28 output.extend_from_slice(&ciphertext);
29 Ok(output)
30}
31
32pub fn encrypt_string(plaintext: &str, key: &[u8]) -> Result<Vec<u8>> {
33 encrypt_bytes(plaintext.as_bytes(), key)
34}
35
36pub fn decrypt_bytes(encrypted: &[u8], key: &[u8]) -> Result<Vec<u8>> {
37 if key.len() != 32 {
38 bail!("Key must be exactly 32 bytes");
39 }
40 if encrypted.len() < 12 {
41 bail!("Encrypted data too short");
42 }
43
44 let cipher = Aes256Gcm::new(key.into());
45
46 let nonce = Nonce::from_slice(&encrypted[..12]);
48 let ciphertext = &encrypted[12..];
49
50 cipher
52 .decrypt(nonce, ciphertext)
53 .map_err(|e| anyhow!("Decryption failed: {}", e))
54}
55
56pub fn decrypt_string(encrypted: &[u8], key: &[u8]) -> Result<String> {
57 let plaintext_bytes = decrypt_bytes(encrypted, key)?;
58 Ok(String::from_utf8(plaintext_bytes)?)
59}
60
61pub fn decrypt_file(filename: &str, password_b64: &str) -> Result<Vec<u8>> {
62 let data = fs::read(filename)?;
63 let key = base64::decode(password_b64)?;
64 decrypt_bytes(&data, &key)
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test() -> Result<()> {
73 let mut key = [0u8; 32];
74 OsRng.try_fill_bytes(&mut key)?;
75
76 let message = "Hello, world!";
77 let encrypted = encrypt_string(message, &key).expect("Encryption should succeed");
78
79 assert!(encrypted.len() > message.len());
81 assert_eq!(encrypted.len(), message.len() + 12 + 16); let decrypted = decrypt_string(&encrypted, &key).expect("Decryption should succeed");
85 assert_eq!(message, decrypted);
86
87 let mut wrong_key = [0u8; 32];
89 OsRng.try_fill_bytes(&mut wrong_key)?;
90 assert!(decrypt_string(&encrypted, &wrong_key).is_err());
91 Ok(())
92 }
93}