Skip to main content

dcrypt_algorithms/block/aes/
mod.rs

1//! AES block cipher implementations
2//!
3//! This module implements the Advanced Encryption Standard (AES) block cipher
4//! as specified in FIPS 197.
5//!
6//! ## Timing-sensitive implementation properties
7//!
8//! This implementation mitigates timing side-channel attacks by:
9//! - Using branchless arithmetic for GF(2^8) operations
10//! - Using bitsliced S-box implementations instead of table lookups
11//! - Ensuring consistent memory access patterns
12//! - Validating keys before use to prevent silent failure
13//!
14//! These source-level properties are not a blanket compiler- or target-level
15//! constant-time guarantee. Release gates inspect supported target builds.
16//!
17//! Note: On platforms where AES hardware acceleration is available, consider using
18//! hardware instructions for better side-channel resistance.
19
20use super::BlockCipher;
21use super::CipherAlgorithm;
22use crate::error::{validate, Result};
23use crate::types::SecretBytes;
24use core::sync::atomic::{compiler_fence, Ordering};
25use dcrypt_common::security::SecretBuffer;
26use dcrypt_internal::random::{try_fill_bytes_zeroing_on_error, CryptoRng, RngCore};
27use dcrypt_internal::zeroing::{Zeroize, ZeroizeOnDrop, Zeroizing};
28use dcrypt_params::utils::symmetric::{
29    AES128_KEY_SIZE, AES192_KEY_SIZE, AES256_KEY_SIZE, AES_BLOCK_SIZE,
30};
31
32/// Round constants for AES key expansion
33const RCON: [u32; 11] = [
34    0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000,
35    0x80000000, 0x1b000000, 0x36000000,
36];
37
38/// Multiply two bytes in GF(2⁸) with AES's reduction poly x⁸ + x⁴ + x³ + x + 1
39#[inline(always)]
40fn gf_mul(a: u8, b: u8) -> u8 {
41    let mut p = 0u8;
42    let mut a = a;
43    let mut b = b;
44    for _ in 0..8 {
45        // mask = 0xFF if b&1==1 else 0x00
46        let mask = (b & 1).wrapping_neg();
47        p ^= a & mask;
48        let hi = a & 0x80;
49        a <<= 1;
50        // if hi was set, reduce by 0x1B
51        a ^= ((hi != 0) as u8) * 0x1B;
52        b >>= 1;
53    }
54    p
55}
56
57/// Raise to the 254th power (b⁻¹ in GF(2⁸)) in constant time
58#[inline(always)]
59fn gf_inv(x: u8) -> u8 {
60    // always do the full exponentiation, even for x==0
61    let x2 = gf_mul(x, x);
62    let x4 = gf_mul(x2, x2);
63    let x8 = gf_mul(x4, x4);
64    let x16 = gf_mul(x8, x8);
65    let x32 = gf_mul(x16, x16);
66    let x64 = gf_mul(x32, x32);
67    let x128 = gf_mul(x64, x64);
68    // now multiply together x128·x64·x32·x16·x8·x4·x2
69    let mut y = gf_mul(x128, x64);
70    y = gf_mul(y, x32);
71    y = gf_mul(y, x16);
72    y = gf_mul(y, x8);
73    y = gf_mul(y, x4);
74    y = gf_mul(y, x2);
75
76    // now mask to zero if original x was zero
77    // mask = 0xFF if x!=0, else 0x00
78    let mask = ((x != 0) as u8).wrapping_neg();
79    y & mask
80}
81
82/// AES forward S-box: inv(x) ⊕ ROTL(inv(x),1–4) ⊕ 0x63
83#[inline(always)]
84fn bitsliced_sbox(x: u8) -> u8 {
85    let i = gf_inv(x);
86    i ^ i.rotate_left(1) ^ i.rotate_left(2) ^ i.rotate_left(3) ^ i.rotate_left(4) ^ 0x63
87}
88
89/// AES inverse S-box: undo affine then invert
90#[inline(always)]
91fn bitsliced_inv_sbox(x: u8) -> u8 {
92    // undo affine: y = A(i)⊕0x63  ⇒  i = A⁻¹(y)
93    let y = x ^ 0x63;
94    // A⁻¹ is convolution by t¹ + t³ + t⁶ mod (t⁸+1)
95    let u = y.rotate_left(1) ^ y.rotate_left(3) ^ y.rotate_left(6);
96    gf_inv(u)
97}
98
99/// Converts 4 bytes to a u32 in big-endian order
100#[inline(always)]
101fn bytes_to_u32(bytes: &[u8]) -> u32 {
102    ((bytes[0] as u32) << 24)
103        | ((bytes[1] as u32) << 16)
104        | ((bytes[2] as u32) << 8)
105        | (bytes[3] as u32)
106}
107
108/// Converts a u32 to 4 bytes in big-endian order
109#[inline(always)]
110fn u32_to_bytes(word: u32) -> [u8; 4] {
111    [
112        (word >> 24) as u8,
113        (word >> 16) as u8,
114        (word >> 8) as u8,
115        word as u8,
116    ]
117}
118
119/// Rotates a word left by 8 bits (1 byte)
120#[inline(always)]
121fn rotate_word(word: u32) -> u32 {
122    word.rotate_left(8)
123}
124
125/// Substitutes each byte in a word using the AES S-box, with bitsliced implementation
126#[inline(always)]
127fn sub_word(word: u32) -> u32 {
128    let bytes = Zeroizing::new(u32_to_bytes(word));
129    let sub_bytes = Zeroizing::new([
130        bitsliced_sbox(bytes[0]),
131        bitsliced_sbox(bytes[1]),
132        bitsliced_sbox(bytes[2]),
133        bitsliced_sbox(bytes[3]),
134    ]);
135    bytes_to_u32(&sub_bytes[..])
136}
137
138/// Type-level constants for AES-128
139pub enum Aes128Algorithm {}
140
141impl CipherAlgorithm for Aes128Algorithm {
142    const KEY_SIZE: usize = AES128_KEY_SIZE;
143    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
144
145    fn name() -> &'static str {
146        "AES-128"
147    }
148}
149
150/// Type-level constants for AES-192
151pub enum Aes192Algorithm {}
152
153impl CipherAlgorithm for Aes192Algorithm {
154    const KEY_SIZE: usize = AES192_KEY_SIZE;
155    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
156
157    fn name() -> &'static str {
158        "AES-192"
159    }
160}
161
162/// Type-level constants for AES-256
163pub enum Aes256Algorithm {}
164
165impl CipherAlgorithm for Aes256Algorithm {
166    const KEY_SIZE: usize = AES256_KEY_SIZE;
167    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
168
169    fn name() -> &'static str {
170        "AES-256"
171    }
172}
173
174/// AES-128 block cipher
175#[derive(Clone)]
176pub struct Aes128 {
177    round_keys: SecretBuffer<176>, // 11 rounds × 16 bytes
178}
179
180/// AES-192 block cipher
181#[derive(Clone)]
182pub struct Aes192 {
183    round_keys: SecretBuffer<208>, // 13 rounds × 16 bytes
184}
185
186/// AES-256 block cipher
187#[derive(Clone)]
188pub struct Aes256 {
189    round_keys: SecretBuffer<240>, // 15 rounds × 16 bytes
190}
191
192macro_rules! impl_aes_zeroize {
193    ($name:ident) => {
194        impl Zeroize for $name {
195            fn zeroize(&mut self) {
196                self.round_keys.zeroize();
197            }
198        }
199
200        impl Drop for $name {
201            fn drop(&mut self) {
202                self.zeroize();
203            }
204        }
205
206        impl ZeroizeOnDrop for $name {}
207    };
208}
209
210impl_aes_zeroize!(Aes128);
211impl_aes_zeroize!(Aes192);
212impl_aes_zeroize!(Aes256);
213
214// Add CipherAlgorithm implementations for AES structs
215impl CipherAlgorithm for Aes128 {
216    const KEY_SIZE: usize = AES128_KEY_SIZE;
217    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
218
219    fn name() -> &'static str {
220        "AES-128"
221    }
222}
223
224impl CipherAlgorithm for Aes192 {
225    const KEY_SIZE: usize = AES192_KEY_SIZE;
226    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
227
228    fn name() -> &'static str {
229        "AES-192"
230    }
231}
232
233impl CipherAlgorithm for Aes256 {
234    const KEY_SIZE: usize = AES256_KEY_SIZE;
235    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
236
237    fn name() -> &'static str {
238        "AES-256"
239    }
240}
241
242impl Aes128 {
243    /// Performs AES-128 key expansion
244    fn expand_key(key: &[u8]) -> Result<SecretBuffer<176>> {
245        validate::length("AES-128 key", key.len(), AES128_KEY_SIZE)?;
246
247        let mut round_keys_u32 = Zeroizing::new([0u32; 44]);
248
249        // Initial key schedule
250        for i in 0..4 {
251            round_keys_u32[i] = bytes_to_u32(&key[i * 4..(i + 1) * 4]);
252        }
253
254        // Key expansion
255        for i in 4..44 {
256            let mut temp = Zeroizing::new(round_keys_u32[i - 1]);
257            if i % 4 == 0 {
258                *temp = sub_word(rotate_word(*temp)) ^ RCON[i / 4];
259            }
260            round_keys_u32[i] = round_keys_u32[i - 4] ^ *temp;
261        }
262
263        // Convert to bytes
264        let mut round_key_bytes = Zeroizing::new([0u8; 176]);
265        for i in 0..44 {
266            let bytes = Zeroizing::new(u32_to_bytes(round_keys_u32[i]));
267            round_key_bytes[i * 4..(i + 1) * 4].copy_from_slice(&bytes[..]);
268        }
269
270        Ok(SecretBuffer::new(*round_key_bytes))
271    }
272
273    /// SubBytes step with bitsliced implementation
274    fn sub_bytes(state: &mut [u8; 16]) {
275        for byte in state.iter_mut() {
276            *byte = bitsliced_sbox(*byte);
277        }
278        // ensure no reordering around our bit-ops
279        compiler_fence(Ordering::SeqCst);
280    }
281
282    /// ShiftRows step
283    fn shift_rows(state: &mut [u8; 16]) {
284        let mut temp = Zeroizing::new([0u8; 16]);
285        temp.copy_from_slice(state);
286        state[0] = temp[0];
287        state[4] = temp[4];
288        state[8] = temp[8];
289        state[12] = temp[12];
290        state[1] = temp[5];
291        state[5] = temp[9];
292        state[9] = temp[13];
293        state[13] = temp[1];
294        state[2] = temp[10];
295        state[6] = temp[14];
296        state[10] = temp[2];
297        state[14] = temp[6];
298        state[3] = temp[15];
299        state[7] = temp[3];
300        state[11] = temp[7];
301        state[15] = temp[11];
302    }
303
304    /// Multiply by 2 in GF(2^8)
305    #[inline(always)]
306    fn mul2(byte: u8) -> u8 {
307        let high = byte >> 7;
308        (byte << 1) ^ (high * 0x1B)
309    }
310
311    /// MixColumns step
312    fn mix_columns(state: &mut [u8; 16]) {
313        for c in 0..4 {
314            let i = c * 4;
315            let s0 = state[i];
316            let s1 = state[i + 1];
317            let s2 = state[i + 2];
318            let s3 = state[i + 3];
319            state[i] = Self::mul2(s0) ^ Self::mul2(s1) ^ s1 ^ s2 ^ s3;
320            state[i + 1] = s0 ^ Self::mul2(s1) ^ Self::mul2(s2) ^ s2 ^ s3;
321            state[i + 2] = s0 ^ s1 ^ Self::mul2(s2) ^ Self::mul2(s3) ^ s3;
322            state[i + 3] = Self::mul2(s0) ^ s0 ^ s1 ^ s2 ^ Self::mul2(s3);
323        }
324    }
325
326    /// AddRoundKey step using precomputed bytes for constant-time behavior
327    fn add_round_key(state: &mut [u8; 16], round_key_bytes: &[u8]) -> Result<()> {
328        // Use validation utility for length check
329        validate::min_length("AES round key", round_key_bytes.len(), 16)?;
330
331        for i in 0..16 {
332            state[i] ^= round_key_bytes[i];
333        }
334        Ok(())
335    }
336
337    /// Inverse SubBytes with bitsliced implementation
338    fn inv_sub_bytes(state: &mut [u8; 16]) {
339        for byte in state.iter_mut() {
340            *byte = bitsliced_inv_sbox(*byte);
341        }
342        compiler_fence(Ordering::SeqCst);
343    }
344
345    /// Inverse ShiftRows
346    fn inv_shift_rows(state: &mut [u8; 16]) {
347        let mut temp = Zeroizing::new([0u8; 16]);
348        temp.copy_from_slice(state);
349        state[0] = temp[0];
350        state[4] = temp[4];
351        state[8] = temp[8];
352        state[12] = temp[12];
353        state[1] = temp[13];
354        state[5] = temp[1];
355        state[9] = temp[5];
356        state[13] = temp[9];
357        state[2] = temp[10];
358        state[6] = temp[14];
359        state[10] = temp[2];
360        state[14] = temp[6];
361        state[3] = temp[7];
362        state[7] = temp[11];
363        state[11] = temp[15];
364        state[15] = temp[3];
365    }
366
367    /// GF(2^8) multiplies for InvMixColumns
368    #[inline(always)]
369    fn mul14(byte: u8) -> u8 {
370        Self::mul2(Self::mul2(Self::mul2(byte))) ^ Self::mul2(Self::mul2(byte)) ^ Self::mul2(byte)
371    }
372    #[inline(always)]
373    fn mul13(byte: u8) -> u8 {
374        Self::mul2(Self::mul2(Self::mul2(byte))) ^ Self::mul2(Self::mul2(byte)) ^ byte
375    }
376    #[inline(always)]
377    fn mul11(byte: u8) -> u8 {
378        Self::mul2(Self::mul2(Self::mul2(byte))) ^ Self::mul2(byte) ^ byte
379    }
380    #[inline(always)]
381    fn mul9(byte: u8) -> u8 {
382        Self::mul2(Self::mul2(Self::mul2(byte))) ^ byte
383    }
384
385    /// Inverse MixColumns
386    fn inv_mix_columns(state: &mut [u8; 16]) {
387        for c in 0..4 {
388            let i = c * 4;
389            let s0 = state[i];
390            let s1 = state[i + 1];
391            let s2 = state[i + 2];
392            let s3 = state[i + 3];
393            state[i] = Self::mul14(s0) ^ Self::mul11(s1) ^ Self::mul13(s2) ^ Self::mul9(s3);
394            state[i + 1] = Self::mul9(s0) ^ Self::mul14(s1) ^ Self::mul11(s2) ^ Self::mul13(s3);
395            state[i + 2] = Self::mul13(s0) ^ Self::mul9(s1) ^ Self::mul14(s2) ^ Self::mul11(s3);
396            state[i + 3] = Self::mul11(s0) ^ Self::mul13(s1) ^ Self::mul9(s2) ^ Self::mul14(s3);
397        }
398    }
399}
400
401impl BlockCipher for Aes128 {
402    type Algorithm = Aes128Algorithm;
403    type Key = SecretBytes<16>;
404
405    fn new(key: &Self::Key) -> Self {
406        let round_keys =
407            Self::expand_key(key.as_ref()).expect("AES-128 key expansion should not fail");
408
409        Aes128 { round_keys }
410    }
411
412    fn encrypt_block(&self, block: &mut [u8]) -> Result<()> {
413        // Use validation utility for length check
414        validate::length("AES block", block.len(), AES_BLOCK_SIZE)?;
415
416        // Access round keys through SecretBuffer
417        let round_key_bytes = self.round_keys.as_ref();
418
419        // Warm the cache by touching all round key bytes
420        let mut _warm: u8 = 0;
421        for &b in round_key_bytes {
422            _warm = _warm.wrapping_add(b);
423        }
424        compiler_fence(Ordering::SeqCst);
425
426        // Copy block to state array
427        let mut state = Zeroizing::new([0u8; 16]);
428        state.copy_from_slice(block);
429
430        // Initial round - AddRoundKey
431        Self::add_round_key(&mut state, &round_key_bytes[0..16])?;
432
433        // Main rounds
434        for round in 1..10 {
435            Self::sub_bytes(&mut state);
436            Self::shift_rows(&mut state);
437            Self::mix_columns(&mut state);
438
439            let offset = round * 16;
440            Self::add_round_key(&mut state, &round_key_bytes[offset..offset + 16])?;
441        }
442
443        // Final round
444        Self::sub_bytes(&mut state);
445        Self::shift_rows(&mut state);
446        Self::add_round_key(&mut state, &round_key_bytes[160..176])?;
447
448        // Copy state back to block
449        block.copy_from_slice(&state[..]);
450        Ok(())
451    }
452
453    fn decrypt_block(&self, block: &mut [u8]) -> Result<()> {
454        // Use validation utility for length check
455        validate::length("AES block", block.len(), AES_BLOCK_SIZE)?;
456
457        // Access round keys through SecretBuffer
458        let round_key_bytes = self.round_keys.as_ref();
459
460        // Warm the cache by touching all round key bytes
461        let mut _warm: u8 = 0;
462        for &b in round_key_bytes {
463            _warm = _warm.wrapping_add(b);
464        }
465        compiler_fence(Ordering::SeqCst);
466
467        // Copy block to state array
468        let mut state = Zeroizing::new([0u8; 16]);
469        state.copy_from_slice(block);
470
471        // Initial round - AddRoundKey (final round key)
472        Self::add_round_key(&mut state, &round_key_bytes[160..176])?;
473
474        // Main rounds in reverse
475        for round in (1..10).rev() {
476            Self::inv_shift_rows(&mut state);
477            Self::inv_sub_bytes(&mut state);
478
479            let offset = round * 16;
480            Self::add_round_key(&mut state, &round_key_bytes[offset..offset + 16])?;
481            Self::inv_mix_columns(&mut state);
482        }
483
484        // Final round
485        Self::inv_shift_rows(&mut state);
486        Self::inv_sub_bytes(&mut state);
487        Self::add_round_key(&mut state, &round_key_bytes[0..16])?;
488
489        // Copy state back to block
490        block.copy_from_slice(&state[..]);
491        Ok(())
492    }
493
494    fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key> {
495        let mut key_data = Zeroizing::new([0u8; AES128_KEY_SIZE]);
496        try_fill_bytes_zeroing_on_error(rng, &mut key_data[..])?;
497        Ok(SecretBytes::new(*key_data))
498    }
499}
500
501// AES-192 implementation
502
503impl Aes192 {
504    /// Performs AES-192 key expansion
505    fn expand_key(key: &[u8]) -> Result<SecretBuffer<208>> {
506        validate::length("AES-192 key", key.len(), AES192_KEY_SIZE)?;
507
508        let mut round_keys_u32 = Zeroizing::new([0u32; 52]);
509
510        // Initial key schedule
511        for i in 0..6 {
512            round_keys_u32[i] = bytes_to_u32(&key[i * 4..(i + 1) * 4]);
513        }
514
515        // Key expansion
516        for i in 6..52 {
517            let mut temp = Zeroizing::new(round_keys_u32[i - 1]);
518            if i % 6 == 0 {
519                *temp = sub_word(rotate_word(*temp)) ^ RCON[i / 6];
520            }
521            round_keys_u32[i] = round_keys_u32[i - 6] ^ *temp;
522        }
523
524        // Convert to bytes
525        let mut round_key_bytes = Zeroizing::new([0u8; 208]);
526        for i in 0..52 {
527            let bytes = Zeroizing::new(u32_to_bytes(round_keys_u32[i]));
528            round_key_bytes[i * 4..(i + 1) * 4].copy_from_slice(&bytes[..]);
529        }
530
531        Ok(SecretBuffer::new(*round_key_bytes))
532    }
533}
534
535impl BlockCipher for Aes192 {
536    type Algorithm = Aes192Algorithm;
537    type Key = SecretBytes<24>;
538
539    fn new(key: &Self::Key) -> Self {
540        let round_keys =
541            Self::expand_key(key.as_ref()).expect("AES-192 key expansion should not fail");
542
543        Aes192 { round_keys }
544    }
545
546    fn encrypt_block(&self, block: &mut [u8]) -> Result<()> {
547        // Use validation utility for length check
548        validate::length("AES block", block.len(), AES_BLOCK_SIZE)?;
549
550        // Access round keys through SecretBuffer
551        let round_key_bytes = self.round_keys.as_ref();
552
553        // Warm the cache by touching all round key bytes
554        let mut _warm: u8 = 0;
555        for &b in round_key_bytes {
556            _warm = _warm.wrapping_add(b);
557        }
558        compiler_fence(Ordering::SeqCst);
559
560        // Copy block to state array
561        let mut state = Zeroizing::new([0u8; 16]);
562        state.copy_from_slice(block);
563
564        // Initial round - AddRoundKey
565        Aes128::add_round_key(&mut state, &round_key_bytes[0..16])?;
566
567        // Main rounds
568        for round in 1..12 {
569            Aes128::sub_bytes(&mut state);
570            Aes128::shift_rows(&mut state);
571            Aes128::mix_columns(&mut state);
572
573            let offset = round * 16;
574            Aes128::add_round_key(&mut state, &round_key_bytes[offset..offset + 16])?;
575        }
576
577        // Final round
578        Aes128::sub_bytes(&mut state);
579        Aes128::shift_rows(&mut state);
580        Aes128::add_round_key(&mut state, &round_key_bytes[192..208])?;
581
582        // Copy state back to block
583        block.copy_from_slice(&state[..]);
584        Ok(())
585    }
586
587    fn decrypt_block(&self, block: &mut [u8]) -> Result<()> {
588        // Use validation utility for length check
589        validate::length("AES block", block.len(), AES_BLOCK_SIZE)?;
590
591        // Access round keys through SecretBuffer
592        let round_key_bytes = self.round_keys.as_ref();
593
594        // Warm the cache by touching all round key bytes
595        let mut _warm: u8 = 0;
596        for &b in round_key_bytes {
597            _warm = _warm.wrapping_add(b);
598        }
599        compiler_fence(Ordering::SeqCst);
600
601        // Copy block to state array
602        let mut state = Zeroizing::new([0u8; 16]);
603        state.copy_from_slice(block);
604
605        // Initial round - AddRoundKey (final round key)
606        Aes128::add_round_key(&mut state, &round_key_bytes[192..208])?;
607
608        // Main rounds in reverse
609        for round in (1..12).rev() {
610            Aes128::inv_shift_rows(&mut state);
611            Aes128::inv_sub_bytes(&mut state);
612
613            let offset = round * 16;
614            Aes128::add_round_key(&mut state, &round_key_bytes[offset..offset + 16])?;
615            Aes128::inv_mix_columns(&mut state);
616        }
617
618        // Final round
619        Aes128::inv_shift_rows(&mut state);
620        Aes128::inv_sub_bytes(&mut state);
621        Aes128::add_round_key(&mut state, &round_key_bytes[0..16])?;
622
623        // Copy state back to block
624        block.copy_from_slice(&state[..]);
625        Ok(())
626    }
627
628    fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key> {
629        let mut key_data = Zeroizing::new([0u8; AES192_KEY_SIZE]);
630        try_fill_bytes_zeroing_on_error(rng, &mut key_data[..])?;
631        Ok(SecretBytes::new(*key_data))
632    }
633}
634
635// AES-256 implementation
636
637impl Aes256 {
638    /// Performs AES-256 key expansion
639    fn expand_key(key: &[u8]) -> Result<SecretBuffer<240>> {
640        validate::length("AES-256 key", key.len(), AES256_KEY_SIZE)?;
641
642        let mut round_keys_u32 = Zeroizing::new([0u32; 60]);
643
644        // Initial key schedule
645        for i in 0..8 {
646            round_keys_u32[i] = bytes_to_u32(&key[i * 4..(i + 1) * 4]);
647        }
648
649        // Key expansion
650        for i in 8..60 {
651            let mut temp = Zeroizing::new(round_keys_u32[i - 1]);
652            if i % 8 == 0 {
653                *temp = sub_word(rotate_word(*temp)) ^ RCON[i / 8];
654            } else if i % 8 == 4 {
655                *temp = sub_word(*temp);
656            }
657            round_keys_u32[i] = round_keys_u32[i - 8] ^ *temp;
658        }
659
660        // Convert to bytes
661        let mut round_key_bytes = Zeroizing::new([0u8; 240]);
662        for i in 0..60 {
663            let bytes = Zeroizing::new(u32_to_bytes(round_keys_u32[i]));
664            round_key_bytes[i * 4..(i + 1) * 4].copy_from_slice(&bytes[..]);
665        }
666
667        Ok(SecretBuffer::new(*round_key_bytes))
668    }
669}
670
671impl BlockCipher for Aes256 {
672    type Algorithm = Aes256Algorithm;
673    type Key = SecretBytes<32>;
674
675    fn new(key: &Self::Key) -> Self {
676        let round_keys =
677            Self::expand_key(key.as_ref()).expect("AES-256 key expansion should not fail");
678
679        Aes256 { round_keys }
680    }
681
682    fn encrypt_block(&self, block: &mut [u8]) -> Result<()> {
683        // Use validation utility for length check
684        validate::length("AES block", block.len(), AES_BLOCK_SIZE)?;
685
686        // Access round keys through SecretBuffer
687        let round_key_bytes = self.round_keys.as_ref();
688
689        // Warm the cache by touching all round key bytes
690        let mut _warm: u8 = 0;
691        for &b in round_key_bytes {
692            _warm = _warm.wrapping_add(b);
693        }
694        compiler_fence(Ordering::SeqCst);
695
696        // Copy block to state array
697        let mut state = Zeroizing::new([0u8; 16]);
698        state.copy_from_slice(block);
699
700        // Initial round - AddRoundKey
701        Aes128::add_round_key(&mut state, &round_key_bytes[0..16])?;
702
703        // Main rounds
704        for round in 1..14 {
705            Aes128::sub_bytes(&mut state);
706            Aes128::shift_rows(&mut state);
707            Aes128::mix_columns(&mut state);
708
709            let offset = round * 16;
710            Aes128::add_round_key(&mut state, &round_key_bytes[offset..offset + 16])?;
711        }
712
713        // Final round
714        Aes128::sub_bytes(&mut state);
715        Aes128::shift_rows(&mut state);
716        Aes128::add_round_key(&mut state, &round_key_bytes[224..240])?;
717
718        // Copy state back to block
719        block.copy_from_slice(&state[..]);
720        Ok(())
721    }
722
723    fn decrypt_block(&self, block: &mut [u8]) -> Result<()> {
724        // Use validation utility for length check
725        validate::length("AES block", block.len(), AES_BLOCK_SIZE)?;
726
727        // Access round keys through SecretBuffer
728        let round_key_bytes = self.round_keys.as_ref();
729
730        // Warm the cache by touching all round key bytes
731        let mut _warm: u8 = 0;
732        for &b in round_key_bytes {
733            _warm = _warm.wrapping_add(b);
734        }
735        compiler_fence(Ordering::SeqCst);
736
737        // Copy block to state array
738        let mut state = Zeroizing::new([0u8; 16]);
739        state.copy_from_slice(block);
740
741        // Initial round - AddRoundKey (final round key)
742        Aes128::add_round_key(&mut state, &round_key_bytes[224..240])?;
743
744        // Main rounds in reverse
745        for round in (1..14).rev() {
746            Aes128::inv_shift_rows(&mut state);
747            Aes128::inv_sub_bytes(&mut state);
748
749            let offset = round * 16;
750            Aes128::add_round_key(&mut state, &round_key_bytes[offset..offset + 16])?;
751            Aes128::inv_mix_columns(&mut state);
752        }
753
754        // Final round
755        Aes128::inv_shift_rows(&mut state);
756        Aes128::inv_sub_bytes(&mut state);
757        Aes128::add_round_key(&mut state, &round_key_bytes[0..16])?;
758
759        // Copy state back to block
760        block.copy_from_slice(&state[..]);
761        Ok(())
762    }
763
764    fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key> {
765        let mut key_data = Zeroizing::new([0u8; AES256_KEY_SIZE]);
766        try_fill_bytes_zeroing_on_error(rng, &mut key_data[..])?;
767        Ok(SecretBytes::new(*key_data))
768    }
769}
770
771#[cfg(test)]
772mod tests;