Skip to main content

this_me/utils/
crypto.rs

1//utils/crypto.rs
2use chacha20poly1305::{
3    aead::{Aead, KeyInit, OsRng},
4    ChaCha20Poly1305, Key, Nonce,
5};
6use rand::RngCore;
7use thiserror::Error;
8
9#[derive(Debug, Error)]
10pub enum CryptoError {
11    #[error("Encryption failed")]
12    EncryptionFailed,
13    #[error("Decryption failed")]
14    DecryptionFailed,
15    #[error("Invalid key length")]
16    InvalidKeyLength,
17}
18
19// Derives a fixed-size key from a hash string
20fn derive_key_from_hash(hash: &str) -> Result<Key, CryptoError> {
21    let mut key_bytes = [0u8; 32];
22    let hash_bytes = hash.as_bytes();
23
24    if hash_bytes.len() < 32 {
25        // Pad the key if it's too short
26        key_bytes[..hash_bytes.len()].copy_from_slice(hash_bytes);
27    } else {
28        key_bytes.copy_from_slice(&hash_bytes[..32]);
29    }
30
31    Ok(Key::from_slice(&key_bytes).clone())
32}
33
34pub fn encrypt_string(hash: &str, plaintext: &str) -> Result<Vec<u8>, CryptoError> {
35    let key = derive_key_from_hash(hash)?;
36    let cipher = ChaCha20Poly1305::new(&key);
37    let mut nonce_bytes = [0u8; 12];
38    OsRng.fill_bytes(&mut nonce_bytes);
39    let nonce = Nonce::from_slice(&nonce_bytes);
40
41    let ciphertext = cipher
42        .encrypt(nonce, plaintext.as_bytes())
43        .map_err(|_| CryptoError::EncryptionFailed)?;
44
45    // Prepend nonce to the result
46    let mut result = nonce_bytes.to_vec();
47    result.extend(ciphertext);
48    Ok(result)
49}
50
51pub fn decrypt_string(hash: &str, ciphertext: &[u8]) -> Result<String, CryptoError> {
52    let key = derive_key_from_hash(hash)?;
53    let cipher = ChaCha20Poly1305::new(&key);
54
55    if ciphertext.len() < 12 {
56        return Err(CryptoError::DecryptionFailed);
57    }
58
59    let (nonce_bytes, cipher_bytes) = ciphertext.split_at(12);
60    let nonce = Nonce::from_slice(nonce_bytes);
61
62    let decrypted = cipher
63        .decrypt(nonce, cipher_bytes)
64        .map_err(|_| CryptoError::DecryptionFailed)?;
65
66    String::from_utf8(decrypted).map_err(|_| CryptoError::DecryptionFailed)
67}