-
Notifications
You must be signed in to change notification settings - Fork 2
Key Schedule
When performing AES encryption or decryption, a distinct key is used for each individual round and "one more" key is used when performing the initial AddRoundKey operation (before the first official round). In AES-128, we are performing 10 rounds of encryption/decryption so we need at 10 distinct keys (one for each round) and "one more"; again, the "one more" is for the initial step of AddRoundKey; so we need a total of 11x 128-bit keys. Keep in mind that when performing encryption or decryption, data (either plain text or cipher text) is typically only presented with a single 128-bit secret key; the AES key schedule takes the supplied secret key and "expands" it to "generate" the required number of distinct keys (which are used as previously explained). It is always assumed that the provided secret key is the "first" key or the "key to be expanded upon".
Going back to our 4x4 byte "grid", consider each column in the grid to be a 32-bit word (4x bytes = 32 bits). Since we need 11x keys we will have 44x 32-bit words (1x 128-bit "grid" represented as 4x 32-bit words means 44x 32-bit words in total). Rather than start from 1 and count to 44, we'll start at 0 and count up to 43.
So, the first 4x words (words 0 through 3) are simply the supplied secret key. Yes, the first distinct key is actually just a copy of the supplied secret key (as previously explained, we are "expanding upon" the supplied secret key).
For words 4 through 43, we take the previous word and apply an XOR
operation on the word which is 4x columns behind (w[i] = w[i-1] XOR w[i-4]
). However, every fourth word (i mod 4 = 0
) we perform some additional steps:
- Rotate the word 1x byte to the left.
- Substitute the bytes in the word using the S-Box (yes, the same S-Box from the SubBytes operation).
- Apply an
XOR
operation on the resulting word with a distinct round constant.
The full pseudocode algorithm for words 4 through 43 can be represented as such:
for i = 4 to 43:
temp = w[i-1]
if i mod 4 = 0:
temp = SubWord(RotWord(temp))
temp = temp XOR RoundConstant(i/4)
end if
w[i] = temp XOR w[i-4]
end for
As previously mentioned, there is a distinct round constant that is used where the constants are represented in hexadecimal:
Round | Constant |
---|---|
1 | 01 |
2 | 02 |
3 | 04 |
4 | 08 |
5 | 10 |
6 | 20 |
7 | 40 |
8 | 80 |
9 | 1b |
10 | 36 |
Once we have all 44x 32-bit words we also have our distinct 128-bit keys! Words 0 through 3 are the supplied key (as previously explained) so that key would be used on the initial AddRoundKey operation which occurs before the first official round. Every 4x words thereafter represent a distinct 128-bit key to be used with each round (words 4 through 7 are the key for round 1, words 8 through 11 are the key for round 2, etc.). When performing decryption, the same exact keys are "generated" in the exact same manner; just be sure to use them in the correct order (decryption starts from round 10 and goes down so use words 40 through 43 for round 10, words 36 through 39 for round 9, etc.).