blob: aa1f4b1c427c776bb227debde53ecc53d2efcd64 [file] [log] [blame]
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +01001/*
2 * AES-NI support functions
3 *
4 * Copyright (C) 2013, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26/*
27 * [AES-WP] http://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set
Manuel Pégourié-Gonnardd333f672013-12-26 11:44:46 +010028 * [CLMUL-WP] http://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode/
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +010029 */
30
31#include "polarssl/config.h"
32
33#if defined(POLARSSL_AESNI_C)
34
35#include "polarssl/aesni.h"
Manuel Pégourié-Gonnard5b685652013-12-18 11:45:21 +010036#include <stdio.h>
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +010037
38#if defined(POLARSSL_HAVE_X86_64)
39
40/*
Manuel Pégourié-Gonnard8eaf20b2013-12-18 19:14:53 +010041 * AES-NI support detection routine
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +010042 */
Manuel Pégourié-Gonnard8eaf20b2013-12-18 19:14:53 +010043int aesni_supports( unsigned int what )
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +010044{
Manuel Pégourié-Gonnard8eaf20b2013-12-18 19:14:53 +010045 static int done = 0;
46 static unsigned int c = 0;
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +010047
Manuel Pégourié-Gonnard8eaf20b2013-12-18 19:14:53 +010048 if( ! done )
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +010049 {
50 asm( "movl $1, %%eax \n"
51 "cpuid \n"
52 : "=c" (c)
53 :
54 : "eax", "ebx", "edx" );
Manuel Pégourié-Gonnard8eaf20b2013-12-18 19:14:53 +010055 done = 1;
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +010056 }
57
Manuel Pégourié-Gonnard8eaf20b2013-12-18 19:14:53 +010058 return( ( c & what ) != 0 );
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +010059}
60
Manuel Pégourié-Gonnard5b685652013-12-18 11:45:21 +010061/*
62 * AES-NI AES-ECB block en(de)cryption
63 */
64int aesni_crypt_ecb( aes_context *ctx,
65 int mode,
66 const unsigned char input[16],
67 unsigned char output[16] )
68{
69 asm( "movdqu (%3), %%xmm0 \n" // load input
70 "movdqu (%1), %%xmm1 \n" // load round key 0
71 "pxor %%xmm1, %%xmm0 \n" // round 0
72 "addq $16, %1 \n" // point to next round key
73 "subl $1, %0 \n" // normal rounds = nr - 1
74 "test %2, %2 \n" // mode?
75 "jz 2f \n" // 0 = decrypt
76
77 "1: \n" // encryption loop
78 "movdqu (%1), %%xmm1 \n" // load round key
79 "aesenc %%xmm1, %%xmm0 \n" // do round
80 "addq $16, %1 \n" // point to next round key
81 "subl $1, %0 \n" // loop
82 "jnz 1b \n"
83 "movdqu (%1), %%xmm1 \n" // load round key
84 "aesenclast %%xmm1, %%xmm0 \n" // last round
85 "jmp 3f \n"
86
87 "2: \n" // decryption loop
88 "movdqu (%1), %%xmm1 \n"
89 "aesdec %%xmm1, %%xmm0 \n"
90 "addq $16, %1 \n"
91 "subl $1, %0 \n"
92 "jnz 2b \n"
93 "movdqu (%1), %%xmm1 \n" // load round key
94 "aesdeclast %%xmm1, %%xmm0 \n" // last round
95
96 "3: \n"
97 "movdqu %%xmm0, (%4) \n" // export output
98 :
99 : "r" (ctx->nr), "r" (ctx->rk), "r" (mode), "r" (input), "r" (output)
100 : "memory", "cc", "xmm0", "xmm1" );
101
102
103 return( 0 );
104}
Manuel Pégourié-Gonnardd333f672013-12-26 11:44:46 +0100105
106/*
107 * GCM multiplication: c = a times b in GF(2^128)
108 * Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5.
109 */
110int aesni_gcm_mult( unsigned char c[16],
111 const unsigned char a[16],
112 const unsigned char b[16] )
113{
114 unsigned char aa[16], bb[16], cc[16];
115 size_t i;
116
117 /* The inputs are in big-endian order, so byte-reverse them */
118 for( i = 0; i < 16; i++ )
119 {
120 aa[i] = a[15 - i];
121 bb[i] = b[15 - i];
122 }
123
124 asm( "movdqu (%0), %%xmm0 \n" // a1:a0
125 "movdqu (%1), %%xmm1 \n" // b1:b0
126
127 /*
128 * Caryless multiplication xmm2:xmm1 = xmm0 * xmm1
129 * using [CLMUL-WP] algorithm 1 (p. 13).
130 */
131 "movdqa %%xmm1, %%xmm2 \n" // copy of b1:b0
132 "movdqa %%xmm1, %%xmm3 \n" // same
133 "movdqa %%xmm1, %%xmm4 \n" // same
134 "pclmulqdq $0x00, %%xmm0, %%xmm1 \n" // a0*b0 = c1:c0
135 "pclmulqdq $0x11, %%xmm0, %%xmm2 \n" // a1*b1 = d1:d0
136 "pclmulqdq $0x10, %%xmm0, %%xmm3 \n" // a0*b1 = e1:e0
137 "pclmulqdq $0x01, %%xmm0, %%xmm4 \n" // a1*b0 = f1:f0
138 "pxor %%xmm3, %%xmm4 \n" // e1+f1:e0+f0
139 "movdqa %%xmm4, %%xmm3 \n" // same
140 "psrldq $8, %%xmm4 \n" // 0:e1+f1
141 "pslldq $8, %%xmm3 \n" // e0+f0:0
142 "pxor %%xmm4, %%xmm2 \n" // d1:d0+e1+f1
143 "pxor %%xmm3, %%xmm1 \n" // c1+e0+f1:c0
144
145 /*
146 * Now shift the result one bit to the left,
147 * taking advantage of [CLMUL-WP] eq 27 (p. 20)
148 */
149 "movdqa %%xmm1, %%xmm3 \n" // r1:r0
150 "movdqa %%xmm2, %%xmm4 \n" // r3:r2
151 "psllq $1, %%xmm1 \n" // r1<<1:r0<<1
152 "psllq $1, %%xmm2 \n" // r3<<1:r2<<1
153 "psrlq $63, %%xmm3 \n" // r1>>63:r0>>63
154 "psrlq $63, %%xmm4 \n" // r3>>63:r2>>63
155 "movdqa %%xmm3, %%xmm5 \n" // r1>>63:r0>>63
156 "pslldq $8, %%xmm3 \n" // r0>>63:0
157 "pslldq $8, %%xmm4 \n" // r2>>63:0
158 "psrldq $8, %%xmm5 \n" // 0:r1>>63
159 "por %%xmm3, %%xmm1 \n" // r1<<1|r0>>63:r0<<1
160 "por %%xmm4, %%xmm2 \n" // r3<<1|r2>>62:r2<<1
161 "por %%xmm5, %%xmm2 \n" // r3<<1|r2>>62:r2<<1|r1>>63
162
163 /*
164 * Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1
165 * using [CLMUL-WP] algorithm 5 (p. 20).
166 * Currently xmm2:xmm1 holds x3:x2:x1:x0 (already shifted).
167 */
168 /* Step 2 (1) */
169 "movdqa %%xmm1, %%xmm3 \n" // x1:x0
170 "movdqa %%xmm1, %%xmm4 \n" // same
171 "movdqa %%xmm1, %%xmm5 \n" // same
172 "psllq $63, %%xmm3 \n" // x1<<63:x0<<63 = stuff:a
173 "psllq $62, %%xmm4 \n" // x1<<62:x0<<62 = stuff:b
174 "psllq $57, %%xmm5 \n" // x1<<57:x0<<57 = stuff:c
175
176 /* Step 2 (2) */
177 "pxor %%xmm4, %%xmm3 \n" // stuff:a+b
178 "pxor %%xmm5, %%xmm3 \n" // stuff:a+b+c
179 "pslldq $8, %%xmm3 \n" // a+b+c:0
180 "pxor %%xmm3, %%xmm1 \n" // x1+a+b+c:x0 = d:x0
181
182 /* Steps 3 and 4 */
183 "movdqa %%xmm1,%%xmm0 \n" // d:x0
184 "movdqa %%xmm1,%%xmm4 \n" // same
185 "movdqa %%xmm1,%%xmm5 \n" // same
186 "psrlq $1, %%xmm0 \n" // e1:x0>>1 = e1:e0'
187 "psrlq $2, %%xmm4 \n" // f1:x0>>2 = f1:f0'
188 "psrlq $7, %%xmm5 \n" // g1:x0>>7 = g1:g0'
189 "pxor %%xmm4, %%xmm0 \n" // e1+f1:e0'+f0'
190 "pxor %%xmm5, %%xmm0 \n" // e1+f1+g1:e0'+f0'+g0'
191 // e0'+f0'+g0' is almost e0+f0+g0, except for some missing
192 // bits carried from d. Now get those bits back in.
193 "movdqa %%xmm1,%%xmm3 \n" // d:x0
194 "movdqa %%xmm1,%%xmm4 \n" // same
195 "movdqa %%xmm1,%%xmm5 \n" // same
196 "psllq $63, %%xmm3 \n" // d<<63:stuff
197 "psllq $62, %%xmm4 \n" // d<<62:stuff
198 "psllq $57, %%xmm5 \n" // d<<57:stuff
199 "pxor %%xmm4, %%xmm3 \n" // d<<63+d<<62:stuff
200 "pxor %%xmm5, %%xmm3 \n" // missing bits of d:stuff
201 "psrldq $8, %%xmm3 \n" // 0:missing bits of d
202 "pxor %%xmm3, %%xmm0 \n" // e1+f1+g1:e0+f0+g0
203 "pxor %%xmm1, %%xmm0 \n" // h1:h0
204 "pxor %%xmm2, %%xmm0 \n" // x3+h1:x2+h0
205
206 "movdqu %%xmm0, (%2) \n" // done
207 :
208 : "r" (aa), "r" (bb), "r" (cc)
209 : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" );
210
211 /* Now byte-reverse the outputs */
212 for( i = 0; i < 16; i++ )
213 c[i] = cc[15 - i];
214
215 return( 0 );
216}
217
Manuel Pégourié-Gonnard01e31bb2013-12-28 15:58:30 +0100218/*
219 * Compute decryption round keys from encryption round keys
220 */
221void aesni_inverse_key( unsigned char *invkey,
222 const unsigned char *fwdkey, int nr )
223{
224 unsigned char *ik = invkey;
225 const unsigned char *fk = fwdkey + 16 * nr;
226
227 memcpy( ik, fk, 16 );
228
229 for( fk -= 16, ik += 16; fk > fwdkey; fk -= 16, ik += 16 )
230 asm( "movdqu (%0), %%xmm0 \n"
231 "aesimc %%xmm0, %%xmm0 \n"
232 "movdqu %%xmm0, (%1) \n"
233 :
234 : "r" (fk), "r" (ik)
235 : "memory", "xmm0" );
236
237 memcpy( ik, fk, 16 );
238}
239
Manuel Pégourié-Gonnard47a35362013-12-28 20:45:04 +0100240/*
241 * Key expansion, 128-bit case
242 */
243void aesni_setkey_enc_128( unsigned char *rk,
244 const unsigned char *key )
245{
246 asm( "movdqu (%1), %%xmm0 \n" // copy the original key
247 "movdqu %%xmm0, (%0) \n" // as round key 0
248 "jmp 2f \n" // skip auxiliary routine
249
250 /*
Manuel Pégourié-Gonnard4a5b9952013-12-29 13:50:32 +0100251 * Finish generating the next round key.
252 *
Manuel Pégourié-Gonnard47a35362013-12-28 20:45:04 +0100253 * On entry xmm0 is r3:r2:r1:r0 and xmm1 is X:stuff:stuff:stuff
254 * with X = rot( sub( r3 ) ) ^ RCON.
255 *
256 * On exit, xmm0 is r7:r6:r5:r4
257 * with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3
258 * and those are written to the round key buffer.
259 */
260 "1: \n"
261 "pshufd $0xff, %%xmm1, %%xmm1 \n" // X:X:X:X
262 "pxor %%xmm0, %%xmm1 \n" // X+r3:X+r2:X+r1:r4
263 "pslldq $4, %%xmm0 \n" // r2:r1:r0:0
264 "pxor %%xmm0, %%xmm1 \n" // X+r3+r2:X+r2+r1:r5:r4
265 "pslldq $4, %%xmm0 \n" // etc
266 "pxor %%xmm0, %%xmm1 \n"
267 "pslldq $4, %%xmm0 \n"
268 "pxor %%xmm1, %%xmm0 \n" // update xmm0 for next time!
269 "add $16, %0 \n" // point to next round key
270 "movdqu %%xmm0, (%0) \n" // write it
271 "ret \n"
272
273 /* Main "loop" */
274 "2: \n"
275 "aeskeygenassist $0x01, %%xmm0, %%xmm1 \ncall 1b \n"
276 "aeskeygenassist $0x02, %%xmm0, %%xmm1 \ncall 1b \n"
277 "aeskeygenassist $0x04, %%xmm0, %%xmm1 \ncall 1b \n"
278 "aeskeygenassist $0x08, %%xmm0, %%xmm1 \ncall 1b \n"
279 "aeskeygenassist $0x10, %%xmm0, %%xmm1 \ncall 1b \n"
280 "aeskeygenassist $0x20, %%xmm0, %%xmm1 \ncall 1b \n"
281 "aeskeygenassist $0x40, %%xmm0, %%xmm1 \ncall 1b \n"
282 "aeskeygenassist $0x80, %%xmm0, %%xmm1 \ncall 1b \n"
283 "aeskeygenassist $0x1B, %%xmm0, %%xmm1 \ncall 1b \n"
284 "aeskeygenassist $0x36, %%xmm0, %%xmm1 \ncall 1b \n"
285 :
286 : "r" (rk), "r" (key)
287 : "memory", "cc", "0" );
288}
289
290/*
Manuel Pégourié-Gonnard23c2f6f2013-12-29 16:05:22 +0100291 * Key expansion, 192-bit case
292 */
293void aesni_setkey_enc_192( unsigned char *rk,
294 const unsigned char *key )
295{
296 asm( "movdqu (%1), %%xmm0 \n" // copy original round key
297 "movdqu %%xmm0, (%0) \n"
298 "add $16, %0 \n"
299 "movq 16(%1), %%xmm1 \n"
300 "movq %%xmm1, (%0) \n"
301 "add $8, %0 \n"
302 "jmp 2f \n" // skip auxiliary routine
303
304 /*
305 * Finish generating the next 6 quarter-keys.
306 *
307 * On entry xmm0 is r3:r2:r1:r0, xmm1 is stuff:stuff:r5:r4
308 * and xmm2 is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON.
309 *
310 * On exit, xmm0 is r9:r8:r7:r6 and xmm1 is stuff:stuff:r11:r10
311 * and those are written to the round key buffer.
312 */
313 "1: \n"
314 "pshufd $0x55, %%xmm2, %%xmm2 \n" // X:X:X:X
315 "pxor %%xmm0, %%xmm2 \n" // X+r3:X+r2:X+r1:r4
316 "pslldq $4, %%xmm0 \n" // etc
317 "pxor %%xmm0, %%xmm2 \n"
318 "pslldq $4, %%xmm0 \n"
319 "pxor %%xmm0, %%xmm2 \n"
320 "pslldq $4, %%xmm0 \n"
321 "pxor %%xmm2, %%xmm0 \n" // update xmm0 = r9:r8:r7:r6
322 "movdqu %%xmm0, (%0) \n"
323 "add $16, %0 \n"
324 "pshufd $0xff, %%xmm0, %%xmm2 \n" // r9:r9:r9:r9
325 "pxor %%xmm1, %%xmm2 \n" // stuff:stuff:r9+r5:r10
326 "pslldq $4, %%xmm1 \n" // r2:r1:r0:0
327 "pxor %%xmm2, %%xmm1 \n" // update xmm1 = stuff:stuff:r11:r10
328 "movq %%xmm1, (%0) \n"
329 "add $8, %0 \n"
330 "ret \n"
331
332 "2: \n"
333 "aeskeygenassist $0x01, %%xmm1, %%xmm2 \ncall 1b \n"
334 "aeskeygenassist $0x02, %%xmm1, %%xmm2 \ncall 1b \n"
335 "aeskeygenassist $0x04, %%xmm1, %%xmm2 \ncall 1b \n"
336 "aeskeygenassist $0x08, %%xmm1, %%xmm2 \ncall 1b \n"
337 "aeskeygenassist $0x10, %%xmm1, %%xmm2 \ncall 1b \n"
338 "aeskeygenassist $0x20, %%xmm1, %%xmm2 \ncall 1b \n"
339 "aeskeygenassist $0x40, %%xmm1, %%xmm2 \ncall 1b \n"
340 "aeskeygenassist $0x80, %%xmm1, %%xmm2 \ncall 1b \n"
341
342 :
343 : "r" (rk), "r" (key)
344 : "memory", "cc", "0" );
345}
346
347/*
Manuel Pégourié-Gonnard4a5b9952013-12-29 13:50:32 +0100348 * Key expansion, 256-bit case
349 */
350void aesni_setkey_enc_256( unsigned char *rk,
351 const unsigned char *key )
352{
353 asm( "movdqu (%1), %%xmm0 \n"
354 "movdqu %%xmm0, (%0) \n"
355 "add $16, %0 \n"
356 "movdqu 16(%1), %%xmm1 \n"
357 "movdqu %%xmm1, (%0) \n"
358 "jmp 2f \n" // skip auxiliary routine
359
360 /*
361 * Finish generating the next two round keys.
362 *
363 * On entry xmm0 is r3:r2:r1:r0, xmm1 is r7:r6:r5:r4 and
364 * xmm2 is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON
365 *
366 * On exit, xmm0 is r11:r10:r9:r8 and xmm1 is r15:r14:r13:r12
367 * and those have been written to the output buffer.
368 */
369 "1: \n"
370 "pshufd $0xff, %%xmm2, %%xmm2 \n"
371 "pxor %%xmm0, %%xmm2 \n"
372 "pslldq $4, %%xmm0 \n"
373 "pxor %%xmm0, %%xmm2 \n"
374 "pslldq $4, %%xmm0 \n"
375 "pxor %%xmm0, %%xmm2 \n"
376 "pslldq $4, %%xmm0 \n"
377 "pxor %%xmm2, %%xmm0 \n"
378 "add $16, %0 \n"
379 "movdqu %%xmm0, (%0) \n"
380
381 /* Set xmm2 to stuff:Y:stuff:stuff with Y = subword( r11 )
382 * and proceed to generate next round key from there */
383 "aeskeygenassist $0, %%xmm0, %%xmm2\n"
384 "pshufd $0xaa, %%xmm2, %%xmm2 \n"
385 "pxor %%xmm1, %%xmm2 \n"
386 "pslldq $4, %%xmm1 \n"
387 "pxor %%xmm1, %%xmm2 \n"
388 "pslldq $4, %%xmm1 \n"
389 "pxor %%xmm1, %%xmm2 \n"
390 "pslldq $4, %%xmm1 \n"
391 "pxor %%xmm2, %%xmm1 \n"
392 "add $16, %0 \n"
393 "movdqu %%xmm1, (%0) \n"
394 "ret \n"
395
396 /*
397 * Main "loop" - Generating one more key than necessary,
398 * see definition of aes_context.buf
399 */
400 "2: \n"
401 "aeskeygenassist $0x01, %%xmm1, %%xmm2 \ncall 1b \n"
402 "aeskeygenassist $0x02, %%xmm1, %%xmm2 \ncall 1b \n"
403 "aeskeygenassist $0x04, %%xmm1, %%xmm2 \ncall 1b \n"
404 "aeskeygenassist $0x08, %%xmm1, %%xmm2 \ncall 1b \n"
405 "aeskeygenassist $0x10, %%xmm1, %%xmm2 \ncall 1b \n"
406 "aeskeygenassist $0x20, %%xmm1, %%xmm2 \ncall 1b \n"
407 "aeskeygenassist $0x40, %%xmm1, %%xmm2 \ncall 1b \n"
408 :
409 : "r" (rk), "r" (key)
410 : "memory", "cc", "0" );
411}
412
413/*
Manuel Pégourié-Gonnard47a35362013-12-28 20:45:04 +0100414 * Key expansion, wrapper
415 */
416int aesni_setkey_enc( unsigned char *rk,
417 const unsigned char *key,
418 size_t bits )
419{
420 switch( bits )
421 {
422 case 128: aesni_setkey_enc_128( rk, key ); break;
Manuel Pégourié-Gonnard23c2f6f2013-12-29 16:05:22 +0100423 case 192: aesni_setkey_enc_192( rk, key ); break;
Manuel Pégourié-Gonnard4a5b9952013-12-29 13:50:32 +0100424 case 256: aesni_setkey_enc_256( rk, key ); break;
Manuel Pégourié-Gonnard47a35362013-12-28 20:45:04 +0100425 default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH );
426 }
427
428 return( 0 );
429}
430
Manuel Pégourié-Gonnard92ac76f2013-12-16 17:12:53 +0100431#endif /* POLARSSL_HAVE_X86_64 */
432
433#endif /* POLARSSL_AESNI_C */