dcrypt_algorithms/block/
mod.rs1#[cfg(feature = "alloc")]
30extern crate alloc;
31
32#[cfg(not(feature = "std"))]
33use alloc::vec::Vec;
34use dcrypt_internal::zeroing::{Zeroize, ZeroizeOnDrop, Zeroizing};
35
36use crate::error::{validate, Error, Result};
37use crate::types::{Nonce, SecretBytes};
38use dcrypt_internal::random::{try_fill_bytes_zeroing_on_error, CryptoRng, RngCore};
39
40pub mod aes;
41pub mod modes;
42
43pub use aes::{Aes128, Aes192, Aes256};
45pub use modes::{cbc::Cbc, ctr::Ctr};
46
47pub trait CipherAlgorithm {
49 const KEY_SIZE: usize;
51
52 const BLOCK_SIZE: usize;
54
55 fn name() -> &'static str;
57}
58
59pub trait AesVariant: CipherAlgorithm {
61 const ROUNDS: usize;
63}
64
65pub trait CipherMode {
67 fn name() -> &'static str;
69
70 const REQUIRES_IV: bool;
72
73 const IS_AUTHENTICATED: bool;
75
76 const IV_SIZE: usize;
78
79 const TAG_SIZE: Option<usize>;
81}
82
83pub trait BlockCipher {
85 type Algorithm: CipherAlgorithm;
87
88 type Key: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
90
91 fn new(key: &Self::Key) -> Self;
93
94 fn encrypt_block(&self, block: &mut [u8]) -> Result<()>;
96
97 fn decrypt_block(&self, block: &mut [u8]) -> Result<()>;
99
100 fn key_size() -> usize {
102 Self::Algorithm::KEY_SIZE
103 }
104
105 fn block_size() -> usize {
107 Self::Algorithm::BLOCK_SIZE
108 }
109
110 fn name() -> &'static str {
112 Self::Algorithm::name()
113 }
114
115 fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key>;
117}
118
119pub trait BlockCipherMode<C: BlockCipher> {
121 type Mode: CipherMode;
123
124 type Nonce: AsRef<[u8]> + AsMut<[u8]> + Clone;
126
127 fn new(cipher: C, nonce: &Self::Nonce) -> Result<Self>
129 where
130 Self: Sized;
131
132 fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>>;
134
135 fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>>;
137
138 fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Nonce>;
140
141 fn mode_name() -> &'static str {
143 Self::Mode::name()
144 }
145}
146
147pub trait AuthenticatedCipherMode<C: BlockCipher>: BlockCipherMode<C> {
149 type Tag: AsRef<[u8]> + AsMut<[u8]> + Clone;
151
152 fn encrypt_with_aad(&self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>>;
154
155 fn decrypt_with_aad(&self, ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>>;
157
158 fn tag_size() -> usize {
160 Self::Mode::TAG_SIZE.unwrap_or(0)
161 }
162}
163
164pub enum Aes128Algorithm {}
166
167impl CipherAlgorithm for Aes128Algorithm {
168 const KEY_SIZE: usize = 16;
169 const BLOCK_SIZE: usize = 16;
170
171 fn name() -> &'static str {
172 "AES-128"
173 }
174}
175
176impl AesVariant for Aes128Algorithm {
177 const ROUNDS: usize = 10;
178}
179
180#[derive(Clone)]
182pub struct TypedAes128 {
183 inner: aes::Aes128,
184}
185
186impl Zeroize for TypedAes128 {
187 fn zeroize(&mut self) {
188 self.inner.zeroize();
189 }
190}
191
192impl Drop for TypedAes128 {
193 fn drop(&mut self) {
194 self.zeroize();
195 }
196}
197
198impl ZeroizeOnDrop for TypedAes128 {}
199
200impl CipherAlgorithm for TypedAes128 {
202 const KEY_SIZE: usize = 16;
203 const BLOCK_SIZE: usize = 16;
204
205 fn name() -> &'static str {
206 "AES-128"
207 }
208}
209
210impl BlockCipher for TypedAes128 {
211 type Algorithm = Aes128Algorithm;
212 type Key = SecretBytes<16>;
213
214 fn new(key: &Self::Key) -> Self {
215 Self {
216 inner: aes::Aes128::new(key),
217 }
218 }
219
220 fn encrypt_block(&self, block: &mut [u8]) -> Result<()> {
221 validate::length("AES-128 block", block.len(), Self::Algorithm::BLOCK_SIZE)?;
222 self.inner.encrypt_block(block)
223 }
224
225 fn decrypt_block(&self, block: &mut [u8]) -> Result<()> {
226 validate::length("AES-128 block", block.len(), Self::Algorithm::BLOCK_SIZE)?;
227 self.inner.decrypt_block(block)
228 }
229
230 fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key> {
231 let mut key = Zeroizing::new([0u8; 16]);
232 try_fill_bytes_zeroing_on_error(rng, &mut key[..])?;
233 Ok(SecretBytes::new(*key))
234 }
235}
236
237pub enum CbcMode {}
239
240impl CipherMode for CbcMode {
241 const REQUIRES_IV: bool = true;
242 const IS_AUTHENTICATED: bool = false;
243 const IV_SIZE: usize = 16; const TAG_SIZE: Option<usize> = None;
245
246 fn name() -> &'static str {
247 "CBC"
248 }
249}
250
251pub struct TypedCbc<C: BlockCipher + CipherAlgorithm + Zeroize + ZeroizeOnDrop> {
253 inner: modes::cbc::Cbc<C>,
254 _phantom: core::marker::PhantomData<C>,
255}
256
257impl<C: BlockCipher + CipherAlgorithm + Zeroize + ZeroizeOnDrop> BlockCipherMode<C>
258 for TypedCbc<C>
259{
260 type Mode = CbcMode;
261 type Nonce = Nonce<16>;
262
263 fn new(cipher: C, nonce: &Self::Nonce) -> Result<Self> {
264 validate::length(
266 "CBC initialization vector",
267 nonce.as_ref().len(),
268 C::BLOCK_SIZE,
269 )?;
270
271 let inner = modes::cbc::Cbc::new(cipher, nonce)?;
272 Ok(Self {
273 inner,
274 _phantom: core::marker::PhantomData,
275 })
276 }
277
278 fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
279 if plaintext.len() % C::BLOCK_SIZE != 0 {
281 return Err(Error::Length {
282 context: "CBC plaintext",
283 expected: ((plaintext.len() / C::BLOCK_SIZE) + 1) * C::BLOCK_SIZE,
284 actual: plaintext.len(),
285 });
286 }
287
288 self.inner.encrypt(plaintext)
289 }
290
291 fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
292 if ciphertext.len() % C::BLOCK_SIZE != 0 {
294 return Err(Error::Length {
295 context: "CBC ciphertext",
296 expected: ((ciphertext.len() / C::BLOCK_SIZE) + 1) * C::BLOCK_SIZE,
297 actual: ciphertext.len(),
298 });
299 }
300
301 self.inner.decrypt(ciphertext)
302 }
303
304 fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Nonce> {
305 let mut nonce = [0u8; 16];
306 try_fill_bytes_zeroing_on_error(rng, &mut nonce)?;
307 Ok(Nonce::new(nonce))
308 }
309}