plain_aes/internal/
key_expansion.rs

1use std::fmt;
2
3use crate::CipherVersion;
4
5use super::RIJNDAEL_S_BOX;
6/// The round constant lookup table.
7const RCON: [u8; 256] = [
8    0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
9    0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
10    0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
11    0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
12    0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
13    0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
14    0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
15    0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
16    0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
17    0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
18    0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
19    0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
20    0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
21    0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
22    0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
23    0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,
24];
25#[derive(Debug)]
26/// A set of generated keys to account for each round of the said cipher version encryption/decryption process.
27pub struct ExpandedKey {
28    content: Vec<u8>,
29    original_key: Vec<u8>,
30    round_num: usize,
31}
32#[derive(Debug, PartialEq)]
33/// An error produced during a key expansion.
34pub enum KeyExpansionError {
35    /// The given key's length does not match the cipher version provided.
36    InvalidKeyLength { expected: usize, actual: usize },
37}
38
39impl fmt::Display for KeyExpansionError {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        write!(f, "{:?}", self)
42    }
43}
44
45impl std::error::Error for KeyExpansionError {}
46impl ExpandedKey {
47    /// Expands the given key based on the specified cipher version.
48    pub fn new(cipher_version: &CipherVersion) -> Result<ExpandedKey, KeyExpansionError> {
49        let key = cipher_version.key();
50        match cipher_version {
51            &CipherVersion::Aes128(_, _) => {
52                if key.len() != 16 {
53                    return Err(KeyExpansionError::InvalidKeyLength {
54                        expected: 16,
55                        actual: key.len(),
56                    });
57                }
58            }
59            &CipherVersion::Aes192(_, _) => {
60                if key.len() != 24 {
61                    return Err(KeyExpansionError::InvalidKeyLength {
62                        expected: 24,
63                        actual: key.len(),
64                    });
65                }
66            }
67        };
68        let mut expanded_key = Vec::new();
69        expanded_key.extend(&key);
70        let mut rcon_iteration = 1;
71        let mut bytes_generated = key.len(); // We've already included the original key.
72        let mut temp: [u8; 4] = [0; 4];
73        while bytes_generated < cipher_version.expanded_key_size() {
74            for i in 0..4 {
75                // Load the last 4 keys of the expanded key into the temp variable.
76                temp[i] = expanded_key[i + bytes_generated - 4];
77            }
78            if bytes_generated % key.len() == 0 {
79                // Call the core everytime we've generated a new key.
80                ExpandedKey::key_schedule_core(&mut temp, rcon_iteration);
81                rcon_iteration = rcon_iteration + 1;
82            }
83            for i in 0..4 {
84                expanded_key.push(expanded_key[bytes_generated - key.len()] ^ temp[i]);
85                bytes_generated = bytes_generated + 1;
86            }
87        }
88        Ok(ExpandedKey {
89            original_key: key,
90            content: expanded_key,
91            round_num: match cipher_version {
92                CipherVersion::Aes128(_, _) => 10,
93                CipherVersion::Aes192(_, _) => 12,
94            },
95        })
96    }
97    pub fn original_key(&self) -> &Vec<u8> {
98        &self.original_key
99    }
100    pub fn content(&self) -> &Vec<u8> {
101        &self.content
102    }
103    /// The number of rounds used in the chosen cipher version.
104    pub fn round_num(&self) -> usize {
105        self.round_num
106    }
107    /// Substitute a word from the key with it's equivalant from Rijndael's S-box.
108    ///
109    /// A word is a 4 byte sequence.
110    fn sub_word(word: &mut [u8; 4]) {
111        for i in 0..4 {
112            word[i] = RIJNDAEL_S_BOX[word[i] as usize];
113        }
114    }
115    /// Rotate a word of the key by one position to the left.
116    fn rot_word(word: &mut [u8; 4]) {
117        let tmp = word[0];
118        for i in 0..3 {
119            word[i] = word[i + 1];
120        }
121        word[3] = tmp;
122    }
123
124    /// AES key schedule core function, applies [ExpandedKey::sub_word], [ExpandedKey::sub_word] and [RCON].
125    fn key_schedule_core(word: &mut [u8; 4], rcon_iteration: usize) {
126        ExpandedKey::rot_word(word);
127        ExpandedKey::sub_word(word);
128        word[0] = word[0] ^ RCON[rcon_iteration];
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use crate::ModeOfOperation;
135
136    use super::*;
137    #[test]
138    /// Mock word taken from the AES standard, Appendix A.1, temp=09cf4f3c.
139    fn rot_word_test() {
140        let mut mock_word = [0x09, 0xcf, 0x4f, 0x3c];
141        let rot_word_expected = [0xcf, 0x4f, 0x3c, 0x09];
142        ExpandedKey::rot_word(&mut mock_word);
143        assert!(rot_word_expected.iter().eq(&mock_word));
144    }
145
146    #[test]
147    /// Mock word taken from the AES standard, Appendix A.1, RotWord(temp)=cf4f3c09.
148    fn sub_word_test() {
149        let mut mock_word = [0xcf, 0x4f, 0x3c, 0x09];
150        let sub_word_expected = [0x8a, 0x84, 0xeb, 0x01];
151        ExpandedKey::sub_word(&mut mock_word);
152        assert!(sub_word_expected.iter().eq(&mock_word));
153    }
154
155    #[test]
156    /// Mock word taken from the AES standard, Appendix A.1, temp=2a6c7605, Rcon[i/Nk]=2.
157    fn key_schedule_core_test() {
158        let mut mock_word = [0x2a, 0x6c, 0x76, 0x05];
159        let key_schedule_core_expected = [0x52, 0x38, 0x6b, 0xe5];
160        ExpandedKey::key_schedule_core(&mut mock_word, 2);
161        assert!(key_schedule_core_expected.iter().eq(&mock_word));
162    }
163
164    #[test]
165    fn expand_key_aes128_test() {
166        let mock_key = [
167            0x54, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x62, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F,
168            0x6F, 0x6C,
169        ]; // This lib is cool
170        let expand_key_expected = [
171            0x54, 0x68, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x62, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f,
172            0x6f, 0x6c, 0xfd, 0xc0, 0x39, 0x88, 0xdd, 0xac, 0x50, 0xea, 0xfd, 0xc5, 0x23, 0xca,
173            0x9e, 0xaa, 0x4c, 0xa6, 0x53, 0xe9, 0x1d, 0x83, 0x8e, 0x45, 0x4d, 0x69, 0x73, 0x80,
174            0x6e, 0xa3, 0xed, 0x2a, 0x22, 0x05, 0xb2, 0x7a, 0x76, 0xd6, 0x3c, 0x3f, 0x3b, 0xbf,
175            0x4f, 0xbf, 0x55, 0x1c, 0xa2, 0x95, 0x77, 0x19, 0x90, 0x8f, 0xa2, 0xec, 0xac, 0xb0,
176            0x99, 0x53, 0xe3, 0x0f, 0xcc, 0x4f, 0x41, 0x9a, 0xbb, 0x56, 0x38, 0x65, 0x13, 0x6f,
177            0x94, 0xd5, 0x8a, 0x3c, 0x77, 0xda, 0x46, 0x73, 0x36, 0x40, 0xfd, 0x25, 0x11, 0x31,
178            0x2c, 0x6a, 0x85, 0xe4, 0xa6, 0x56, 0xf2, 0x3e, 0xe0, 0x25, 0xc4, 0x7e, 0x1d, 0x00,
179            0xa2, 0x95, 0x4f, 0x76, 0x27, 0x71, 0xe9, 0x20, 0xd5, 0x4f, 0x09, 0x05, 0x11, 0x31,
180            0x14, 0x05, 0xe5, 0x6f, 0x24, 0xf4, 0xc2, 0x1e, 0xcd, 0xd4, 0x17, 0x51, 0xc4, 0xd1,
181            0x06, 0x60, 0xd0, 0xd4, 0x2e, 0x1f, 0x6c, 0x9b, 0xec, 0x01, 0xa1, 0x4f, 0xfb, 0x50,
182            0x65, 0x9e, 0xfd, 0x30, 0xb5, 0x4a, 0x1c, 0xca, 0xba, 0xcf, 0xf0, 0xcb, 0x1b, 0x80,
183            0x0b, 0x9b, 0x7e, 0x1e, 0xf6, 0xab, 0xcb, 0x54,
184        ];
185        let cipher_version = CipherVersion::Aes128(&mock_key[..], ModeOfOperation::ECB);
186        let expand_key_result = ExpandedKey::new(&cipher_version).unwrap();
187        assert!(expand_key_expected.iter().eq(expand_key_result.content()));
188    }
189    #[test]
190    fn expand_key_aes128_invalid_key_length() {
191        let mock_key = [
192            0x54, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x62, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F,
193        ]; // Key's length is invalid for AES-128.
194        let cipher_version = CipherVersion::Aes128(&mock_key[..], ModeOfOperation::ECB);
195        let expand_key_result = ExpandedKey::new(&cipher_version).unwrap_err();
196        println!("{}", expand_key_result);
197        assert_eq!(
198            expand_key_result,
199            KeyExpansionError::InvalidKeyLength {
200                expected: 16,
201                actual: 14
202            }
203        )
204    }
205    #[test]
206    /// Based on the FIPS test vector.
207    fn expand_key_aes192_test() {
208        let mock_key = [
209            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
210            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
211        ];
212        let expand_key_expected = [
213            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
214            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x58, 0x46, 0xf2, 0xf9,
215            0x5c, 0x43, 0xf4, 0xfe, 0x54, 0x4a, 0xfe, 0xf5, 0x58, 0x47, 0xf0, 0xfa, 0x48, 0x56,
216            0xe2, 0xe9, 0x5c, 0x43, 0xf4, 0xfe, 0x40, 0xf9, 0x49, 0xb3, 0x1c, 0xba, 0xbd, 0x4d,
217            0x48, 0xf0, 0x43, 0xb8, 0x10, 0xb7, 0xb3, 0x42, 0x58, 0xe1, 0x51, 0xab, 0x04, 0xa2,
218            0xa5, 0x55, 0x7e, 0xff, 0xb5, 0x41, 0x62, 0x45, 0x08, 0x0c, 0x2a, 0xb5, 0x4b, 0xb4,
219            0x3a, 0x02, 0xf8, 0xf6, 0x62, 0xe3, 0xa9, 0x5d, 0x66, 0x41, 0x0c, 0x08, 0xf5, 0x01,
220            0x85, 0x72, 0x97, 0x44, 0x8d, 0x7e, 0xbd, 0xf1, 0xc6, 0xca, 0x87, 0xf3, 0x3e, 0x3c,
221            0xe5, 0x10, 0x97, 0x61, 0x83, 0x51, 0x9b, 0x69, 0x34, 0x15, 0x7c, 0x9e, 0xa3, 0x51,
222            0xf1, 0xe0, 0x1e, 0xa0, 0x37, 0x2a, 0x99, 0x53, 0x09, 0x16, 0x7c, 0x43, 0x9e, 0x77,
223            0xff, 0x12, 0x05, 0x1e, 0xdd, 0x7e, 0x0e, 0x88, 0x7e, 0x2f, 0xff, 0x68, 0x60, 0x8f,
224            0xc8, 0x42, 0xf9, 0xdc, 0xc1, 0x54, 0x85, 0x9f, 0x5f, 0x23, 0x7a, 0x8d, 0x5a, 0x3d,
225            0xc0, 0xc0, 0x29, 0x52, 0xbe, 0xef, 0xd6, 0x3a, 0xde, 0x60, 0x1e, 0x78, 0x27, 0xbc,
226            0xdf, 0x2c, 0xa2, 0x23, 0x80, 0x0f, 0xd8, 0xae, 0xda, 0x32, 0xa4, 0x97, 0x0a, 0x33,
227            0x1a, 0x78, 0xdc, 0x09, 0xc4, 0x18, 0xc2, 0x71, 0xe3, 0xa4, 0x1d, 0x5d,
228        ];
229        let cipher_version = CipherVersion::Aes192(&mock_key[..], ModeOfOperation::ECB);
230        let expand_key_result = ExpandedKey::new(&cipher_version).unwrap();
231        assert!(expand_key_expected.iter().eq(expand_key_result.content()))
232    }
233}