1bf74da6bf524b4ae2c297d966e8c81080d5964e
[libgcrypt.git] / cipher / rijndael-armv8-ce.c
1 /* ARMv8 Crypto Extension AES for Libgcrypt
2  * Copyright (C) 2016 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h> /* for memcmp() */
25
26 #include "types.h"  /* for byte and u32 typedefs */
27 #include "g10lib.h"
28 #include "cipher.h"
29 #include "bufhelp.h"
30 #include "cipher-selftest.h"
31 #include "rijndael-internal.h"
32 #include "./cipher-internal.h"
33
34
35 #ifdef USE_ARM_CE
36
37
38 typedef struct u128_s { u32 a, b, c, d; } u128_t;
39
40 extern u32 _gcry_aes_sbox4_armv8_ce(u32 in4b);
41 extern void _gcry_aes_invmixcol_armv8_ce(u128_t *dst, const u128_t *src);
42
43 extern unsigned int _gcry_aes_enc_armv8_ce(const void *keysched, byte *dst,
44                                            const byte *src,
45                                            unsigned int nrounds);
46 extern unsigned int _gcry_aes_dec_armv8_ce(const void *keysched, byte *dst,
47                                            const byte *src,
48                                            unsigned int nrounds);
49
50 extern void _gcry_aes_cbc_enc_armv8_ce (const void *keysched,
51                                         unsigned char *outbuf,
52                                         const unsigned char *inbuf,
53                                         unsigned char *iv, size_t nblocks,
54                                         int cbc_mac, unsigned int nrounds);
55 extern void _gcry_aes_cbc_dec_armv8_ce (const void *keysched,
56                                         unsigned char *outbuf,
57                                         const unsigned char *inbuf,
58                                         unsigned char *iv, size_t nblocks,
59                                         unsigned int nrounds);
60
61 extern void _gcry_aes_cfb_enc_armv8_ce (const void *keysched,
62                                         unsigned char *outbuf,
63                                         const unsigned char *inbuf,
64                                         unsigned char *iv, size_t nblocks,
65                                         unsigned int nrounds);
66 extern void _gcry_aes_cfb_dec_armv8_ce (const void *keysched,
67                                         unsigned char *outbuf,
68                                         const unsigned char *inbuf,
69                                         unsigned char *iv, size_t nblocks,
70                                         unsigned int nrounds);
71
72 extern void _gcry_aes_ctr_enc_armv8_ce (const void *keysched,
73                                         unsigned char *outbuf,
74                                         const unsigned char *inbuf,
75                                         unsigned char *iv, size_t nblocks,
76                                         unsigned int nrounds);
77
78 extern void _gcry_aes_ocb_enc_armv8_ce (const void *keysched,
79                                         unsigned char *outbuf,
80                                         const unsigned char *inbuf,
81                                         unsigned char *offset,
82                                         unsigned char *checksum,
83                                         void **Ls,
84                                         size_t nblocks,
85                                         unsigned int nrounds);
86 extern void _gcry_aes_ocb_dec_armv8_ce (const void *keysched,
87                                         unsigned char *outbuf,
88                                         const unsigned char *inbuf,
89                                         unsigned char *offset,
90                                         unsigned char *checksum,
91                                         void **Ls,
92                                         size_t nblocks,
93                                         unsigned int nrounds);
94 extern void _gcry_aes_ocb_auth_armv8_ce (const void *keysched,
95                                          const unsigned char *abuf,
96                                          unsigned char *offset,
97                                          unsigned char *checksum,
98                                          void **Ls,
99                                          size_t nblocks,
100                                          unsigned int nrounds);
101
102 typedef void (*ocb_crypt_fn_t) (const void *keysched, unsigned char *outbuf,
103                                 const unsigned char *inbuf,
104                                 unsigned char *offset, unsigned char *checksum,
105                                 void **Ls, size_t nblocks,
106                                 unsigned int nrounds);
107
108 void
109 _gcry_aes_armv8_ce_setkey (RIJNDAEL_context *ctx, const byte *key)
110 {
111   union
112     {
113       PROPERLY_ALIGNED_TYPE dummy;
114       byte data[MAXKC][4];
115       u32 data32[MAXKC];
116     } tkk[2];
117   unsigned int rounds = ctx->rounds;
118   int KC = rounds - 6;
119   unsigned int keylen = KC * 4;
120   unsigned int i, r, t;
121   byte rcon = 1;
122   int j;
123 #define k      tkk[0].data
124 #define k_u32  tkk[0].data32
125 #define tk     tkk[1].data
126 #define tk_u32 tkk[1].data32
127 #define W      (ctx->keyschenc)
128 #define W_u32  (ctx->keyschenc32)
129
130   for (i = 0; i < keylen; i++)
131     {
132       k[i >> 2][i & 3] = key[i];
133     }
134
135   for (j = KC-1; j >= 0; j--)
136     {
137       tk_u32[j] = k_u32[j];
138     }
139   r = 0;
140   t = 0;
141   /* Copy values into round key array.  */
142   for (j = 0; (j < KC) && (r < rounds + 1); )
143     {
144       for (; (j < KC) && (t < 4); j++, t++)
145         {
146           W_u32[r][t] = le_bswap32(tk_u32[j]);
147         }
148       if (t == 4)
149         {
150           r++;
151           t = 0;
152         }
153     }
154
155   while (r < rounds + 1)
156     {
157       tk_u32[0] ^= _gcry_aes_sbox4_armv8_ce(rol(tk_u32[KC - 1], 24)) ^ rcon;
158
159       if (KC != 8)
160         {
161           for (j = 1; j < KC; j++)
162             {
163               tk_u32[j] ^= tk_u32[j-1];
164             }
165         }
166       else
167         {
168           for (j = 1; j < KC/2; j++)
169             {
170               tk_u32[j] ^= tk_u32[j-1];
171             }
172
173           tk_u32[KC/2] ^= _gcry_aes_sbox4_armv8_ce(tk_u32[KC/2 - 1]);
174
175           for (j = KC/2 + 1; j < KC; j++)
176             {
177               tk_u32[j] ^= tk_u32[j-1];
178             }
179         }
180
181       /* Copy values into round key array.  */
182       for (j = 0; (j < KC) && (r < rounds + 1); )
183         {
184           for (; (j < KC) && (t < 4); j++, t++)
185             {
186               W_u32[r][t] = le_bswap32(tk_u32[j]);
187             }
188           if (t == 4)
189             {
190               r++;
191               t = 0;
192             }
193         }
194
195       rcon = (rcon << 1) ^ ((rcon >> 7) * 0x1b);
196     }
197
198 #undef W
199 #undef tk
200 #undef k
201 #undef W_u32
202 #undef tk_u32
203 #undef k_u32
204   wipememory(&tkk, sizeof(tkk));
205 }
206
207 /* Make a decryption key from an encryption key. */
208 void
209 _gcry_aes_armv8_ce_prepare_decryption (RIJNDAEL_context *ctx)
210 {
211   u128_t *ekey = (u128_t *)(void *)ctx->keyschenc;
212   u128_t *dkey = (u128_t *)(void *)ctx->keyschdec;
213   int rounds = ctx->rounds;
214   int rr;
215   int r;
216
217 #define DO_AESIMC() _gcry_aes_invmixcol_armv8_ce(&dkey[r], &ekey[rr])
218
219   dkey[0] = ekey[rounds];
220   r = 1;
221   rr = rounds-1;
222   DO_AESIMC(); r++; rr--; /* round 1 */
223   DO_AESIMC(); r++; rr--; /* round 2 */
224   DO_AESIMC(); r++; rr--; /* round 3 */
225   DO_AESIMC(); r++; rr--; /* round 4 */
226   DO_AESIMC(); r++; rr--; /* round 5 */
227   DO_AESIMC(); r++; rr--; /* round 6 */
228   DO_AESIMC(); r++; rr--; /* round 7 */
229   DO_AESIMC(); r++; rr--; /* round 8 */
230   DO_AESIMC(); r++; rr--; /* round 9 */
231   if (rounds >= 12)
232     {
233       if (rounds > 12)
234         {
235           DO_AESIMC(); r++; rr--; /* round 10 */
236           DO_AESIMC(); r++; rr--; /* round 11 */
237         }
238
239       DO_AESIMC(); r++; rr--; /* round 12 / 10 */
240       DO_AESIMC(); r++; rr--; /* round 13 / 11 */
241     }
242
243   dkey[r] = ekey[0];
244
245 #undef DO_AESIMC
246 }
247
248 unsigned int
249 _gcry_aes_armv8_ce_encrypt (const RIJNDAEL_context *ctx, unsigned char *dst,
250                             const unsigned char *src)
251 {
252   const void *keysched = ctx->keyschenc32;
253   unsigned int nrounds = ctx->rounds;
254
255   return _gcry_aes_enc_armv8_ce(keysched, dst, src, nrounds);
256 }
257
258 unsigned int
259 _gcry_aes_armv8_ce_decrypt (const RIJNDAEL_context *ctx, unsigned char *dst,
260                             const unsigned char *src)
261 {
262   const void *keysched = ctx->keyschdec32;
263   unsigned int nrounds = ctx->rounds;
264
265   return _gcry_aes_dec_armv8_ce(keysched, dst, src, nrounds);
266 }
267
268 void
269 _gcry_aes_armv8_ce_cbc_enc (const RIJNDAEL_context *ctx, unsigned char *outbuf,
270                             const unsigned char *inbuf, unsigned char *iv,
271                             size_t nblocks, int cbc_mac)
272 {
273   const void *keysched = ctx->keyschenc32;
274   unsigned int nrounds = ctx->rounds;
275
276   _gcry_aes_cbc_enc_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, cbc_mac,
277                              nrounds);
278 }
279
280 void
281 _gcry_aes_armv8_ce_cbc_dec (RIJNDAEL_context *ctx, unsigned char *outbuf,
282                             const unsigned char *inbuf, unsigned char *iv,
283                             size_t nblocks)
284 {
285   const void *keysched = ctx->keyschdec32;
286   unsigned int nrounds = ctx->rounds;
287
288   _gcry_aes_cbc_dec_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, nrounds);
289 }
290
291 void
292 _gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
293                             const unsigned char *inbuf, unsigned char *iv,
294                             size_t nblocks)
295 {
296   const void *keysched = ctx->keyschenc32;
297   unsigned int nrounds = ctx->rounds;
298
299   _gcry_aes_cfb_enc_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, nrounds);
300 }
301
302 void
303 _gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_context *ctx, unsigned char *outbuf,
304                             const unsigned char *inbuf, unsigned char *iv,
305                             size_t nblocks)
306 {
307   const void *keysched = ctx->keyschenc32;
308   unsigned int nrounds = ctx->rounds;
309
310   _gcry_aes_cfb_dec_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, nrounds);
311 }
312
313 void
314 _gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
315                             const unsigned char *inbuf, unsigned char *iv,
316                             size_t nblocks)
317 {
318   const void *keysched = ctx->keyschenc32;
319   unsigned int nrounds = ctx->rounds;
320
321   _gcry_aes_ctr_enc_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, nrounds);
322 }
323
324 void
325 _gcry_aes_armv8_ce_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
326                               const void *inbuf_arg, size_t nblocks,
327                               int encrypt)
328 {
329   RIJNDAEL_context *ctx = (void *)&c->context.c;
330   const void *keysched = encrypt ? ctx->keyschenc32 : ctx->keyschdec32;
331   ocb_crypt_fn_t crypt_fn = encrypt ? _gcry_aes_ocb_enc_armv8_ce
332                                     : _gcry_aes_ocb_dec_armv8_ce;
333   unsigned char *outbuf = outbuf_arg;
334   const unsigned char *inbuf = inbuf_arg;
335   unsigned int nrounds = ctx->rounds;
336   u64 blkn = c->u_mode.ocb.data_nblocks;
337   u64 blkn_offs = blkn - blkn % 32;
338   unsigned int n = 32 - blkn % 32;
339   void *Ls[32];
340   void **l;
341   size_t i;
342
343   c->u_mode.ocb.data_nblocks = blkn + nblocks;
344
345   if (nblocks >= 32)
346     {
347       for (i = 0; i < 32; i += 8)
348         {
349           Ls[(i + 0 + n) % 32] = (void *)c->u_mode.ocb.L[0];
350           Ls[(i + 1 + n) % 32] = (void *)c->u_mode.ocb.L[1];
351           Ls[(i + 2 + n) % 32] = (void *)c->u_mode.ocb.L[0];
352           Ls[(i + 3 + n) % 32] = (void *)c->u_mode.ocb.L[2];
353           Ls[(i + 4 + n) % 32] = (void *)c->u_mode.ocb.L[0];
354           Ls[(i + 5 + n) % 32] = (void *)c->u_mode.ocb.L[1];
355           Ls[(i + 6 + n) % 32] = (void *)c->u_mode.ocb.L[0];
356         }
357
358       Ls[(7 + n) % 32] = (void *)c->u_mode.ocb.L[3];
359       Ls[(15 + n) % 32] = (void *)c->u_mode.ocb.L[4];
360       Ls[(23 + n) % 32] = (void *)c->u_mode.ocb.L[3];
361       l = &Ls[(31 + n) % 32];
362
363       /* Process data in 32 block chunks. */
364       while (nblocks >= 32)
365         {
366           blkn_offs += 32;
367           *l = (void *)ocb_get_l(c, blkn_offs);
368
369           crypt_fn(keysched, outbuf, inbuf, c->u_iv.iv, c->u_ctr.ctr, Ls, 32,
370                     nrounds);
371
372           nblocks -= 32;
373           outbuf += 32 * 16;
374           inbuf  += 32 * 16;
375         }
376
377       if (nblocks && l < &Ls[nblocks])
378         {
379           *l = (void *)ocb_get_l(c, 32 + blkn_offs);
380         }
381     }
382   else
383     {
384       for (i = 0; i < nblocks; i++)
385         Ls[i] = (void *)ocb_get_l(c, ++blkn);
386     }
387
388   if (nblocks)
389     {
390       crypt_fn(keysched, outbuf, inbuf, c->u_iv.iv, c->u_ctr.ctr, Ls, nblocks,
391                nrounds);
392     }
393 }
394
395 void
396 _gcry_aes_armv8_ce_ocb_auth (gcry_cipher_hd_t c, void *abuf_arg,
397                              size_t nblocks)
398 {
399   RIJNDAEL_context *ctx = (void *)&c->context.c;
400   const void *keysched = ctx->keyschenc32;
401   const unsigned char *abuf = abuf_arg;
402   unsigned int nrounds = ctx->rounds;
403   u64 blkn = c->u_mode.ocb.aad_nblocks;
404   u64 blkn_offs = blkn - blkn % 32;
405   unsigned int n = 32 - blkn % 32;
406   void *Ls[32];
407   void **l;
408   size_t i;
409
410   c->u_mode.ocb.aad_nblocks = blkn + nblocks;
411
412   if (nblocks >= 32)
413     {
414       for (i = 0; i < 32; i += 8)
415         {
416           Ls[(i + 0 + n) % 32] = (void *)c->u_mode.ocb.L[0];
417           Ls[(i + 1 + n) % 32] = (void *)c->u_mode.ocb.L[1];
418           Ls[(i + 2 + n) % 32] = (void *)c->u_mode.ocb.L[0];
419           Ls[(i + 3 + n) % 32] = (void *)c->u_mode.ocb.L[2];
420           Ls[(i + 4 + n) % 32] = (void *)c->u_mode.ocb.L[0];
421           Ls[(i + 5 + n) % 32] = (void *)c->u_mode.ocb.L[1];
422           Ls[(i + 6 + n) % 32] = (void *)c->u_mode.ocb.L[0];
423         }
424
425       Ls[(7 + n) % 32] = (void *)c->u_mode.ocb.L[3];
426       Ls[(15 + n) % 32] = (void *)c->u_mode.ocb.L[4];
427       Ls[(23 + n) % 32] = (void *)c->u_mode.ocb.L[3];
428       l = &Ls[(31 + n) % 32];
429
430       /* Process data in 32 block chunks. */
431       while (nblocks >= 32)
432         {
433           blkn_offs += 32;
434           *l = (void *)ocb_get_l(c, blkn_offs);
435
436           _gcry_aes_ocb_auth_armv8_ce(keysched, abuf, c->u_mode.ocb.aad_offset,
437                                       c->u_mode.ocb.aad_sum, Ls, 32, nrounds);
438
439           nblocks -= 32;
440           abuf += 32 * 16;
441         }
442
443       if (nblocks && l < &Ls[nblocks])
444         {
445           *l = (void *)ocb_get_l(c, 32 + blkn_offs);
446         }
447     }
448   else
449     {
450       for (i = 0; i < nblocks; i++)
451         Ls[i] = (void *)ocb_get_l(c, ++blkn);
452     }
453
454   if (nblocks)
455     {
456       _gcry_aes_ocb_auth_armv8_ce(keysched, abuf, c->u_mode.ocb.aad_offset,
457                                   c->u_mode.ocb.aad_sum, Ls, nblocks, nrounds);
458     }
459 }
460
461 #endif /* USE_ARM_CE */