secworks/aes

Use aes_encipher_block component for one AES round

Closed this issue · 6 comments

Hi,
is it possible to use aes_encipher_block for exactly one AES round like the AES-NI instruction __m128i _mm_aesenc_si128(__m128i a, __m128i RoundKey)? [Link]
If I have to update a few lines in the component this would be totally fine.

From the documentation of the AES-NI instruction _mm_aesenc_si128:

state := a
a[127:0] := ShiftRows(a[127:0])
a[127:0] := SubBytes(a[127:0])
a[127:0] := MixColumns(a[127:0])
dst[127:0] := a[127:0] XOR RoundKey[127:0]

The encipher component does exactly that, but also does the initial round key addition and the final round (without mixing). Is there a way to avoid the initial key addition? I tried to modify the code in this line so the round key does not get xor'd to the block, but it didn't get me the expected result. Is there something else I could do/might try?

Here is an example of a software AES-NI that I use to generate my expected values. [Link]. You can also see the expected values it produces as a comment in the gist.

After the first round (without key addition) with the following parameters:
block = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f and
round_key = 06 84 70 4c e6 20 c0 0a b2 c5 fe f0 75 81 7b 9d
keylen = 0
I expect new_block to be: f7 11 dd 30 dc 93 f6 e3 ba 19 7d 87 6b ec a5 5a

The goal of all this is to use the aes_encipher_block component for a hardware implementation of Haraka.

Aloha!
A very interesting question!
You could always extract the functions for shiftrows() and mixcolumns() and use them in a design. In the current design subbytes() is implemented over four cycles (there are four S-boxes which are reused four times in a round). This means that subbytes() is not implemented as a function, but instead as a mux with four stges, see:

https://github.com/secworks/aes/blob/master/src/rtl/aes_encipher_block.v#L291

The initial addroundkey() kan be solved by having an all zero round key. But I think you need to modify the aes_encipher_block quite a bit to be able to match the exact behaviour of AES-NI.

There is a new version of the stream cipher Snow called Snow5. Snow5 actually reuse the AES round, but crucially does not have a round key. It seems similar to Haraka, if I understand the paper from a fast peek. I have started implementing Snow5. In that implementation I basically took the encipher_block and extracted the round function into a simpler module. You might want to look at reusing that instead. BIG WARNING The code in my snow5 repo is untested, not complete. It may require debugging to work. BIG WARNING with that disclaimer, here is the link:

https://github.com/secworks/snow5/blob/master/src/rtl/snow5_aes_round.v

And yes, it accepts a round key, but it is actually explicitly set in Snow5 to zero. See page 5 in the Snow5 paper:
https://eprint.iacr.org/2018/1143.pdf

Your test vectors are actually quite useful. I will add them to the testbench for the snow5_aes_round.v

I've added a testbench for the snow5_aes_round and a testcase with your vector. And I don't get the expected value. I will debug.

I think I have written the key in the wrong endianness. Try to change the round key.

round key (wrong):
round key = 06 84 70 4c e6 20 c0 0a b2 c5 fe f0 75 81 7b 9d

round key new:
round_key = 9d 7b 81 75 f0 fe c5 b2 0a c0 20 e6 4c 70 84 06

Result should be:
block_new = f7 11 dd 30 dc 93 f6 e3 ba 19 7d 87 6b ec a5 5a

Ah!, much better:

Testing vectors created using AES-NI:
State of DUT

Inputs and outputs:
key: 0x9d7b8175f0fec5b20ac020e64c708406
in: 0x000102030405060708090a0b0c0d0e0f
out: 0xf711dd30dc93f6e3ba197d876beca55a

So you should be able to use the snow5_aes_round in you implementation.

Closing this issue since we have a solution in the snow5 repo.