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 rand::rngs::OsRng;
11//!
12//! // Generate a random key and nonce
13//! let key = TypedAes128::generate_key(&mut OsRng);
14//! let nonce = TypedCbc::<TypedAes128>::generate_nonce(&mut OsRng);
15//!
16//! // Create cipher and mode instances
17//! let cipher = TypedAes128::new(&key);
18//! let mode = TypedCbc::new(cipher, &nonce).unwrap();
19//!
20//! // Encrypt and decrypt
21//! let plaintext = b"secret message with padding...!!"; // Exactly 32 bytes (multiple of 16)
22//! let ciphertext = mode.encrypt(plaintext).unwrap();
23//! let decrypted = mode.decrypt(&ciphertext).unwrap();
24//!
25//! assert_eq!(plaintext, &decrypted[..]);
26//! ```
27
28#![cfg_attr(not(feature = "std"), no_std)]
29
30#[cfg(feature = "alloc")]
31extern crate alloc;
32
33#[cfg(not(feature = "std"))]
34use alloc::vec::Vec;
35use zeroize::{Zeroize, ZeroizeOnDrop};
36
37use crate::error::{validate, Error, Result};
38use crate::types::{Nonce, SecretBytes};
39use rand::{CryptoRng, RngCore};
40
41pub mod aes;
42pub mod modes;
43
44// Re-exports
45pub use aes::{Aes128, Aes192, Aes256};
46pub use modes::{cbc::Cbc, ctr::Ctr};
47
48/// Marker trait for cipher algorithms with compile-time properties
49pub trait CipherAlgorithm {
50    /// Key size in bytes
51    const KEY_SIZE: usize;
52
53    /// Block size in bytes
54    const BLOCK_SIZE: usize;
55
56    /// Algorithm name
57    fn name() -> &'static str;
58}
59
60/// Marker trait for specific AES key sizes
61pub trait AesVariant: CipherAlgorithm {
62    /// Number of rounds
63    const ROUNDS: usize;
64}
65
66/// Marker trait for block cipher operating modes
67pub trait CipherMode {
68    /// Mode name
69    fn name() -> &'static str;
70
71    /// Whether the mode requires initialization vector/nonce
72    const REQUIRES_IV: bool;
73
74    /// Whether this is an authenticated mode
75    const IS_AUTHENTICATED: bool;
76
77    /// Size of the nonce/IV in bytes (if applicable)
78    const IV_SIZE: usize;
79
80    /// Size of the tag in bytes (if applicable and authenticated)
81    const TAG_SIZE: Option<usize>;
82}
83
84/// Trait for block ciphers with type-level constraints
85pub trait BlockCipher {
86    /// The algorithm this cipher implements
87    type Algorithm: CipherAlgorithm;
88
89    /// Key type with appropriate size guarantee
90    type Key: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
91
92    /// Creates a new block cipher instance with the given key
93    fn new(key: &Self::Key) -> Self;
94
95    /// Encrypts a single block in place
96    fn encrypt_block(&self, block: &mut [u8]) -> Result<()>;
97
98    /// Decrypts a single block in place
99    fn decrypt_block(&self, block: &mut [u8]) -> Result<()>;
100
101    /// Returns the key size in bytes
102    fn key_size() -> usize {
103        Self::Algorithm::KEY_SIZE
104    }
105
106    /// Returns the block size in bytes
107    fn block_size() -> usize {
108        Self::Algorithm::BLOCK_SIZE
109    }
110
111    /// Returns the name of the block cipher
112    fn name() -> &'static str {
113        Self::Algorithm::name()
114    }
115
116    /// Generate a random key
117    fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Key;
118}
119
120/// Trait for block cipher modes with type parameters
121pub trait BlockCipherMode<C: BlockCipher> {
122    /// The mode this implementation uses
123    type Mode: CipherMode;
124
125    /// Nonce/IV type with appropriate size constraint
126    type Nonce: AsRef<[u8]> + AsMut<[u8]> + Clone;
127
128    /// Creates a new block cipher mode instance
129    fn new(cipher: C, nonce: &Self::Nonce) -> Result<Self>
130    where
131        Self: Sized;
132
133    /// Encrypts plaintext data
134    fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>>;
135
136    /// Decrypts ciphertext data
137    fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>>;
138
139    /// Generate a random nonce
140    fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Nonce;
141
142    /// Returns the mode name
143    fn mode_name() -> &'static str {
144        Self::Mode::name()
145    }
146}
147
148/// Trait for authenticated block cipher modes
149pub trait AuthenticatedCipherMode<C: BlockCipher>: BlockCipherMode<C> {
150    /// Tag type with appropriate size constraint
151    type Tag: AsRef<[u8]> + AsMut<[u8]> + Clone;
152
153    /// Encrypts plaintext with associated data
154    fn encrypt_with_aad(&self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>>;
155
156    /// Decrypts ciphertext with associated data
157    fn decrypt_with_aad(&self, ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>>;
158
159    /// Returns the tag size in bytes
160    fn tag_size() -> usize {
161        Self::Mode::TAG_SIZE.unwrap_or(0)
162    }
163}
164
165/// Type-level constants for AES-128
166pub enum Aes128Algorithm {}
167
168impl CipherAlgorithm for Aes128Algorithm {
169    const KEY_SIZE: usize = 16;
170    const BLOCK_SIZE: usize = 16;
171
172    fn name() -> &'static str {
173        "AES-128"
174    }
175}
176
177impl AesVariant for Aes128Algorithm {
178    const ROUNDS: usize = 10;
179}
180
181/// Enhanced AES-128 implementation with type-level guarantees
182#[derive(Clone, Zeroize, ZeroizeOnDrop)]
183pub struct TypedAes128 {
184    inner: aes::Aes128,
185}
186
187// Add the missing CipherAlgorithm implementation for TypedAes128
188impl CipherAlgorithm for TypedAes128 {
189    const KEY_SIZE: usize = 16;
190    const BLOCK_SIZE: usize = 16;
191
192    fn name() -> &'static str {
193        "AES-128"
194    }
195}
196
197impl BlockCipher for TypedAes128 {
198    type Algorithm = Aes128Algorithm;
199    type Key = SecretBytes<16>;
200
201    fn new(key: &Self::Key) -> Self {
202        Self {
203            inner: aes::Aes128::new(key),
204        }
205    }
206
207    fn encrypt_block(&self, block: &mut [u8]) -> Result<()> {
208        validate::length("AES-128 block", block.len(), Self::Algorithm::BLOCK_SIZE)?;
209        self.inner.encrypt_block(block)
210    }
211
212    fn decrypt_block(&self, block: &mut [u8]) -> Result<()> {
213        validate::length("AES-128 block", block.len(), Self::Algorithm::BLOCK_SIZE)?;
214        self.inner.decrypt_block(block)
215    }
216
217    fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Key {
218        let mut key = [0u8; 16];
219        rng.fill_bytes(&mut key);
220        SecretBytes::new(key)
221    }
222}
223
224/// Type-level constants for CBC mode
225pub enum CbcMode {}
226
227impl CipherMode for CbcMode {
228    const REQUIRES_IV: bool = true;
229    const IS_AUTHENTICATED: bool = false;
230    const IV_SIZE: usize = 16; // For AES
231    const TAG_SIZE: Option<usize> = None;
232
233    fn name() -> &'static str {
234        "CBC"
235    }
236}
237
238/// Enhanced CBC mode implementation with type parameters
239pub struct TypedCbc<C: BlockCipher + CipherAlgorithm + Zeroize + ZeroizeOnDrop> {
240    inner: modes::cbc::Cbc<C>,
241    _phantom: core::marker::PhantomData<C>,
242}
243
244impl<C: BlockCipher + CipherAlgorithm + Zeroize + ZeroizeOnDrop> BlockCipherMode<C>
245    for TypedCbc<C>
246{
247    type Mode = CbcMode;
248    type Nonce = Nonce<16>;
249
250    fn new(cipher: C, nonce: &Self::Nonce) -> Result<Self> {
251        // Validate that the nonce size matches the block size
252        validate::length(
253            "CBC initialization vector",
254            nonce.as_ref().len(),
255            C::BLOCK_SIZE,
256        )?;
257
258        let inner = modes::cbc::Cbc::new(cipher, nonce)?;
259        Ok(Self {
260            inner,
261            _phantom: core::marker::PhantomData,
262        })
263    }
264
265    fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
266        // Validate that plaintext is a multiple of block size
267        if plaintext.len() % C::BLOCK_SIZE != 0 {
268            return Err(Error::Length {
269                context: "CBC plaintext",
270                expected: ((plaintext.len() / C::BLOCK_SIZE) + 1) * C::BLOCK_SIZE,
271                actual: plaintext.len(),
272            });
273        }
274
275        self.inner.encrypt(plaintext)
276    }
277
278    fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
279        // Validate that ciphertext is a multiple of block size
280        if ciphertext.len() % C::BLOCK_SIZE != 0 {
281            return Err(Error::Length {
282                context: "CBC ciphertext",
283                expected: ((ciphertext.len() / C::BLOCK_SIZE) + 1) * C::BLOCK_SIZE,
284                actual: ciphertext.len(),
285            });
286        }
287
288        self.inner.decrypt(ciphertext)
289    }
290
291    fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Nonce {
292        let mut nonce = [0u8; 16];
293        rng.fill_bytes(&mut nonce);
294        Nonce::new(nonce)
295    }
296}