dcrypt_symmetric/aead/chacha20poly1305/
cipher.rs1use super::common::{
7 ChaCha20Poly1305CiphertextPackage, ChaCha20Poly1305Key, ChaCha20Poly1305Nonce,
8};
9use crate::cipher::{Aead, SymmetricCipher};
10use crate::error::{from_primitive_error, validate, Result};
11use dcrypt_algorithms::aead::chacha20poly1305::ChaCha20Poly1305;
12use dcrypt_algorithms::aead::chacha20poly1305::CHACHA20POLY1305_TAG_SIZE;
13use dcrypt_algorithms::aead::xchacha20poly1305::XChaCha20Poly1305;
14use dcrypt_algorithms::error::Error as PrimitiveError;
15use dcrypt_algorithms::types::Nonce; use rand::RngCore;
17use std::fmt;
18
19pub struct ChaCha20Poly1305Cipher {
21 cipher: ChaCha20Poly1305,
22 pub(crate) key: ChaCha20Poly1305Key,
23}
24
25impl SymmetricCipher for ChaCha20Poly1305Cipher {
26 type Key = ChaCha20Poly1305Key;
27
28 fn new(key: &Self::Key) -> Result<Self> {
29 validate::length("ChaCha20Poly1305 key", key.as_bytes().len(), 32)?;
31
32 let cipher = ChaCha20Poly1305::new(key.as_bytes());
33 Ok(Self {
34 cipher,
35 key: key.clone(),
36 })
37 }
38
39 fn name() -> &'static str {
40 "ChaCha20Poly1305"
41 }
42}
43
44impl Aead for ChaCha20Poly1305Cipher {
45 type Nonce = ChaCha20Poly1305Nonce;
46
47 fn encrypt(
48 &self,
49 nonce: &Self::Nonce,
50 plaintext: &[u8],
51 aad: Option<&[u8]>,
52 ) -> Result<Vec<u8>> {
53 let primitives_nonce = Nonce::<12>::from_slice(nonce.as_bytes())?;
55
56 self.cipher
58 .encrypt(&primitives_nonce, plaintext, aad)
59 .map_err(from_primitive_error)
60 }
61
62 fn decrypt(
63 &self,
64 nonce: &Self::Nonce,
65 ciphertext: &[u8],
66 aad: Option<&[u8]>,
67 ) -> Result<Vec<u8>> {
68 validate::min_length(
70 "ChaCha20Poly1305 ciphertext",
71 ciphertext.len(),
72 CHACHA20POLY1305_TAG_SIZE,
73 )?;
74
75 let primitives_nonce = Nonce::<12>::from_slice(nonce.as_bytes())?;
77
78 self.cipher
80 .decrypt(&primitives_nonce, ciphertext, aad)
81 .map_err(|e| match e {
82 PrimitiveError::Authentication { .. } => {
83 dcrypt_api::error::Error::AuthenticationFailed {
84 context: "ChaCha20Poly1305",
85 #[cfg(feature = "std")]
86 message: "authentication tag verification failed".to_string(),
87 }
88 }
89 _ => from_primitive_error(e),
90 })
91 }
92
93 fn generate_nonce() -> Self::Nonce {
94 ChaCha20Poly1305Nonce::generate()
95 }
96}
97
98impl ChaCha20Poly1305Cipher {
99 pub fn generate() -> Result<(Self, ChaCha20Poly1305Key)> {
101 let key = ChaCha20Poly1305Key::generate();
102 let cipher = Self::new(&key)?;
103 Ok((cipher, key))
104 }
105
106 pub fn encrypt_with_random_nonce(
108 &self,
109 plaintext: &[u8],
110 aad: Option<&[u8]>,
111 ) -> Result<(Vec<u8>, ChaCha20Poly1305Nonce)> {
112 let nonce = Self::generate_nonce();
113 let ciphertext = self.encrypt(&nonce, plaintext, aad)?;
114 Ok((ciphertext, nonce))
115 }
116
117 pub fn decrypt_and_verify(
119 &self,
120 ciphertext: &[u8],
121 nonce: &ChaCha20Poly1305Nonce,
122 aad: Option<&[u8]>,
123 ) -> Result<Vec<u8>> {
124 self.decrypt(nonce, ciphertext, aad)
125 }
126
127 pub fn key(&self) -> &ChaCha20Poly1305Key {
129 &self.key
130 }
131
132 pub fn encrypt_to_package(
134 &self,
135 plaintext: &[u8],
136 aad: Option<&[u8]>,
137 ) -> Result<ChaCha20Poly1305CiphertextPackage> {
138 let (ciphertext, nonce) = self.encrypt_with_random_nonce(plaintext, aad)?;
139 Ok(ChaCha20Poly1305CiphertextPackage::new(nonce, ciphertext))
140 }
141
142 pub fn decrypt_package(
144 &self,
145 package: &ChaCha20Poly1305CiphertextPackage,
146 aad: Option<&[u8]>,
147 ) -> Result<Vec<u8>> {
148 self.decrypt(&package.nonce, &package.ciphertext, aad)
149 }
150}
151
152pub struct XChaCha20Poly1305Cipher {
154 cipher: XChaCha20Poly1305,
155}
156
157impl SymmetricCipher for XChaCha20Poly1305Cipher {
158 type Key = ChaCha20Poly1305Key;
159
160 fn new(key: &Self::Key) -> Result<Self> {
161 validate::length("XChaCha20Poly1305 key", key.as_bytes().len(), 32)?;
163
164 let cipher = XChaCha20Poly1305::new(key.as_bytes());
165 Ok(Self { cipher })
166 }
167
168 fn name() -> &'static str {
169 "XChaCha20Poly1305"
170 }
171}
172
173#[derive(Clone, Debug)]
175pub struct XChaCha20Poly1305Nonce([u8; 24]);
176
177impl XChaCha20Poly1305Nonce {
178 pub fn new(bytes: [u8; 24]) -> Self {
180 Self(bytes)
181 }
182
183 pub fn generate() -> Self {
185 let mut nonce = [0u8; 24];
186 rand::rngs::OsRng.fill_bytes(&mut nonce);
187 Self(nonce)
188 }
189
190 pub fn as_bytes(&self) -> &[u8; 24] {
192 &self.0
193 }
194
195 pub fn from_string(s: &str) -> Result<Self> {
197 let bytes =
198 base64::decode(s).map_err(|_| dcrypt_api::error::Error::SerializationError {
199 context: "XChaCha20Poly1305 nonce base64 decode",
200 #[cfg(feature = "std")]
201 message: "invalid base64 encoding".to_string(),
202 })?;
203
204 validate::length("XChaCha20Poly1305 nonce", bytes.len(), 24)?;
205
206 let mut nonce = [0u8; 24];
207 nonce.copy_from_slice(&bytes);
208
209 Ok(Self(nonce))
210 }
211}
212
213impl fmt::Display for XChaCha20Poly1305Nonce {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(f, "{}", base64::encode(self.0))
216 }
217}
218
219impl Aead for XChaCha20Poly1305Cipher {
220 type Nonce = XChaCha20Poly1305Nonce;
221
222 fn encrypt(
223 &self,
224 nonce: &Self::Nonce,
225 plaintext: &[u8],
226 aad: Option<&[u8]>,
227 ) -> Result<Vec<u8>> {
228 let primitives_nonce = Nonce::<24>::from_slice(nonce.as_bytes())?;
230
231 self.cipher
233 .encrypt(&primitives_nonce, plaintext, aad)
234 .map_err(from_primitive_error)
235 }
236
237 fn decrypt(
238 &self,
239 nonce: &Self::Nonce,
240 ciphertext: &[u8],
241 aad: Option<&[u8]>,
242 ) -> Result<Vec<u8>> {
243 validate::min_length(
245 "XChaCha20Poly1305 ciphertext",
246 ciphertext.len(),
247 CHACHA20POLY1305_TAG_SIZE,
248 )?;
249
250 let primitives_nonce = Nonce::<24>::from_slice(nonce.as_bytes())?;
252
253 self.cipher
255 .decrypt(&primitives_nonce, ciphertext, aad)
256 .map_err(|e| match e {
257 PrimitiveError::Authentication { .. } => {
258 dcrypt_api::error::Error::AuthenticationFailed {
259 context: "XChaCha20Poly1305",
260 #[cfg(feature = "std")]
261 message: "authentication tag verification failed".to_string(),
262 }
263 }
264 _ => from_primitive_error(e),
265 })
266 }
267
268 fn generate_nonce() -> Self::Nonce {
269 XChaCha20Poly1305Nonce::generate()
270 }
271}
272
273impl XChaCha20Poly1305Cipher {
274 pub fn generate() -> Result<(Self, ChaCha20Poly1305Key)> {
276 let key = ChaCha20Poly1305Key::generate();
277 let cipher = Self::new(&key)?;
278 Ok((cipher, key))
279 }
280
281 pub fn encrypt_with_random_nonce(
283 &self,
284 plaintext: &[u8],
285 aad: Option<&[u8]>,
286 ) -> Result<(Vec<u8>, XChaCha20Poly1305Nonce)> {
287 let nonce = Self::generate_nonce();
288 let ciphertext = self.encrypt(&nonce, plaintext, aad)?;
289 Ok((ciphertext, nonce))
290 }
291
292 pub fn decrypt_and_verify(
294 &self,
295 ciphertext: &[u8],
296 nonce: &XChaCha20Poly1305Nonce,
297 aad: Option<&[u8]>,
298 ) -> Result<Vec<u8>> {
299 self.decrypt(nonce, ciphertext, aad)
300 }
301}