network_protocol/utils/
crypto.rs1use chacha20poly1305::{
2 aead::{Aead, KeyInit},
3 Key, XChaCha20Poly1305, XNonce,
4};
5use getrandom::fill;
6use zeroize::Zeroize;
7
8use crate::error::{ProtocolError, Result};
9
10pub struct Crypto {
11 cipher: XChaCha20Poly1305,
12}
13
14impl Crypto {
15 pub fn new(key_bytes: &[u8; 32]) -> Self {
16 let key = Key::from_slice(key_bytes);
17 let cipher = XChaCha20Poly1305::new(key);
18 Self { cipher }
19 }
20
21 pub fn encrypt(&self, plaintext: &[u8], nonce: &[u8; 24]) -> Result<Vec<u8>> {
22 let nonce = XNonce::from_slice(nonce);
23 self.cipher
24 .encrypt(nonce, plaintext)
25 .map_err(|_| ProtocolError::EncryptionFailure)
26 }
27
28 pub fn decrypt(&self, ciphertext: &[u8], nonce: &[u8; 24]) -> Result<Vec<u8>> {
29 let nonce = XNonce::from_slice(nonce);
30 self.cipher
31 .decrypt(nonce, ciphertext)
32 .map_err(|_| ProtocolError::DecryptionFailure)
33 }
34
35 #[allow(clippy::expect_used)] pub fn generate_nonce() -> [u8; 24] {
39 let mut nonce = [0u8; 24];
40 fill(&mut nonce).expect("Failed to fill nonce");
41 nonce
42 }
43
44 #[allow(clippy::expect_used)] pub fn generate_key() -> [u8; 32] {
48 let mut key = [0u8; 32];
49 fill(&mut key).expect("Failed to fill key");
50 key
51 }
52}
53
54impl Drop for Crypto {
55 fn drop(&mut self) {
56 }
60}
61
62#[derive(Clone)]
64pub struct SharedSecret {
65 secret: [u8; 32],
66}
67
68impl SharedSecret {
69 pub fn new(secret: [u8; 32]) -> Self {
70 Self { secret }
71 }
72
73 pub fn as_bytes(&self) -> &[u8; 32] {
74 &self.secret
75 }
76}
77
78impl Zeroize for SharedSecret {
79 fn zeroize(&mut self) {
80 self.secret.zeroize();
81 }
82}
83
84impl Drop for SharedSecret {
85 fn drop(&mut self) {
86 self.zeroize();
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_crypto_nonce_generation() {
96 let nonce = Crypto::generate_nonce();
97 assert_eq!(nonce.len(), 24);
98 assert!(nonce.iter().any(|&b| b != 0));
100 }
101
102 #[test]
103 fn test_crypto_key_generation() {
104 let key = Crypto::generate_key();
105 assert_eq!(key.len(), 32);
106 assert!(key.iter().any(|&b| b != 0));
108 }
109
110 #[test]
111 fn test_shared_secret_zeroize() {
112 let mut secret = SharedSecret::new([0xAB; 32]);
113 secret.zeroize();
114 assert!(secret.as_bytes().iter().all(|&b| b == 0));
115 }
116}