chie_crypto/
encryption.rs1use chacha20poly1305::{
4 ChaCha20Poly1305, Nonce,
5 aead::{Aead, KeyInit},
6};
7use rand::RngCore;
8use thiserror::Error;
9
10pub type EncryptionKey = [u8; 32];
12
13pub type EncryptionNonce = [u8; 12];
15
16#[derive(Debug, Error)]
17pub enum EncryptionError {
18 #[error("Encryption failed")]
19 EncryptionFailed,
20
21 #[error("Decryption failed")]
22 DecryptionFailed,
23}
24
25pub fn generate_key() -> EncryptionKey {
27 let mut key = [0u8; 32];
28 rand::thread_rng().fill_bytes(&mut key);
29 key
30}
31
32pub fn generate_nonce() -> EncryptionNonce {
34 let mut nonce = [0u8; 12];
35 rand::thread_rng().fill_bytes(&mut nonce);
36 nonce
37}
38
39pub fn encrypt(
41 data: &[u8],
42 key: &EncryptionKey,
43 nonce: &EncryptionNonce,
44) -> Result<Vec<u8>, EncryptionError> {
45 let cipher = ChaCha20Poly1305::new(key.into());
46 let nonce = Nonce::from_slice(nonce);
47
48 cipher
49 .encrypt(nonce, data)
50 .map_err(|_| EncryptionError::EncryptionFailed)
51}
52
53pub fn decrypt(
55 ciphertext: &[u8],
56 key: &EncryptionKey,
57 nonce: &EncryptionNonce,
58) -> Result<Vec<u8>, EncryptionError> {
59 let cipher = ChaCha20Poly1305::new(key.into());
60 let nonce = Nonce::from_slice(nonce);
61
62 cipher
63 .decrypt(nonce, ciphertext)
64 .map_err(|_| EncryptionError::DecryptionFailed)
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_encrypt_decrypt() {
73 let key = generate_key();
74 let nonce = generate_nonce();
75 let plaintext = b"Hello, CHIE Protocol!";
76
77 let ciphertext = encrypt(plaintext, &key, &nonce).unwrap();
78 let decrypted = decrypt(&ciphertext, &key, &nonce).unwrap();
79
80 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
81 }
82
83 #[test]
84 fn test_decrypt_with_wrong_key() {
85 let key1 = generate_key();
86 let key2 = generate_key();
87 let nonce = generate_nonce();
88 let plaintext = b"Secret message";
89
90 let ciphertext = encrypt(plaintext, &key1, &nonce).unwrap();
91 let result = decrypt(&ciphertext, &key2, &nonce);
92
93 assert!(result.is_err());
94 assert!(matches!(result, Err(EncryptionError::DecryptionFailed)));
95 }
96
97 #[test]
98 fn test_decrypt_with_wrong_nonce() {
99 let key = generate_key();
100 let nonce1 = generate_nonce();
101 let nonce2 = generate_nonce();
102 let plaintext = b"Secret message";
103
104 let ciphertext = encrypt(plaintext, &key, &nonce1).unwrap();
105 let result = decrypt(&ciphertext, &key, &nonce2);
106
107 assert!(result.is_err());
108 assert!(matches!(result, Err(EncryptionError::DecryptionFailed)));
109 }
110
111 #[test]
112 fn test_nonce_reuse_different_plaintexts() {
113 let key = generate_key();
114 let nonce = generate_nonce();
115 let plaintext1 = b"First message";
116 let plaintext2 = b"Second message";
117
118 let ciphertext1 = encrypt(plaintext1, &key, &nonce).unwrap();
120 let ciphertext2 = encrypt(plaintext2, &key, &nonce).unwrap();
121
122 assert_ne!(ciphertext1, ciphertext2);
123
124 let decrypted1 = decrypt(&ciphertext1, &key, &nonce).unwrap();
126 let decrypted2 = decrypt(&ciphertext2, &key, &nonce).unwrap();
127
128 assert_eq!(plaintext1.as_slice(), decrypted1.as_slice());
129 assert_eq!(plaintext2.as_slice(), decrypted2.as_slice());
130 }
131
132 #[test]
133 fn test_empty_data_encryption() {
134 let key = generate_key();
135 let nonce = generate_nonce();
136 let plaintext = b"";
137
138 let ciphertext = encrypt(plaintext, &key, &nonce).unwrap();
139 let decrypted = decrypt(&ciphertext, &key, &nonce).unwrap();
140
141 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
142 assert!(!ciphertext.is_empty());
144 }
145
146 #[test]
147 fn test_large_data_encryption() {
148 let key = generate_key();
149 let nonce = generate_nonce();
150 let plaintext = vec![0x42u8; 1024 * 1024];
152
153 let ciphertext = encrypt(&plaintext, &key, &nonce).unwrap();
154 let decrypted = decrypt(&ciphertext, &key, &nonce).unwrap();
155
156 assert_eq!(plaintext, decrypted);
157 assert_eq!(ciphertext.len(), plaintext.len() + 16);
159 }
160
161 #[test]
162 fn test_corrupted_ciphertext() {
163 let key = generate_key();
164 let nonce = generate_nonce();
165 let plaintext = b"Important message";
166
167 let mut ciphertext = encrypt(plaintext, &key, &nonce).unwrap();
168 ciphertext[0] ^= 0xFF;
170
171 let result = decrypt(&ciphertext, &key, &nonce);
172 assert!(result.is_err());
173 assert!(matches!(result, Err(EncryptionError::DecryptionFailed)));
174 }
175
176 #[test]
177 fn test_key_generation_randomness() {
178 let key1 = generate_key();
179 let key2 = generate_key();
180 let key3 = generate_key();
181
182 assert_ne!(key1, key2);
184 assert_ne!(key2, key3);
185 assert_ne!(key1, key3);
186
187 assert_ne!(key1, [0u8; 32]);
189 assert_ne!(key2, [0u8; 32]);
190 }
191
192 #[test]
193 fn test_nonce_generation_randomness() {
194 let nonce1 = generate_nonce();
195 let nonce2 = generate_nonce();
196 let nonce3 = generate_nonce();
197
198 assert_ne!(nonce1, nonce2);
200 assert_ne!(nonce2, nonce3);
201 assert_ne!(nonce1, nonce3);
202
203 assert_ne!(nonce1, [0u8; 12]);
205 assert_ne!(nonce2, [0u8; 12]);
206 }
207
208 #[test]
209 fn test_deterministic_encryption_same_inputs() {
210 let key = generate_key();
211 let nonce = [0u8; 12]; let plaintext = b"Deterministic test";
213
214 let ciphertext1 = encrypt(plaintext, &key, &nonce).unwrap();
215 let ciphertext2 = encrypt(plaintext, &key, &nonce).unwrap();
216
217 assert_eq!(ciphertext1, ciphertext2);
219 }
220
221 #[test]
222 fn test_truncated_ciphertext() {
223 let key = generate_key();
224 let nonce = generate_nonce();
225 let plaintext = b"Test message for truncation";
226
227 let mut ciphertext = encrypt(plaintext, &key, &nonce).unwrap();
228 ciphertext.truncate(ciphertext.len() - 10);
230
231 let result = decrypt(&ciphertext, &key, &nonce);
232 assert!(result.is_err());
233 assert!(matches!(result, Err(EncryptionError::DecryptionFailed)));
234 }
235}