file_encrypt/encryption_algos/
chacha20_poly.rs

1use anyhow::{anyhow, Result};
2use argon2::PasswordHash;
3use base64::prelude::*;
4use chacha20poly1305::{
5    aead::{Aead, AeadCore},
6    ChaCha20Poly1305, Key, KeyInit, Nonce,
7};
8use rand_core::OsRng;
9use std::{ffi::OsString, fs, path::PathBuf};
10
11use crate::hash_algos::argon_hash;
12
13pub fn encrypt_file(
14    file_path: String,
15    passphrase: String,
16    output_file: String,
17) -> Result<(OsString, String)> {
18    // Hash passphrase
19    let argon_pch: String = argon_hash::hash_passphrase(passphrase);
20    let hash = PasswordHash::new(&argon_pch).unwrap();
21    let hash = match hash.hash {
22        Some(hash) => hash.to_string(),
23        None => {
24            eprintln!("[-] Error with argon2 hash");
25            return Err(anyhow!("Unable to get hash from Argon2 PCH"));
26        }
27    };
28
29    // Argon2 hash is encoded in base64
30    let hash = BASE64_STANDARD_NO_PAD.decode(hash)?;
31
32    // Generate iv, cipher, and key for encryption
33    let key = Key::from_slice(&hash);
34    let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
35    let cipher = ChaCha20Poly1305::new(&key);
36
37    let file_data = fs::read(file_path.clone())?;
38    let mut enc_data = match cipher.encrypt(&nonce, file_data.as_ref()) {
39        Ok(enc_data) => enc_data,
40        Err(e) => {
41            let e = e.to_string();
42            return Err(anyhow!("Unable to encrypt data: {e}"));
43        }
44    };
45
46    let mut nonce_and_data = nonce.to_vec();
47    nonce_and_data.append(&mut enc_data);
48
49    let new_file = PathBuf::from(output_file);
50    fs::write(new_file.clone(), nonce_and_data)?;
51
52    Ok((new_file.into(), argon_pch))
53}
54
55pub fn decrypt_file(
56    file_path: String,
57    passphrase: String,
58    expected_pch: String,
59    output_file: String,
60) -> Result<()> {
61    let (res, hash_opt) = argon_hash::check_hash(passphrase, expected_pch);
62    if res == false {
63        eprintln!("[-] Invalid passphrase provided");
64        return Err(anyhow!("Invalid passphrase"));
65    }
66
67    let hash = hash_opt.unwrap();
68    let hash = PasswordHash::new(&hash).unwrap();
69    let hash = hash.hash.unwrap().to_string();
70
71    let hash = BASE64_STANDARD_NO_PAD.decode(hash)?;
72
73    // Generate iv, cipher, and key for encryption
74    let key = Key::from_slice(&hash);
75    let cipher = ChaCha20Poly1305::new(&key);
76
77    // Get nonce from encrypted data
78    let mut nonce_and_data = fs::read(file_path.clone())?;
79    let data = nonce_and_data.split_off(12);
80    let nonce = nonce_and_data;
81    let nonce = Nonce::from_slice(&nonce);
82
83    let plain_data = match cipher.decrypt(nonce, data.as_ref()) {
84        Ok(data) => data,
85        Err(e) => {
86            let e = e.to_string();
87            return Err(anyhow!("Unable to decrypt file: {e}"));
88        }
89    };
90
91    let new_file = PathBuf::from(output_file);
92
93    fs::write(new_file, plain_data)?;
94
95    Ok(())
96}