i6_pack/encryptions/
cha_cha20_poly1305.rs1use chacha20poly1305::{
2 aead::{Aead, AeadCore, KeyInit, OsRng},
3 Nonce,
4};
5
6use argon2::{self, password_hash::SaltString, Argon2, PasswordHasher};
7
8use hmac::digest::{generic_array::GenericArray, typenum};
9use rand::RngCore;
10use std::fs::File;
11use std::io::{self, Write};
12
13use super::encryption::{self, Encryption};
14
15const SALT_LEN: usize = 16;
16const NONCE_LEN: usize = 12;
17
18fn generate_salt() -> [u8; SALT_LEN] {
19 let mut salt = [0u8; SALT_LEN];
20 rand::thread_rng().fill_bytes(&mut salt);
21 salt
22}
23
24fn derive_key_from_password_argon2(password: &str, salt: &[u8]) -> [u8; 32] {
25 let argon2 = Argon2::default();
26 let salt = SaltString::encode_b64(salt).unwrap();
27 let password_hash = argon2.hash_password(password.as_bytes(), &salt).unwrap();
28 let key = password_hash.hash.unwrap();
29 let mut key_bytes = [0u8; 32];
30 key_bytes.copy_from_slice(key.as_bytes());
31 key_bytes
32}
33
34pub struct ChaCha20Poly1305;
35
36impl Encryption for ChaCha20Poly1305 {
37 fn encrypt_file(
38 input_file: &str,
39 output_file: &str,
40 password: &str,
41 ) -> io::Result<()> {
42 let salt = generate_salt();
43 let key = derive_key_from_password_argon2(password, &salt);
44 let cipher = chacha20poly1305::ChaCha20Poly1305::new((&key).into());
45 let nonce = chacha20poly1305::ChaCha20Poly1305::generate_nonce(&mut OsRng);
46
47 let file_content = std::fs::read(input_file)?;
48 let ciphertext =
49 cipher.encrypt(&nonce, file_content.as_ref()).map_err(|_| {
50 io::Error::new(io::ErrorKind::Other, "Encryption failure")
51 })?;
52
53 let mut output = File::create(output_file)?;
54 output.write_all(&salt)?; output.write_all(nonce.as_slice())?; output.write_all(&ciphertext)?;
57
58 Ok(())
59 }
60
61 fn decrypt_file(
62 input_file: &str,
63 output_file: &str,
64 password: &str,
65 ) -> io::Result<()> {
66 let file_content = std::fs::read(input_file)?;
67 let (salt_and_nonce, ciphertext) =
68 file_content.split_at(SALT_LEN + NONCE_LEN); let (salt, nonce) = salt_and_nonce.split_at(SALT_LEN); let key = derive_key_from_password_argon2(password, salt);
72 let cipher = chacha20poly1305::ChaCha20Poly1305::new((&key).into());
73
74 let nonce = GenericArray::from_slice(nonce);
75 let plaintext = match cipher.decrypt(nonce, ciphertext) {
76 Ok(pt) => pt,
77 Err(_) => {
78 return Err(io::Error::new(io::ErrorKind::Other, "Decryption failure"))
79 }
80 };
81
82 let mut output = File::create(output_file)?;
83 output.write_all(&plaintext)?;
84 Ok(())
85 }
86}