Skip to content

Instantly share code, notes, and snippets.

@colinoflynn
Last active June 13, 2020 15:19
Show Gist options
  • Save colinoflynn/4d430e2b869ad3ef35e4b668783f1cee to your computer and use it in GitHub Desktop.
Save colinoflynn/4d430e2b869ad3ef35e4b668783f1cee to your computer and use it in GitHub Desktop.

Cache Oddity Stuff

Using fork of mbed-tls AES implementation I've looked at a bit: https://github.com/newaetech/chipwhisperer/blob/develop/hardware/victims/firmware/crypto/mbedtls/library/aes.c

Important chunks:

One round of AES works like this with T-Tables:

#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3)     \
{                                               \
    X0 = *RK++ ^ FT0[ ( Y0       ) & 0xFF ] ^   \
                 FT1[ ( Y1 >>  8 ) & 0xFF ] ^   \
                 FT2[ ( Y2 >> 16 ) & 0xFF ] ^   \
                 FT3[ ( Y3 >> 24 ) & 0xFF ];    \
                                                \
    X1 = *RK++ ^ FT0[ ( Y1       ) & 0xFF ] ^   \
                 FT1[ ( Y2 >>  8 ) & 0xFF ] ^   \
                 FT2[ ( Y3 >> 16 ) & 0xFF ] ^   \
                 FT3[ ( Y0 >> 24 ) & 0xFF ];    \
                                                \
    X2 = *RK++ ^ FT0[ ( Y2       ) & 0xFF ] ^   \
                 FT1[ ( Y3 >>  8 ) & 0xFF ] ^   \
                 FT2[ ( Y0 >> 16 ) & 0xFF ] ^   \
                 FT3[ ( Y1 >> 24 ) & 0xFF ];    \
                                                \
    X3 = *RK++ ^ FT0[ ( Y3       ) & 0xFF ] ^   \
                 FT1[ ( Y0 >>  8 ) & 0xFF ] ^   \
                 FT2[ ( Y1 >> 16 ) & 0xFF ] ^   \
                 FT3[ ( Y2 >> 24 ) & 0xFF ];    \
}

When it goes to encrypt something, it runs this before calling the FROUND() function above:

NB: Watch carefully Xn vs Yn - I've changed X to Y below to match the above function, in MBED-TLS AES it swaps the two around, the code works fine but it's confusing as X0 in the encryption function becomes Y0 in the macro above for example

    GET_UINT32_LE( Y0, input,  0 ); Y0 ^= *RK++;
    GET_UINT32_LE( Y1, input,  4 ); Y1 ^= *RK++;
    GET_UINT32_LE( Y2, input,  8 ); Y2 ^= *RK++;
    GET_UINT32_LE( Y3, input, 12 ); Y3 ^= *RK++;

If you run through a single round for example, we can make the previous FROUND function reference a new INPUT[N] variable, which is the input ^ RK from above, but referencing byte N. This makes it easier to see the byte collisions than before (I think anyway):

    X0 = *RK++ ^ FT0[ ( INPUT[0] ) ] ^   \
                 FT1[ ( INPUT[5] ) ] ^   \
                 FT2[ ( INPUT[10]) ] ^   \
                 FT3[ ( INPUT[15]) ];    \
                                                \
    X1 = *RK++ ^ FT0[ ( INPUT[4] ) ] ^   \
                 FT1[ ( INPUT[9] ) ] ^   \
                 FT2[ ( INPUT[14]) ] ^   \
                 FT3[ ( INPUT[3] ) ];    \
                                                \
    X2 = *RK++ ^ FT0[ ( INPUT[8] ) ] ^   \
                 FT1[ ( INPUT[13]) ] ^   \
                 FT2[ ( INPUT[2] ) ] ^   \
                 FT3[ ( INPUT[7] ) ];    \
                                                \
    X3 = *RK++ ^ FT0[ ( INPUT[12]) ] ^   \
                 FT1[ ( INPUT[1] ) ] ^   \
                 FT2[ ( INPUT[6] ) ] ^   \
                 FT3[ ( INPUT[11]) ];    \

This has the expected collisions on the FT tables (FT = Forward T-Table).

If we write out the order of access to elements, we see the following:

X0: 0   5  10  15
X1: 4   9  14   3
X2: 8  13   2   7
X3: 12  1   6  11

There also appears to be collisions from 5-->12, 10-->1, 15-->6 (wrapping around).

The next call to AES_FROUND is for 2nd round effectively, so seems unlikely it's providing additional leakage?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment