blob: a0c83c6b2b26239cecdbf226cb178474111031af [file] [log] [blame]
#include <string.h>
#include <stdio.h>
#include <assert.h>
typedef unsigned int UInt;
typedef signed int Int;
typedef unsigned char UChar;
typedef unsigned long long int ULong;
typedef UChar Bool;
#define False ((Bool)0)
#define True ((Bool)1)
//typedef unsigned char V128[16];
typedef
union {
UChar uChar[16];
UInt uInt[4];
}
V128;
static UChar fromhex(char x) {
if (x >= '0' && x <= '9') { return(x - '0'); }
else if (x >= 'A' && x <= 'F') { return(x - 'A' + 10); }
else if (x >= 'a' && x <= 'f') { return(x - 'a' + 10); }
else assert(0);
}
static void expand ( V128* dst, char* summary )
{
Int i;
assert( strlen(summary) == 32 );
for (i = 0; i < 16; i++) {
UChar xx = 0;
UChar x = summary[31-2*i];
UChar yy = 0;
UChar y = summary[31-2*i-1];
xx = fromhex (x);
yy = fromhex (y);
assert(xx < 16);
assert(yy < 16);
xx = (yy << 4) | xx;
assert(xx < 256);
dst->uChar[i] = xx;
}
}
static int tohex (int nib)
{
if (nib < 10)
return '0' + nib;
else
return 'a' + nib - 10;
}
static void unexpand ( V128* dst, char* summary )
{
Int i;
for (i = 0; i < 16; i++) {
*summary++ = tohex((dst->uChar[i] >> 4) & 0xf);
*summary++ = tohex(dst->uChar[i] & 0xf);
}
*summary = 0;
}
static void AESDEC(char *s_argL, char *s_argR, char *s_exp)
{
/*
; xmm1 and xmm2 hold two 128-bit inputs (xmm1 = State; xmm2 = Round key).
; The result is delivered in xmm1.
*/
V128 argL, argR;
V128 res;
char s_res[33];
V128 exp;
expand(&argL, s_argL);
expand(&argR, s_argR);
__asm__ __volatile__(
"subq $1024, %%rsp" "\n\t"
"movdqu %1, %%xmm1" "\n\t"
"movdqu %2, %%xmm2" "\n\t"
"aesdec %%xmm2, %%xmm1" "\n\t"
"movdqu %%xmm1, %0" "\n\t"
"addq $1024, %%rsp" "\n\t"
: /*out*/ "=m"(res)
: "m"/*in*/(argL), "m"/*in*/(argR)
: /*trash*/ "xmm1", "xmm2"
);
if (strlen(s_exp) > 0) {
expand(&exp, s_exp);
assert (0 == memcmp(&res, &exp, 16));
}
unexpand (&res, s_res);
printf ("aesdec %s %s result %s\n", s_argL, s_argR, s_res);
}
static void AESDECLAST(char *s_argL, char *s_argR, char *s_exp)
{
/*
; xmm1 and xmm2 hold two 128-bit inputs (xmm1 = State; xmm2 = Round key).
; The result is delivered in xmm1.
*/
V128 argL, argR;
V128 res;
char s_res[33];
V128 exp;
expand(&argL, s_argL);
expand(&argR, s_argR);
__asm__ __volatile__(
"subq $1024, %%rsp" "\n\t"
"movdqu %1, %%xmm1" "\n\t"
"movdqu %2, %%xmm2" "\n\t"
"aesdeclast %%xmm2, %%xmm1" "\n\t"
"movdqu %%xmm1, %0" "\n\t"
"addq $1024, %%rsp" "\n\t"
: /*out*/ "=m"(res)
: "m"/*in*/(argL), "m"/*in*/(argR)
: /*trash*/ "xmm1", "xmm2"
);
if (strlen(s_exp) > 0) {
expand(&exp, s_exp);
assert (0 == memcmp(&res, &exp, 16));
}
unexpand (&res, s_res);
printf ("aesdeclast %s %s result %s\n", s_argL, s_argR, s_res);
}
static void AESENC(char *s_argL, char *s_argR, char *s_exp)
{
/*
; xmm1 and xmm2 hold two 128-bit inputs (xmm1 = State; xmm2 = Round key).
; The result is delivered in xmm1.
*/
V128 argL, argR;
V128 res;
char s_res[33];
V128 exp;
expand(&argL, s_argL);
expand(&argR, s_argR);
__asm__ __volatile__(
"subq $1024, %%rsp" "\n\t"
"movdqu %1, %%xmm1" "\n\t"
"movdqu %2, %%xmm2" "\n\t"
"aesenc %%xmm2, %%xmm1" "\n\t"
"movdqu %%xmm1, %0" "\n\t"
"addq $1024, %%rsp" "\n\t"
: /*out*/ "=m"(res)
: "m"/*in*/(argL), "m"/*in*/(argR)
: /*trash*/ "xmm1", "xmm2"
);
if (strlen(s_exp) > 0) {
expand(&exp, s_exp);
assert (0 == memcmp(&res, &exp, 16));
}
unexpand (&res, s_res);
printf ("aesenc %s %s result %s\n", s_argL, s_argR, s_res);
}
static void AESENCLAST(char *s_argL, char *s_argR, char *s_exp)
{
/*
; xmm1 and xmm2 hold two 128-bit inputs (xmm1 = State; xmm2 = Round key)
; The result delivered in xmm1
*/
V128 argL, argR;
V128 res;
char s_res[33];
V128 exp;
expand(&argL, s_argL);
expand(&argR, s_argR);
__asm__ __volatile__(
"subq $1024, %%rsp" "\n\t"
"movdqu %1, %%xmm1" "\n\t"
"movdqu %2, %%xmm2" "\n\t"
"aesenclast %%xmm2, %%xmm1" "\n\t"
"movdqu %%xmm1, %0" "\n\t"
"addq $1024, %%rsp" "\n\t"
: /*out*/ "=m"(res)
: "m"/*in*/(argL), "m"/*in*/(argR)
: /*trash*/ "xmm1", "xmm2"
);
if (strlen(s_exp) > 0) {
expand(&exp, s_exp);
assert (0 == memcmp(&res, &exp, 16));
}
unexpand (&res, s_res);
printf ("aesenclast %s %s result %s\n", s_argL, s_argR, s_res);
}
static void AESIMC(char *s_argR, char *s_exp)
{
/* We test another way to pass input and get results */
/* ; argR hold one 128-bit inputs (argR = Round key)
; result delivered in xmm5 */
V128 argR;
V128 res;
char s_res[33];
V128 exp;
expand(&argR, s_argR);
__asm__ __volatile__(
"subq $1024, %%rsp" "\n\t"
"aesimc %1, %%xmm5" "\n\t"
"movdqu %%xmm5, %0" "\n\t"
"addq $1024, %%rsp" "\n\t"
: /*out*/ "=m"(res)
: "m"/*in*/(argR)
: /*trash*/ "xmm5"
);
if (strlen(s_exp) > 0) {
expand(&exp, s_exp);
assert (0 == memcmp(&res, &exp, 16));
}
unexpand (&res, s_res);
printf ("aesimc %s result %s\n", s_argR, s_res);
}
static void AESKEYGENASSIST(int imm, char* s_argL, char* s_exp)
{
/*
; xmm2 holds a 128-bit input; imm8 holds the RCON value
; result delivered in xmm1
*/
V128 argL;
V128 res;
char s_res[33];
V128 exp;
expand(&argL, s_argL);
if (imm == 1)
__asm__ __volatile__(
"subq $1024, %%rsp" "\n\t"
"movdqu %1, %%xmm2" "\n\t"
"aeskeygenassist $1,%%xmm2, %%xmm1" "\n\t"
"movdqu %%xmm1, %0" "\n\t"
"addq $1024, %%rsp" "\n\t"
: /*out*/ "=m"(res)
: "m"/*in*/(argL)
: /*trash*/ "xmm1", "xmm2"
);
else if (imm == 2)
__asm__ __volatile__(
"subq $1024, %%rsp" "\n\t"
"movdqu %1, %%xmm2" "\n\t"
"aeskeygenassist $2,%%xmm2, %%xmm1" "\n\t"
"movdqu %%xmm1, %0" "\n\t"
"addq $1024, %%rsp" "\n\t"
: /*out*/ "=m"(res)
: "m"/*in*/(argL)
: /*trash*/ "xmm1", "xmm2"
);
else if (imm == 8)
__asm__ __volatile__(
"subq $1024, %%rsp" "\n\t"
"movdqu %1, %%xmm2" "\n\t"
"aeskeygenassist $8,%%xmm2, %%xmm1" "\n\t"
"movdqu %%xmm1, %0" "\n\t"
"addq $1024, %%rsp" "\n\t"
: /*out*/ "=m"(res)
: "m"/*in*/(argL)
: /*trash*/ "xmm1", "xmm2"
);
else assert (0);
if (strlen(s_exp) > 0) {
expand(&exp, s_exp);
assert (0 == memcmp(&res, &exp, 16));
}
unexpand (&res, s_res);
printf ("aeskeygenassist %d %s result %s\n", imm, s_argL, s_res);
}
typedef struct Aes_Args {
char* argL;
char* argR;
int imm; // only for aeskeygenassist
} Aes_Args;
/* Just a bunch of various data to compare a native run
with a run under Valgrind. */
static const Aes_Args aes_args[] = {
{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
8},
{"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
8},
{"3243f6a8885a308d313198a2e0370734",
"2b7e151628aed2a6abf7158809cf4f3c",
2},
{"193de3bea0f4e22b9ac68d2ae9f84808",
"d42711aee0bf98f1b8b45de51e415230",
2},
{"d4bf5d30e0b452aeb84111f11e2798e5",
"046681e5e0cb199a48f8d37a2806264c",
1},
{"a0fafe1788542cb123a339392a6c7605",
"a49c7ff2689f352b6b5bea43026a5049",
1},
{"49ded28945db96f17f39871a7702533b",
"49db873b453953897f02d2f177de961a",
8},
{"584dcaf11b4b5aacdbe7caa81b6bb0e5",
"f2c295f27a96b9435935807a7359f67f",
8},
{"aa8f5f0361dde3ef82d24ad26832469a",
"ac73cf7befc111df13b5d6b545235ab8",
2},
{"acc1d6b8efb55a7b1323cfdf457311b5",
"75ec0993200b633353c0cf7cbb25d0dc",
2},
{"e9317db5cb322c723d2e895faf090794",
"d014f9a8c9ee2589e13f0cc8b6630ca6",
1},
{NULL,
NULL,
0}
};
int main ( void )
{
int i;
/* test the various instructions, using the examples provided
in "White Paper Intel Advanced Encryption Standard AES
instruction set" January 2010 (26/1/2010)
Rev. 3.0
by Shay Gueron */
AESKEYGENASSIST(1,
"3c4fcf098815f7aba6d2ae2816157e2b",
"01eb848beb848a013424b5e524b5e434");
AESENC("7b5b54657374566563746f725d53475d",
"48692853686179295b477565726f6e5d",
"a8311c2f9fdba3c58b104b58ded7e595");
AESENCLAST("7b5b54657374566563746f725d53475d",
"48692853686179295b477565726f6e5d",
"c7fb881e938c5964177ec42553fdc611");
AESDEC("7b5b54657374566563746f725d53475d",
"48692853686179295b477565726f6e5d",
"138ac342faea2787b58eb95eb730392a");
AESDECLAST("7b5b54657374566563746f725d53475d",
"48692853686179295b477565726f6e5d",
"c5a391ef6b317f95d410637b72a593d0");
/* ??? the AESIMC example given in the Intel White paper
seems wrong.
The below fails both under Valgrind and natively.
AESIMC("48692853686179295b477565726f6e5d",
"627a6f6644b109c82b18330a81c3b3e5");
So we use the example given for the InvMixColums
transformation. */
AESIMC("8dcab9dc035006bc8f57161e00cafd8d",
"d635a667928b5eaeeec9cc3bc55f5777");
/* and now a bunch of other calls. The below are verified
using the aes.stdout.exp (produced by a native run). */
for (i = 0; aes_args[i].argL != NULL; i++) {
AESKEYGENASSIST(aes_args[i].imm, aes_args[i].argL, "");
AESENC(aes_args[i].argL, aes_args[i].argR, "");
AESENCLAST(aes_args[i].argL, aes_args[i].argR, "");
AESDEC(aes_args[i].argL, aes_args[i].argR, "");
AESDECLAST(aes_args[i].argL, aes_args[i].argR, "");
AESIMC(aes_args[i].argL, "");
}
return 0;
}