I worked on slices of bytes instead of array of words. This made certain operations different. I wrote the algorithm in Go. Sources used are “A Graduate Course in Applied Cryptography” by Dan Boneh and Victor Shoup, and the official NIST publication from 2001.
The preparation works as follows:
- Expand input key with Key Expansion algorithm
- Split input into array of states, each a 16 byte array
Then, with this, do the following for each state
- Transpose the state
- Add Round Key
- For Rounds-1 time, do the following
- Sub Bytes according to the Rijndael S-Box
- Shift Rows
- Mix Columns
- Add Round Key
- Sub Bytes
- Shift Rows
- Add Round Key
- Transpose the state
This is a basic
for i := 0...16:
state[i] ^= key[i]
This substitutes each byte in accordance with the Rijndael S-Box.
for i := 0...16:
state[i] = sbox[state[i]]
This shifts row
for i := 0...4:
rotate_word(state[i:i+4], -i)
Where rotate simply rotates the slice i
steps to the left because of the negative value. See repo for more information.
This implements and uses the mix-columns array of Rijndael. For each column, do the following
a := m1[state[i]] ^ m2[state[4+i]] ^ m3[state[8+i]] ^ m4[state[12+i]]
b := m4[state[i]] ^ m1[state[4+i]] ^ m2[state[8+i]] ^ m3[state[12+i]]
c := m3[state[i]] ^ m4[state[4+i]] ^ m1[state[8+i]] ^ m2[state[12+i]]
d := m2[state[i]] ^ m3[state[4+i]] ^ m4[state[8+i]] ^ m1[state[12+i]]
state[i] = a
state[4+i] = b
state[8+i] = c
state[12+i] = d
The following is a summary of the algorithm:
- Create space for 11 (number of rounds is 10+1) sets of 16 byte keys (where each 16 byte key is a set of 4 words).
- Copy the input key into the first 16 bytes of the space
- For each new key-set, do the following
- Calculate G-Function of the most previous word
- XOR the previous key-sets first word with the word from a) and store in the current key-sets first word
- For each coming word in the current key, set it equal to the previous key-sets’ word (with the same index) XOR:ed with the most previous word in the key
- For each key-set, Transpose the set as seen as a matrix
Below glookup
is the RCON array found here
out := make([]byte, 4)
for i := 0...3:
out[i] = word[i]
rotate_word(out, -1)
sub_bytes(out, false)
out[0] ^= glookup[i-1]
return out
``