secure_edit/
secure.rs

1/// File format:
2/// `<[Salt; 128][Blocks]>`
3use super::{PBKDF2_ITERS, SALT_BYTES};
4use aes::{
5    cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit},
6    Aes256,
7};
8use anyhow::{anyhow, Result};
9use pbkdf2::pbkdf2_hmac_array;
10use rand_core::{OsRng, RngCore};
11use sha2::Sha512;
12
13fn pad_zeroes<const N: usize>(arr: &[u8]) -> [u8; N] {
14    let mut ret = [0; N];
15    ret[..arr.len()].copy_from_slice(&arr);
16    ret
17}
18
19pub fn generate_salt() -> [u8; SALT_BYTES] {
20    let mut salt = [0u8; SALT_BYTES];
21    OsRng.fill_bytes(&mut salt);
22    salt
23}
24
25pub fn generate_key(pwd: &str, salt: &[u8]) -> [u8; 32] {
26    let hash = pbkdf2_hmac_array::<Sha512, 20>(pwd.as_bytes(), salt, PBKDF2_ITERS);
27    pad_zeroes(&hash)
28}
29
30pub fn encrypt_data(key: [u8; 32], data: &[u8]) -> Result<Vec<u8>> {
31    let mut output = Vec::with_capacity(data.len());
32    let mut block = GenericArray::from([0u8; 16]);
33    let cipher =
34        Aes256::new_from_slice(&key).map_err(|e| anyhow!("Failed to create AES cipher: {}", e))?;
35
36    let mut handle_chunk = |chunk: &[u8]| {
37        block.copy_from_slice(chunk);
38        cipher.encrypt_block(&mut block);
39        output.extend_from_slice(&block);
40    };
41
42    let chunks = data.chunks_exact(16);
43    let remainder = chunks.remainder();
44    for block_data in chunks {
45        handle_chunk(block_data);
46    }
47    if !remainder.is_empty() {
48        let block_data = pad_zeroes::<16>(remainder);
49        handle_chunk(&block_data);
50    }
51
52    Ok(output)
53}
54
55pub fn decrypt_data(key: [u8; 32], data: &[u8]) -> Result<Vec<u8>> {
56    if data.len() % 16 != 0 {
57        return Err(anyhow!("Data length is not a multiple of 16"));
58    }
59    let mut output = Vec::with_capacity(data.len());
60    let mut block = GenericArray::from([0u8; 16]);
61    let cipher =
62        Aes256::new_from_slice(&key).map_err(|e| anyhow!("Failed to create AES cipher: {}", e))?;
63
64    let mut handle_chunk = |chunk: &[u8]| {
65        block.copy_from_slice(chunk);
66        cipher.decrypt_block(&mut block);
67        output.extend_from_slice(&block);
68    };
69
70    let chunks = data.chunks_exact(16);
71    for block_data in chunks {
72        handle_chunk(block_data);
73    }
74
75    Ok(output)
76}
77
78pub fn encrypt_data_formatted(pwd: &str, salt: &[u8], data: &[u8]) -> Result<Vec<u8>> {
79    let mut input = Vec::with_capacity(SALT_BYTES + data.len());
80    let mut output = Vec::with_capacity(SALT_BYTES + data.len());
81    input.extend_from_slice(&(data.len() as u64).to_le_bytes());
82    input.extend_from_slice(data);
83    output.extend_from_slice(salt);
84    let key = generate_key(pwd, salt);
85    let encrypted_data = encrypt_data(key, &input)?;
86    output.extend_from_slice(&encrypted_data);
87    Ok(output)
88}
89
90pub fn decrypt_data_formatted(pwd: &str, data: &[u8]) -> Result<Vec<u8>> {
91    if data.len() < SALT_BYTES {
92        return Err(anyhow!("Data is too short"));
93    }
94    let salt = &data[..SALT_BYTES];
95    let key = generate_key(pwd, salt);
96    let decrypted_data = decrypt_data(key, &data[SALT_BYTES..])?;
97    let len_bytes = &decrypted_data[..8];
98    let len = u64::from_le_bytes(len_bytes.try_into()?) as usize;
99    Ok(decrypted_data[8..8 + len].to_vec())
100}