aes_ndlr/
lib.rs

1/// Resources used:
2/// - FIPS 197, Advanced Encryption Standard (AES):
3///     https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf
4///     Comments in the code reference this paper's sections.
5/// - Rijndael MixColumns - Implementation example:
6///     https://en.wikipedia.org/wiki/Rijndael_MixColumns#Implementation_example
7/// - Block cipher mode of operation:
8///     https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
9use constants::*;
10use key::Key;
11use pad::{Padding, pkcs7_pad};
12use Padding::PKCS7;
13use state::State;
14
15pub mod pad;
16pub mod key;
17mod state;
18mod xor;
19mod math;
20mod word;
21mod constants;
22mod ctr;
23
24#[derive(PartialEq, Debug)]
25pub struct AESEncryptionOptions<'a> {
26    pub block_cipher_mode: &'a BlockCipherMode<'a>,
27    pub padding: &'a Padding,
28}
29
30impl<'a> AESEncryptionOptions<'a> {
31    pub fn new(block_cipher_mode: &'a BlockCipherMode, padding: &'a Padding) -> Self {
32        AESEncryptionOptions {
33            block_cipher_mode,
34            padding,
35        }
36    }
37}
38
39impl Default for AESEncryptionOptions<'_> {
40    fn default() -> Self {
41        AESEncryptionOptions::new(&BlockCipherMode::ECB, &Padding::None)
42    }
43}
44
45/// a 4 x Nb matrix
46#[derive(PartialEq, Debug)]
47pub struct Block(pub [[u8; 4]; Nb]);
48
49impl Block {
50    pub fn empty() -> Self {
51        Block([[0; 4]; Nb])
52    }
53}
54
55#[derive(PartialEq, Debug)]
56pub enum BlockCipherMode<'a> {
57    ECB,
58    CBC(&'a Iv),
59    CTR(&'a Nonce),
60}
61
62pub type Iv = Block;
63pub type Nonce = [u8; 8];
64
65/// Encrypts in aes-128.
66///
67/// At the start of the Cipher, the input is copied to the State array using the conventions
68/// described in Sec. 3.4. After an initial Round Key addition, the State array is transformed by
69/// implementing a round function Nr times, with the final round differing slightly from the first
70/// Nr -1 rounds. The final State is then copied to the output as described in Sec. 3.4.
71pub fn encrypt_aes_128(raw_bytes: &[u8], key: &Key, options: &AESEncryptionOptions) -> Vec<u8> {
72    let block_size = 16;
73
74    let w = &key.do_key_expansion().0;
75    let bytes = &if options.padding == &PKCS7 {
76        pkcs7_pad(raw_bytes, block_size)
77    } else {
78        if let BlockCipherMode::CTR(nonce) = &options.block_cipher_mode {
79            ctr::generate_ctr_byte_stream_for_length(raw_bytes.len(), &nonce)
80        } else {
81            raw_bytes.to_vec()
82        }
83    };
84    let parts = bytes_to_parts(bytes);
85
86    let mut cipher: Vec<u8> = Vec::with_capacity(raw_bytes.len());
87    let mut previous_state: State = State::empty();
88
89    for (i, part) in parts.iter().enumerate() {
90        let mut state = State::from_part(part);
91        if let BlockCipherMode::CBC(iv) = &options.block_cipher_mode {
92            if i == 0 {
93                state.xor_with_iv(&iv);
94            } else {
95                state.xor_with_state(&previous_state);
96            };
97        }
98
99        state.add_round_key(&w[0..Nb]);
100
101        for round in 1..Nr {
102            state.sub_bytes();
103            state.shift_rows();
104            state.mix_columns();
105            state.add_round_key(&w[round * Nb..(round + 1) * Nb]);
106        }
107
108        state.sub_bytes();
109        state.shift_rows();
110        state.add_round_key(&w[Nr * Nb..(Nr + 1) * Nb]);
111
112        if let BlockCipherMode::CBC(_iv) = &options.block_cipher_mode {
113            previous_state = state.clone();
114        }
115
116        cipher.append(state.to_block().as_mut());
117    }
118
119    if let BlockCipherMode::CTR(_nonce) = &options.block_cipher_mode {
120        xor::fixed_key_xor(&raw_bytes, &cipher)
121    } else {
122        cipher
123    }
124}
125
126/// Decrypts aes-128 ciphers.
127pub fn decrypt_aes_128(cipher: &[u8], key: &Key, mode: &BlockCipherMode) -> Vec<u8> {
128    if let BlockCipherMode::CTR(_nonce) = mode {
129        panic!("Cannot decrypt using CTR block cipher mode. Use encryption instead.");
130    }
131
132    let w = &key.do_key_expansion().0;
133    let parts = bytes_to_parts(cipher);
134    let mut deciphered: Vec<u8> = Vec::with_capacity(cipher.len());
135    let mut previous_state = State::empty();
136
137    for (i, part) in parts.iter().enumerate() {
138        let mut state = State::from_part(part);
139
140        state.add_round_key(&w[Nr * Nb..(Nr + 1) * Nb]);
141
142        for round in (1..Nr).rev() {
143            state.inv_shift_rows();
144            state.inv_sub_bytes();
145            state.add_round_key(&w[round * Nb..(round + 1) * Nb]);
146            state.inv_mix_columns();
147        }
148
149        state.inv_shift_rows();
150        state.inv_sub_bytes();
151        state.add_round_key(&w[0..Nb]);
152
153        if let BlockCipherMode::CBC(iv) = mode {
154            if i == 0 {
155                state.xor_with_iv(iv);
156            } else {
157                state.xor_with_state(&previous_state);
158            };
159            previous_state = State::from_part(part);
160        }
161
162        deciphered.append(state.to_block().as_mut());
163    }
164
165    deciphered
166}
167
168/// chunks a slice of bytes to chunks of block_size length
169pub fn bytes_to_parts(bytes: &[u8]) -> Vec<&[u8]> {
170    let block_size = 16usize;
171
172    bytes.chunks_exact(block_size).collect()
173}
174
175/// Some encryption/decryption test cases are taken from:
176/// https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
177#[cfg(test)]
178mod tests {
179    use pad::Padding;
180
181    use super::*;
182
183    const ECB_KEY: Key = Key([
184        0x00, 0x01, 0x02, 0x03,
185        0x04, 0x05, 0x06, 0x07,
186        0x08, 0x09, 0x0a, 0x0b,
187        0x0c, 0x0d, 0x0e, 0x0f
188    ]);
189    const RAW_ECB: [u8; 16] = [
190        0x0, 0x11, 0x22, 0x33,
191        0x44, 0x55, 0x66, 0x77,
192        0x88, 0x99, 0xaa, 0xbb,
193        0xcc, 0xdd, 0xee, 0xff
194    ];
195    const CIPHERED_ECB: [u8; 16] = [
196        0x69, 0xc4, 0xe0, 0xd8,
197        0x6a, 0x7b, 0x04, 0x30,
198        0xd8, 0xcd, 0xb7, 0x80,
199        0x70, 0xb4, 0xc5, 0x5a
200    ];
201
202    const CBC_KEY: Key = Key([
203        0x2b, 0x7e, 0x15, 0x16,
204        0x28, 0xae, 0xd2, 0xa6,
205        0xab, 0xf7, 0x15, 0x88,
206        0x09, 0xcf, 0x4f, 0x3c
207    ]);
208    const CBC_IV: Iv = Block([
209        [0x00, 0x01, 0x02, 0x03],
210        [0x04, 0x05, 0x06, 0x07],
211        [0x08, 0x09, 0x0a, 0x0b],
212        [0x0c, 0x0d, 0x0e, 0x0f]
213    ]);
214    const CIPHERED_CBC: [u8; 16] = [
215        0x76, 0x49, 0xab, 0xac,
216        0x81, 0x19, 0xb2, 0x46,
217        0xce, 0xe9, 0x8e, 0x9b,
218        0x12, 0xe9, 0x19, 0x7d
219    ];
220    const RAW_CBC: [u8; 16] = [
221        0x6b, 0xc1, 0xbe, 0xe2,
222        0x2e, 0x40, 0x9f, 0x96,
223        0xe9, 0x3d, 0x7e, 0x11,
224        0x73, 0x93, 0x17, 0x2a
225    ];
226
227    const CTR_KEY: Key = Key([
228        0x2b, 0x7e, 0x15, 0x16,
229        0x28, 0xae, 0xd2, 0xa6,
230        0xab, 0xf7, 0x15, 0x88,
231        0x09, 0xcf, 0x4f, 0x3c
232    ]);
233    const CTR_NONCE: Nonce = [0xff; 8];
234    const RAW_CTR: [u8; 16] = [
235        0x30, 0xc8, 0x1c, 0x46,
236        0xa3, 0x5c, 0xe4, 0x11,
237        0xe5, 0xfb, 0xc1, 0x19,
238        0x1a, 0x0a, 0x52, 0xef
239    ];
240    const CIPHERED_CTR: [u8; 16] = [
241        0x27, 0x5c, 0x37, 0xf4,
242        0xd3, 0x53, 0xf9, 0x93,
243        0x2f, 0x6c, 0xd4, 0x60,
244        0xa1, 0xc2, 0xb2, 0x25
245    ];
246
247    #[test]
248    fn default_encryption_options_are_ecb_with_no_padding() {
249        let encryption_options = AESEncryptionOptions::default();
250
251        assert_eq!(encryption_options.block_cipher_mode, &BlockCipherMode::ECB);
252        assert_eq!(encryption_options.padding, &Padding::None);
253    }
254
255    #[test]
256    fn empty_produces_empty_block() {
257        let block = Block::empty();
258        let expected_block = [
259            [0, 0, 0, 0],
260            [0, 0, 0, 0],
261            [0, 0, 0, 0],
262            [0, 0, 0, 0],
263        ];
264
265        assert_eq!(block.0, expected_block);
266    }
267
268    #[test]
269    fn encrypts_in_ecb_mode() {
270        let actual_cipher = encrypt_aes_128(
271            &RAW_ECB,
272            &ECB_KEY,
273            &AESEncryptionOptions::new(
274                &BlockCipherMode::ECB,
275                &Padding::None,
276            ),
277        );
278
279        assert_eq!(actual_cipher, CIPHERED_ECB);
280    }
281
282    #[test]
283    fn decrypts_in_ecb_mode() {
284        let actual_raw = decrypt_aes_128(
285            &CIPHERED_ECB,
286            &ECB_KEY,
287            &BlockCipherMode::ECB,
288        );
289
290        assert_eq!(actual_raw, RAW_ECB);
291    }
292
293    #[test]
294    fn encrypts_in_cbc_mode() {
295        let actual_cipher = encrypt_aes_128(
296            &RAW_CBC,
297            &CBC_KEY,
298            &AESEncryptionOptions::new(
299                &BlockCipherMode::CBC(&CBC_IV),
300                &Padding::None,
301            ),
302        );
303
304        assert_eq!(actual_cipher, CIPHERED_CBC);
305    }
306
307    #[test]
308    fn decrypts_in_cbc_mode() {
309        let actual_raw = decrypt_aes_128(
310            &CIPHERED_CBC,
311            &CBC_KEY,
312            &BlockCipherMode::CBC(&CBC_IV),
313        );
314
315        assert_eq!(actual_raw, RAW_CBC);
316    }
317
318    #[test]
319    fn encrypts_in_ctr_mode() {
320        let actual_cipher = encrypt_aes_128(
321            &RAW_CTR,
322            &CTR_KEY,
323            &AESEncryptionOptions::new(
324                &BlockCipherMode::CTR(&CTR_NONCE),
325                &Padding::None,
326            ),
327        );
328
329        assert_eq!(actual_cipher, CIPHERED_CTR);
330    }
331
332    #[test]
333    fn decrypts_in_ctr_mode() {
334        // CTR decryption uses the dencryption process
335        let actual_raw = encrypt_aes_128(
336            &CIPHERED_CTR,
337            &CTR_KEY,
338            &AESEncryptionOptions::new(
339                &BlockCipherMode::CTR(&CTR_NONCE),
340                &Padding::None,
341            ),
342        );
343
344        assert_eq!(actual_raw, RAW_CTR);
345    }
346
347    #[test]
348    #[should_panic(expected = "Cannot decrypt using CTR block cipher mode. Use encryption instead.")]
349    fn decryption_in_ctr_mode_should_panic() {
350        decrypt_aes_128(
351            &CIPHERED_CTR,
352            &CTR_KEY,
353            &BlockCipherMode::CTR(&CTR_NONCE),
354        );
355    }
356
357    #[test]
358    fn bytes_to_parts_converts_bytes_to_parts_of_block_size_length() {
359        let bytes: [u8; 32] = [
360            0x00, 0x01, 0x02, 0x03,
361            0x04, 0x05, 0x06, 0x07,
362            0x08, 0x09, 0x10, 0x11,
363            0x12, 0x13, 0x14, 0x15,
364            0x16, 0x17, 0x18, 0x19,
365            0x20, 0x21, 0x22, 0x23,
366            0x24, 0x25, 0x26, 0x27,
367            0x28, 0x29, 0x30, 0x31
368        ];
369        let expected_parts = vec![
370            &bytes[..16],
371            &bytes[16..]
372        ];
373
374        assert_eq!(bytes_to_parts(&bytes.to_vec()), expected_parts);
375    }
376}