p2p_chat/crypto/
storage.rs1use anyhow::{anyhow, Result};
5use argon2::{Argon2, Params};
6use chacha20poly1305::{
7 aead::{Aead, AeadCore, KeyInit},
8 ChaCha20Poly1305, Key, Nonce,
9};
10
11#[derive(Clone)]
15pub struct StorageEncryption {
16 key: [u8; 32], }
18
19impl StorageEncryption {
20 pub fn new(password: &str, salt: &[u8]) -> Result<Self> {
32 if salt.len() != 16 {
33 return Err(anyhow!("Salt must be 16 bytes"));
34 }
35
36 let params = Params::new(15000, 2, 1, Some(32))
37 .map_err(|e| anyhow!("Argon2 params error: {:?}", e))?;
38 let argon2 = Argon2::new(argon2::Algorithm::Argon2id, argon2::Version::V0x13, params);
39
40 let mut key = [0u8; 32];
41 argon2
42 .hash_password_into(password.as_bytes(), salt, &mut key)
43 .map_err(|e| anyhow!("Argon2 key derivation failed: {}", e))?;
44
45 Ok(Self { key })
46 }
47
48 pub fn generate_salt() -> [u8; 16] {
50 let mut salt = [0u8; 16];
51 getrandom::getrandom(&mut salt).expect("Failed to generate random salt");
52 salt
53 }
54
55 pub fn encrypt_value(&self, data: &[u8]) -> Result<Vec<u8>> {
69 let cipher = ChaCha20Poly1305::new(Key::from_slice(&self.key));
70 let nonce = ChaCha20Poly1305::generate_nonce(&mut rand::rngs::OsRng);
71
72 let ciphertext = cipher
73 .encrypt(&nonce, data)
74 .map_err(|e| anyhow!("Encryption failed: {}", e))?;
75
76 let mut result = nonce.to_vec();
77 result.extend_from_slice(&ciphertext);
78
79 Ok(result)
80 }
81
82 pub fn decrypt_value(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
96 if ciphertext.len() < 12 {
97 return Err(anyhow!("Ciphertext too short"));
98 }
99
100 let (nonce_bytes, encrypted_data) = ciphertext.split_at(12);
101 let nonce = Nonce::from_slice(nonce_bytes);
102
103 let cipher = ChaCha20Poly1305::new(Key::from_slice(&self.key));
104
105 let plaintext = cipher
106 .decrypt(nonce, encrypted_data)
107 .map_err(|e| anyhow!("Decryption failed: {}", e))?;
108
109 Ok(plaintext)
110 }
111
112 pub fn derive_recipient_hash(public_key: &[u8]) -> [u8; 32] {
121 use sha2::{Digest, Sha256};
122 let mut hasher = Sha256::new();
123 hasher.update(b"p2p-messenger-recipient-");
124 hasher.update(public_key);
125 hasher.finalize().into()
126 }
127}