1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
use argon2::{
    password_hash::SaltString,
    Argon2, PasswordHasher, Params, Version, Algorithm,
};
use generic_array::{GenericArray, typenum::U32};
use rand::Rng;

const SALT: &[u8] = b"salasasdfasft";
const OPSLIMIT: u32 = 3;
const MEMLIMIT: u32 = 102400;

fn derive_key(password: &[u8]) -> GenericArray<u8, U32> {
    let mut rng = rand::thread_rng();
    let salt = SaltString::generate(&mut rng);
    let params = Params::new(
        OPSLIMIT,
        MEMLIMIT,
        OPSLIMIT,
        None,
    )
    .map_err(|e| e.to_string())
    .unwrap();
    let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
    let hash = argon2
        .hash_password(password, &salt)
        .map(|hash| hash.hash.unwrap().as_bytes().to_vec())
        .unwrap();

    *GenericArray::from_slice(&hash[..32])
}

fn encrypt(data: &[u8], password: &[u8]) -> Result<Vec<u8>, aes_gcm::Error> {
    let key = derive_key(password);
    let cipher = Aes256Gcm::new(&key.into());
    let nonce = Nonce::from_slice(b"unique_nonce_for_this_encryption");
    cipher.encrypt(nonce, data)
}

fn decrypt(ciphertext: &[u8], password: &[u8]) -> Result<Vec<u8>, aes_gcm::Error> {
    let key = derive_key(password);
    let cipher = Aes256Gcm::new(&key.into());
    let nonce = Nonce::from_slice(b"unique_nonce_for_this_encryption");
    cipher.decrypt(nonce, ciphertext)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_encrypt_decrypt() {
        let password = b"your-secure-password";
        let plaintext = b"Hello, World!";
        let ciphertext = encrypt(plaintext, password).unwrap();
        let decrypted = decrypt(&ciphertext, password).unwrap();
        assert_eq!(decrypted, plaintext);
    }
}