aes.c revision 663860b1408516d02ebfcb3a9999a134e6cfb223
1
2#include <string.h>
3#include <stdio.h>
4#include <assert.h>
5
6typedef  unsigned int   UInt;
7typedef  signed int     Int;
8typedef  unsigned char  UChar;
9typedef  unsigned long long int ULong;
10typedef  UChar          Bool;
11#define False ((Bool)0)
12#define True  ((Bool)1)
13
14//typedef  unsigned char  V128[16];
15typedef
16   union {
17      UChar uChar[16];
18      UInt  uInt[4];
19   }
20   V128;
21
22static UChar fromhex(char x) {
23   if      (x >= '0' && x <= '9') { return(x - '0'); }
24   else if (x >= 'A' && x <= 'F') { return(x - 'A' + 10); }
25   else if (x >= 'a' && x <= 'f') { return(x - 'a' + 10); }
26   else assert(0);
27}
28
29static void expand ( V128* dst, char* summary )
30{
31   Int i;
32   assert( strlen(summary) == 32 );
33   for (i = 0; i < 16; i++) {
34      UChar xx = 0;
35      UChar x = summary[31-2*i];
36      UChar yy = 0;
37      UChar y = summary[31-2*i-1];
38      xx = fromhex (x);
39      yy = fromhex (y);
40
41      assert(xx < 16);
42      assert(yy < 16);
43      xx = (yy << 4) | xx;
44      assert(xx < 256);
45      dst->uChar[i] = xx;
46   }
47}
48
49static int tohex (int nib)
50{
51   if (nib < 10)
52      return '0' + nib;
53   else
54      return 'a' + nib - 10;
55}
56static void unexpand ( V128* dst, char* summary )
57{
58   Int i;
59   for (i = 0; i < 16; i++) {
60      *summary++ = tohex((dst->uChar[i] >> 4) & 0xf);
61      *summary++ = tohex(dst->uChar[i] & 0xf);
62   }
63   *summary = 0;
64}
65
66static void AESDEC(char *s_argL, char *s_argR, char *s_exp)
67{
68   /*
69     ; xmm1 and xmm2 hold two 128-bit inputs (xmm1 = State; xmm2 = Round key).
70     ; The result is delivered in xmm1.
71   */
72   V128 argL, argR;
73   V128 res;
74   char s_res[33];
75   V128 exp;
76   expand(&argL, s_argL);
77   expand(&argR, s_argR);
78   __asm__ __volatile__(
79      "subq      $1024,  %%rsp"             "\n\t"
80      "movdqu    %1,     %%xmm1"            "\n\t"
81      "movdqu    %2,     %%xmm2"            "\n\t"
82      "aesdec    %%xmm2, %%xmm1"            "\n\t"
83      "movdqu    %%xmm1, %0"                "\n\t"
84      "addq      $1024,  %%rsp"             "\n\t"
85      : /*out*/ "=m"(res)
86      : "m"/*in*/(argL), "m"/*in*/(argR)
87      : /*trash*/ "xmm1", "xmm2"
88   );
89
90   if (strlen(s_exp) > 0) {
91      expand(&exp,  s_exp);
92      assert (0 == memcmp(&res, &exp, 16));
93   }
94   unexpand (&res, s_res);
95   printf ("aesdec %s %s result %s\n", s_argL, s_argR, s_res);
96}
97
98static void AESDECLAST(char *s_argL, char *s_argR, char *s_exp)
99{
100   /*
101     ; xmm1 and xmm2 hold two 128-bit inputs (xmm1 = State; xmm2 = Round key).
102     ; The result is delivered in xmm1.
103   */
104   V128 argL, argR;
105   V128 res;
106   char s_res[33];
107   V128 exp;
108   expand(&argL, s_argL);
109   expand(&argR, s_argR);
110   __asm__ __volatile__(
111      "subq       $1024,  %%rsp"             "\n\t"
112      "movdqu     %1,     %%xmm1"            "\n\t"
113      "movdqu     %2,     %%xmm2"            "\n\t"
114      "aesdeclast %%xmm2, %%xmm1"            "\n\t"
115      "movdqu     %%xmm1, %0"                "\n\t"
116      "addq       $1024,  %%rsp"             "\n\t"
117      : /*out*/ "=m"(res)
118      : "m"/*in*/(argL), "m"/*in*/(argR)
119      : /*trash*/ "xmm1", "xmm2"
120   );
121
122   if (strlen(s_exp) > 0) {
123      expand(&exp,  s_exp);
124      assert (0 == memcmp(&res, &exp, 16));
125   }
126   unexpand (&res, s_res);
127   printf ("aesdeclast %s %s result %s\n", s_argL, s_argR, s_res);
128}
129
130static void AESENC(char *s_argL, char *s_argR, char *s_exp)
131{
132   /*
133     ; xmm1 and xmm2 hold two 128-bit inputs (xmm1 = State; xmm2 = Round key).
134     ; The result is delivered in xmm1.
135   */
136   V128 argL, argR;
137   V128 res;
138   char s_res[33];
139   V128 exp;
140   expand(&argL, s_argL);
141   expand(&argR, s_argR);
142   __asm__ __volatile__(
143      "subq      $1024,  %%rsp"             "\n\t"
144      "movdqu    %1,     %%xmm1"            "\n\t"
145      "movdqu    %2,     %%xmm2"            "\n\t"
146      "aesenc    %%xmm2, %%xmm1"            "\n\t"
147      "movdqu    %%xmm1, %0"                "\n\t"
148      "addq      $1024,  %%rsp"             "\n\t"
149      : /*out*/ "=m"(res)
150      : "m"/*in*/(argL), "m"/*in*/(argR)
151      : /*trash*/ "xmm1", "xmm2"
152   );
153
154   if (strlen(s_exp) > 0) {
155      expand(&exp,  s_exp);
156      assert (0 == memcmp(&res, &exp, 16));
157   }
158   unexpand (&res, s_res);
159   printf ("aesenc %s %s result %s\n", s_argL, s_argR, s_res);
160}
161
162static void AESENCLAST(char *s_argL, char *s_argR, char *s_exp)
163{
164   /*
165     ; xmm1 and xmm2 hold two 128-bit inputs (xmm1 = State; xmm2 = Round key)
166     ; The result delivered in xmm1
167   */
168   V128 argL, argR;
169   V128 res;
170   char s_res[33];
171   V128 exp;
172   expand(&argL, s_argL);
173   expand(&argR, s_argR);
174   __asm__ __volatile__(
175      "subq       $1024,  %%rsp"             "\n\t"
176      "movdqu     %1,     %%xmm1"            "\n\t"
177      "movdqu     %2,     %%xmm2"            "\n\t"
178      "aesenclast %%xmm2, %%xmm1"            "\n\t"
179      "movdqu     %%xmm1, %0"                "\n\t"
180      "addq       $1024,  %%rsp"             "\n\t"
181      : /*out*/ "=m"(res)
182      : "m"/*in*/(argL), "m"/*in*/(argR)
183      : /*trash*/ "xmm1", "xmm2"
184   );
185
186   if (strlen(s_exp) > 0) {
187      expand(&exp,  s_exp);
188      assert (0 == memcmp(&res, &exp, 16));
189   }
190   unexpand (&res, s_res);
191   printf ("aesenclast %s %s result %s\n", s_argL, s_argR, s_res);
192}
193
194static void AESIMC(char *s_argR, char *s_exp)
195{
196   /* We test another way to pass input and get results */
197   /* ; argR hold one 128-bit inputs (argR = Round key)
198      ; result delivered in xmm5 */
199
200   V128 argR;
201   V128 res;
202   char s_res[33];
203   V128 exp;
204   expand(&argR, s_argR);
205
206   __asm__ __volatile__(
207      "subq       $1024,  %%rsp"             "\n\t"
208      "aesimc     %1,     %%xmm5"            "\n\t"
209      "movdqu     %%xmm5, %0"                "\n\t"
210      "addq       $1024,  %%rsp"             "\n\t"
211      : /*out*/ "=m"(res)
212      : "m"/*in*/(argR)
213      : /*trash*/ "xmm5"
214   );
215
216   if (strlen(s_exp) > 0) {
217      expand(&exp,  s_exp);
218      assert (0 == memcmp(&res, &exp, 16));
219   }
220   unexpand (&res, s_res);
221   printf ("aesimc %s result %s\n", s_argR, s_res);
222}
223
224static void AESKEYGENASSIST(int imm, char* s_argL, char* s_exp)
225{
226   /*
227     ; xmm2 holds a 128-bit input; imm8 holds the RCON value
228     ; result delivered in xmm1
229   */
230
231   V128 argL;
232   V128 res;
233   char s_res[33];
234   V128 exp;
235   expand(&argL, s_argL);
236   if (imm == 1)
237      __asm__ __volatile__(
238         "subq       $1024,  %%rsp"             "\n\t"
239         "movdqu     %1,     %%xmm2"            "\n\t"
240         "aeskeygenassist $1,%%xmm2, %%xmm1"    "\n\t"
241         "movdqu     %%xmm1, %0"                "\n\t"
242         "addq       $1024,  %%rsp"             "\n\t"
243         : /*out*/ "=m"(res)
244         : "m"/*in*/(argL)
245         : /*trash*/ "xmm1", "xmm2"
246      );
247   else if (imm == 2)
248      __asm__ __volatile__(
249         "subq       $1024,  %%rsp"             "\n\t"
250         "movdqu     %1,     %%xmm2"            "\n\t"
251         "aeskeygenassist $2,%%xmm2, %%xmm1"    "\n\t"
252         "movdqu     %%xmm1, %0"                "\n\t"
253         "addq       $1024,  %%rsp"             "\n\t"
254         : /*out*/ "=m"(res)
255         : "m"/*in*/(argL)
256         : /*trash*/ "xmm1", "xmm2"
257      );
258   else if (imm == 8)
259      __asm__ __volatile__(
260         "subq       $1024,  %%rsp"             "\n\t"
261         "movdqu     %1,     %%xmm2"            "\n\t"
262         "aeskeygenassist $8,%%xmm2, %%xmm1"    "\n\t"
263         "movdqu     %%xmm1, %0"                "\n\t"
264         "addq       $1024,  %%rsp"             "\n\t"
265         : /*out*/ "=m"(res)
266         : "m"/*in*/(argL)
267         : /*trash*/ "xmm1", "xmm2"
268      );
269   else assert (0);
270
271   if (strlen(s_exp) > 0) {
272      expand(&exp,  s_exp);
273      assert (0 == memcmp(&res, &exp, 16));
274   }
275   unexpand (&res, s_res);
276   printf ("aeskeygenassist %d %s result %s\n", imm, s_argL, s_res);
277}
278
279typedef struct Aes_Args {
280   char* argL;
281   char* argR;
282   int imm; // only for aeskeygenassist
283} Aes_Args;
284
285/* Just a bunch of various data to compare a native run
286   with a run under Valgrind. */
287static const Aes_Args aes_args[] = {
288   {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
289    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
290    8},
291   {"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
292    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
293    8},
294   {"3243f6a8885a308d313198a2e0370734",
295    "2b7e151628aed2a6abf7158809cf4f3c",
296    2},
297   {"193de3bea0f4e22b9ac68d2ae9f84808",
298    "d42711aee0bf98f1b8b45de51e415230",
299    2},
300   {"d4bf5d30e0b452aeb84111f11e2798e5",
301    "046681e5e0cb199a48f8d37a2806264c",
302    1},
303   {"a0fafe1788542cb123a339392a6c7605",
304    "a49c7ff2689f352b6b5bea43026a5049",
305    1},
306   {"49ded28945db96f17f39871a7702533b",
307    "49db873b453953897f02d2f177de961a",
308    8},
309   {"584dcaf11b4b5aacdbe7caa81b6bb0e5",
310    "f2c295f27a96b9435935807a7359f67f",
311    8},
312   {"aa8f5f0361dde3ef82d24ad26832469a",
313    "ac73cf7befc111df13b5d6b545235ab8",
314    2},
315   {"acc1d6b8efb55a7b1323cfdf457311b5",
316    "75ec0993200b633353c0cf7cbb25d0dc",
317    2},
318   {"e9317db5cb322c723d2e895faf090794",
319    "d014f9a8c9ee2589e13f0cc8b6630ca6",
320    1},
321   {NULL,
322    NULL,
323    0}
324};
325
326int main ( void )
327{
328   int i;
329
330   /* test the various instructions, using the examples provided
331      in  "White Paper Intel Advanced Encryption Standard AES
332          instruction set" January 2010 (26/1/2010)
333          Rev. 3.0
334          by Shay Gueron */
335   AESKEYGENASSIST(1,
336                   "3c4fcf098815f7aba6d2ae2816157e2b",
337                   "01eb848beb848a013424b5e524b5e434");
338   AESENC("7b5b54657374566563746f725d53475d",
339          "48692853686179295b477565726f6e5d",
340          "a8311c2f9fdba3c58b104b58ded7e595");
341   AESENCLAST("7b5b54657374566563746f725d53475d",
342              "48692853686179295b477565726f6e5d",
343              "c7fb881e938c5964177ec42553fdc611");
344   AESDEC("7b5b54657374566563746f725d53475d",
345          "48692853686179295b477565726f6e5d",
346          "138ac342faea2787b58eb95eb730392a");
347   AESDECLAST("7b5b54657374566563746f725d53475d",
348              "48692853686179295b477565726f6e5d",
349              "c5a391ef6b317f95d410637b72a593d0");
350   /* ??? the AESIMC example given in the Intel White paper
351      seems wrong.
352      The below fails both under Valgrind and natively.
353      AESIMC("48692853686179295b477565726f6e5d",
354             "627a6f6644b109c82b18330a81c3b3e5");
355      So we use the example given for the InvMixColums
356      transformation. */
357   AESIMC("8dcab9dc035006bc8f57161e00cafd8d",
358          "d635a667928b5eaeeec9cc3bc55f5777");
359
360
361   /* and now a bunch of other calls. The below are verified
362      using the aes.stdout.exp (produced by a native run). */
363
364   for (i = 0; aes_args[i].argL != NULL; i++) {
365      AESKEYGENASSIST(aes_args[i].imm, aes_args[i].argL, "");
366      AESENC(aes_args[i].argL, aes_args[i].argR, "");
367      AESENCLAST(aes_args[i].argL, aes_args[i].argR, "");
368      AESDEC(aes_args[i].argL, aes_args[i].argR, "");
369      AESDECLAST(aes_args[i].argL, aes_args[i].argR, "");
370      AESIMC(aes_args[i].argL, "");
371   }
372   return 0;
373}
374