Skip to main content

dcrypt_algorithms/block/
mod.rs

1//! Block cipher implementations with advanced type-level guarantees
2//!
3//! This module contains implementations of various block ciphers and related
4//! algorithms with improved type-safety through compile-time constraints.
5//!
6//! ## Example usage
7//!
8//! ```
9//! use dcrypt_algorithms::block::{TypedAes128, TypedCbc, BlockCipher, BlockCipherMode, CipherAlgorithm};
10//! use dcrypt_internal::random::ChaCha20Rng;
11//!
12//! // Generate a random key and nonce
13//! let mut rng = ChaCha20Rng::from_seed([0x42; 32]);
14//! let key = TypedAes128::generate_key(&mut rng).unwrap();
15//! let nonce = TypedCbc::<TypedAes128>::generate_nonce(&mut rng).unwrap();
16//!
17//! // Create cipher and mode instances
18//! let cipher = TypedAes128::new(&key);
19//! let mode = TypedCbc::new(cipher, &nonce).unwrap();
20//!
21//! // Encrypt and decrypt
22//! let plaintext = b"secret message with padding...!!"; // Exactly 32 bytes (multiple of 16)
23//! let ciphertext = mode.encrypt(plaintext).unwrap();
24//! let decrypted = mode.decrypt(&ciphertext).unwrap();
25//!
26//! assert_eq!(plaintext, &decrypted[..]);
27//! ```
28
29#[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
43// Re-exports
44pub use aes::{Aes128, Aes192, Aes256};
45pub use modes::{cbc::Cbc, ctr::Ctr};
46
47/// Marker trait for cipher algorithms with compile-time properties
48pub trait CipherAlgorithm {
49    /// Key size in bytes
50    const KEY_SIZE: usize;
51
52    /// Block size in bytes
53    const BLOCK_SIZE: usize;
54
55    /// Algorithm name
56    fn name() -> &'static str;
57}
58
59/// Marker trait for specific AES key sizes
60pub trait AesVariant: CipherAlgorithm {
61    /// Number of rounds
62    const ROUNDS: usize;
63}
64
65/// Marker trait for block cipher operating modes
66pub trait CipherMode {
67    /// Mode name
68    fn name() -> &'static str;
69
70    /// Whether the mode requires initialization vector/nonce
71    const REQUIRES_IV: bool;
72
73    /// Whether this is an authenticated mode
74    const IS_AUTHENTICATED: bool;
75
76    /// Size of the nonce/IV in bytes (if applicable)
77    const IV_SIZE: usize;
78
79    /// Size of the tag in bytes (if applicable and authenticated)
80    const TAG_SIZE: Option<usize>;
81}
82
83/// Trait for block ciphers with type-level constraints
84pub trait BlockCipher {
85    /// The algorithm this cipher implements
86    type Algorithm: CipherAlgorithm;
87
88    /// Key type with appropriate size guarantee
89    type Key: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
90
91    /// Creates a new block cipher instance with the given key
92    fn new(key: &Self::Key) -> Self;
93
94    /// Encrypts a single block in place
95    fn encrypt_block(&self, block: &mut [u8]) -> Result<()>;
96
97    /// Decrypts a single block in place
98    fn decrypt_block(&self, block: &mut [u8]) -> Result<()>;
99
100    /// Returns the key size in bytes
101    fn key_size() -> usize {
102        Self::Algorithm::KEY_SIZE
103    }
104
105    /// Returns the block size in bytes
106    fn block_size() -> usize {
107        Self::Algorithm::BLOCK_SIZE
108    }
109
110    /// Returns the name of the block cipher
111    fn name() -> &'static str {
112        Self::Algorithm::name()
113    }
114
115    /// Generate a random key
116    fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key>;
117}
118
119/// Trait for block cipher modes with type parameters
120pub trait BlockCipherMode<C: BlockCipher> {
121    /// The mode this implementation uses
122    type Mode: CipherMode;
123
124    /// Nonce/IV type with appropriate size constraint
125    type Nonce: AsRef<[u8]> + AsMut<[u8]> + Clone;
126
127    /// Creates a new block cipher mode instance
128    fn new(cipher: C, nonce: &Self::Nonce) -> Result<Self>
129    where
130        Self: Sized;
131
132    /// Encrypts plaintext data
133    fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>>;
134
135    /// Decrypts ciphertext data
136    fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>>;
137
138    /// Generate a random nonce
139    fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Nonce>;
140
141    /// Returns the mode name
142    fn mode_name() -> &'static str {
143        Self::Mode::name()
144    }
145}
146
147/// Trait for authenticated block cipher modes
148pub trait AuthenticatedCipherMode<C: BlockCipher>: BlockCipherMode<C> {
149    /// Tag type with appropriate size constraint
150    type Tag: AsRef<[u8]> + AsMut<[u8]> + Clone;
151
152    /// Encrypts plaintext with associated data
153    fn encrypt_with_aad(&self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>>;
154
155    /// Decrypts ciphertext with associated data
156    fn decrypt_with_aad(&self, ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>>;
157
158    /// Returns the tag size in bytes
159    fn tag_size() -> usize {
160        Self::Mode::TAG_SIZE.unwrap_or(0)
161    }
162}
163
164/// Type-level constants for AES-128
165pub 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/// Enhanced AES-128 implementation with type-level guarantees
181#[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
200// Add the missing CipherAlgorithm implementation for TypedAes128
201impl 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
237/// Type-level constants for CBC mode
238pub 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; // For AES
244    const TAG_SIZE: Option<usize> = None;
245
246    fn name() -> &'static str {
247        "CBC"
248    }
249}
250
251/// Enhanced CBC mode implementation with type parameters
252pub 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 that the nonce size matches the block size
265        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        // Validate that plaintext is a multiple of block size
280        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        // Validate that ciphertext is a multiple of block size
293        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}