f2dec6293597fe60ba6613d6da7aeb375daae3ac
[vpp.git] / src / plugins / crypto_native / aes_gcm.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2019 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <vlib/vlib.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vnet/crypto/crypto.h>
21 #include <x86intrin.h>
22 #include <crypto_native/crypto_native.h>
23 #include <crypto_native/aes.h>
24 #include <crypto_native/ghash.h>
25
26 #if __GNUC__ > 4  && !__clang__ && CLIB_DEBUG == 0
27 #pragma GCC optimize ("O3")
28 #endif
29
30 typedef struct
31 {
32   /* pre-calculated hash key values */
33   const u8x16 Hi[8];
34   /* extracted AES key */
35   const u8x16 Ke[15];
36 } aes_gcm_key_data_t;
37
38 static const u32x4 last_byte_one = { 0, 0, 0, 1 << 24 };
39
40 static const u8x16 bswap_mask = {
41   15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
42 };
43
44 static_always_inline u8x16
45 aesni_gcm_bswap (u8x16 x)
46 {
47   return (u8x16) _mm_shuffle_epi8 ((__m128i) x, (__m128i) bswap_mask);
48 }
49
50 static_always_inline void
51 aesni_gcm_load (u8x16 * d, u8x16u * inv, int n, int n_bytes)
52 {
53   for (int i = 0; i < n - 1; i++)
54     d[i] = inv[i];
55   d[n - 1] = n_bytes ? aes_load_partial (inv + n - 1, n_bytes) : inv[n - 1];
56 }
57
58 static_always_inline void
59 aesni_gcm_store (u8x16 * d, u8x16u * outv, int n, int n_bytes)
60 {
61   for (int i = 0; i < n - 1; i++)
62     outv[i] = d[i];
63   if (n_bytes & 0xf)
64     aes_store_partial (outv + n - 1, d[n - 1], n_bytes);
65   else
66     outv[n - 1] = d[n - 1];
67 }
68
69 static_always_inline void
70 aesni_gcm_enc_first_round (u8x16 * r, u32x4 * Y, u32 * ctr, u8x16 k,
71                            int n_blocks)
72 {
73   if (PREDICT_TRUE ((u8) ctr[0] < (256 - n_blocks)))
74     {
75       for (int i = 0; i < n_blocks; i++)
76         {
77           Y[0] += last_byte_one;
78           r[i] = k ^ (u8x16) Y[0];
79         }
80       ctr[0] += n_blocks;
81     }
82   else
83     {
84       for (int i = 0; i < n_blocks; i++)
85         {
86           Y[0][3] = clib_host_to_net_u32 (++ctr[0]);
87           r[i] = k ^ (u8x16) Y[0];
88         }
89     }
90 }
91
92 static_always_inline void
93 aesni_gcm_enc_round (u8x16 * r, u8x16 k, int n_blocks)
94 {
95   for (int i = 0; i < n_blocks; i++)
96     r[i] = aes_enc_round (r[i], k);
97 }
98
99 static_always_inline void
100 aesni_gcm_enc_last_round (u8x16 * r, u8x16 * d, u8x16 const *k,
101                           int rounds, int n_blocks)
102 {
103
104   /* additional ronuds for AES-192 and AES-256 */
105   for (int i = 10; i < rounds; i++)
106     aesni_gcm_enc_round (r, k[i], n_blocks);
107
108   for (int i = 0; i < n_blocks; i++)
109     d[i] ^= aes_enc_last_round (r[i], k[rounds]);
110 }
111
112 static_always_inline u8x16
113 aesni_gcm_ghash_blocks (u8x16 T, aes_gcm_key_data_t * kd,
114                         u8x16u * in, int n_blocks)
115 {
116   ghash_data_t _gd, *gd = &_gd;
117   const u8x16 *Hi = kd->Hi + n_blocks - 1;
118   ghash_mul_first (gd, aesni_gcm_bswap (in[0]) ^ T, Hi[0]);
119   for (int i = 1; i < n_blocks; i++)
120     ghash_mul_next (gd, aesni_gcm_bswap ((in[i])), Hi[-i]);
121   ghash_reduce (gd);
122   ghash_reduce2 (gd);
123   return ghash_final (gd);
124 }
125
126 static_always_inline u8x16
127 aesni_gcm_ghash (u8x16 T, aes_gcm_key_data_t * kd, u8x16u * in, u32 n_left)
128 {
129
130   while (n_left >= 128)
131     {
132       T = aesni_gcm_ghash_blocks (T, kd, in, 8);
133       n_left -= 128;
134       in += 8;
135     }
136
137   if (n_left >= 64)
138     {
139       T = aesni_gcm_ghash_blocks (T, kd, in, 4);
140       n_left -= 64;
141       in += 4;
142     }
143
144   if (n_left >= 32)
145     {
146       T = aesni_gcm_ghash_blocks (T, kd, in, 2);
147       n_left -= 32;
148       in += 2;
149     }
150
151   if (n_left >= 16)
152     {
153       T = aesni_gcm_ghash_blocks (T, kd, in, 1);
154       n_left -= 16;
155       in += 1;
156     }
157
158   if (n_left)
159     {
160       u8x16 r = aes_load_partial (in, n_left);
161       T = ghash_mul (aesni_gcm_bswap (r) ^ T, kd->Hi[0]);
162     }
163   return T;
164 }
165
166 static_always_inline u8x16
167 aesni_gcm_calc (u8x16 T, aes_gcm_key_data_t * kd, u8x16 * d,
168                 u32x4 * Y, u32 * ctr, u8x16u * inv, u8x16u * outv,
169                 int rounds, int n, int last_block_bytes, int with_ghash,
170                 int is_encrypt)
171 {
172   u8x16 r[n];
173   ghash_data_t _gd = { }, *gd = &_gd;
174   const u8x16 *rk = (u8x16 *) kd->Ke;
175   int hidx = is_encrypt ? 4 : n, didx = 0;
176
177   _mm_prefetch (inv + 4, _MM_HINT_T0);
178
179   /* AES rounds 0 and 1 */
180   aesni_gcm_enc_first_round (r, Y, ctr, rk[0], n);
181   aesni_gcm_enc_round (r, rk[1], n);
182
183   /* load data - decrypt round */
184   if (is_encrypt == 0)
185     aesni_gcm_load (d, inv, n, last_block_bytes);
186
187   /* GHASH multiply block 1 */
188   if (with_ghash)
189     ghash_mul_first (gd, aesni_gcm_bswap (d[didx++]) ^ T, kd->Hi[--hidx]);
190
191   /* AES rounds 2 and 3 */
192   aesni_gcm_enc_round (r, rk[2], n);
193   aesni_gcm_enc_round (r, rk[3], n);
194
195   /* GHASH multiply block 2 */
196   if (with_ghash && hidx)
197     ghash_mul_next (gd, aesni_gcm_bswap (d[didx++]), kd->Hi[--hidx]);
198
199   /* AES rounds 4 and 5 */
200   aesni_gcm_enc_round (r, rk[4], n);
201   aesni_gcm_enc_round (r, rk[5], n);
202
203   /* GHASH multiply block 3 */
204   if (with_ghash && hidx)
205     ghash_mul_next (gd, aesni_gcm_bswap (d[didx++]), kd->Hi[--hidx]);
206
207   /* AES rounds 6 and 7 */
208   aesni_gcm_enc_round (r, rk[6], n);
209   aesni_gcm_enc_round (r, rk[7], n);
210
211   /* GHASH multiply block 4 */
212   if (with_ghash && hidx)
213     ghash_mul_next (gd, aesni_gcm_bswap (d[didx++]), kd->Hi[--hidx]);
214
215   /* AES rounds 8 and 9 */
216   aesni_gcm_enc_round (r, rk[8], n);
217   aesni_gcm_enc_round (r, rk[9], n);
218
219   /* GHASH reduce 1st step */
220   if (with_ghash)
221     ghash_reduce (gd);
222
223   /* load data - encrypt round */
224   if (is_encrypt)
225     aesni_gcm_load (d, inv, n, last_block_bytes);
226
227   /* GHASH reduce 2nd step */
228   if (with_ghash)
229     ghash_reduce2 (gd);
230
231   /* AES last round(s) */
232   aesni_gcm_enc_last_round (r, d, rk, rounds, n);
233
234   /* store data */
235   aesni_gcm_store (d, outv, n, last_block_bytes);
236
237   /* GHASH final step */
238   if (with_ghash)
239     T = ghash_final (gd);
240
241   return T;
242 }
243
244 static_always_inline u8x16
245 aesni_gcm_calc_double (u8x16 T, aes_gcm_key_data_t * kd, u8x16 * d,
246                        u32x4 * Y, u32 * ctr, u8x16u * inv, u8x16u * outv,
247                        int rounds, int is_encrypt)
248 {
249   u8x16 r[4];
250   ghash_data_t _gd, *gd = &_gd;
251   const u8x16 *rk = (u8x16 *) kd->Ke;
252
253   /* AES rounds 0 and 1 */
254   aesni_gcm_enc_first_round (r, Y, ctr, rk[0], 4);
255   aesni_gcm_enc_round (r, rk[1], 4);
256
257   /* load 4 blocks of data - decrypt round */
258   if (is_encrypt == 0)
259     aesni_gcm_load (d, inv, 4, 0);
260
261   /* GHASH multiply block 0 */
262   ghash_mul_first (gd, aesni_gcm_bswap (d[0]) ^ T, kd->Hi[7]);
263
264   /* AES rounds 2 and 3 */
265   aesni_gcm_enc_round (r, rk[2], 4);
266   aesni_gcm_enc_round (r, rk[3], 4);
267
268   /* GHASH multiply block 1 */
269   ghash_mul_next (gd, aesni_gcm_bswap (d[1]), kd->Hi[6]);
270
271   /* AES rounds 4 and 5 */
272   aesni_gcm_enc_round (r, rk[4], 4);
273   aesni_gcm_enc_round (r, rk[5], 4);
274
275   /* GHASH multiply block 2 */
276   ghash_mul_next (gd, aesni_gcm_bswap (d[2]), kd->Hi[5]);
277
278   /* AES rounds 6 and 7 */
279   aesni_gcm_enc_round (r, rk[6], 4);
280   aesni_gcm_enc_round (r, rk[7], 4);
281
282   /* GHASH multiply block 3 */
283   ghash_mul_next (gd, aesni_gcm_bswap (d[3]), kd->Hi[4]);
284
285   /* AES rounds 8 and 9 */
286   aesni_gcm_enc_round (r, rk[8], 4);
287   aesni_gcm_enc_round (r, rk[9], 4);
288
289   /* load 4 blocks of data - encrypt round */
290   if (is_encrypt)
291     aesni_gcm_load (d, inv, 4, 0);
292
293   /* AES last round(s) */
294   aesni_gcm_enc_last_round (r, d, rk, rounds, 4);
295
296   /* store 4 blocks of data */
297   aesni_gcm_store (d, outv, 4, 0);
298
299   /* load next 4 blocks of data data - decrypt round */
300   if (is_encrypt == 0)
301     aesni_gcm_load (d, inv + 4, 4, 0);
302
303   /* GHASH multiply block 4 */
304   ghash_mul_next (gd, aesni_gcm_bswap (d[0]), kd->Hi[3]);
305
306   /* AES rounds 0, 1 and 2 */
307   aesni_gcm_enc_first_round (r, Y, ctr, rk[0], 4);
308   aesni_gcm_enc_round (r, rk[1], 4);
309   aesni_gcm_enc_round (r, rk[2], 4);
310
311   /* GHASH multiply block 5 */
312   ghash_mul_next (gd, aesni_gcm_bswap (d[1]), kd->Hi[2]);
313
314   /* AES rounds 3 and 4 */
315   aesni_gcm_enc_round (r, rk[3], 4);
316   aesni_gcm_enc_round (r, rk[4], 4);
317
318   /* GHASH multiply block 6 */
319   ghash_mul_next (gd, aesni_gcm_bswap (d[2]), kd->Hi[1]);
320
321   /* AES rounds 5 and 6 */
322   aesni_gcm_enc_round (r, rk[5], 4);
323   aesni_gcm_enc_round (r, rk[6], 4);
324
325   /* GHASH multiply block 7 */
326   ghash_mul_next (gd, aesni_gcm_bswap (d[3]), kd->Hi[0]);
327
328   /* AES rounds 7 and 8 */
329   aesni_gcm_enc_round (r, rk[7], 4);
330   aesni_gcm_enc_round (r, rk[8], 4);
331
332   /* GHASH reduce 1st step */
333   ghash_reduce (gd);
334
335   /* AES round 9 */
336   aesni_gcm_enc_round (r, rk[9], 4);
337
338   /* load data - encrypt round */
339   if (is_encrypt)
340     aesni_gcm_load (d, inv + 4, 4, 0);
341
342   /* GHASH reduce 2nd step */
343   ghash_reduce2 (gd);
344
345   /* AES last round(s) */
346   aesni_gcm_enc_last_round (r, d, rk, rounds, 4);
347
348   /* store data */
349   aesni_gcm_store (d, outv + 4, 4, 0);
350
351   /* GHASH final step */
352   return ghash_final (gd);
353 }
354
355 static_always_inline u8x16
356 aesni_gcm_ghash_last (u8x16 T, aes_gcm_key_data_t * kd, u8x16 * d,
357                       int n_blocks, int n_bytes)
358 {
359   ghash_data_t _gd, *gd = &_gd;
360
361   if (n_bytes)
362     d[n_blocks - 1] = aes_byte_mask (d[n_blocks - 1], n_bytes);
363
364   ghash_mul_first (gd, aesni_gcm_bswap (d[0]) ^ T, kd->Hi[n_blocks - 1]);
365   if (n_blocks > 1)
366     ghash_mul_next (gd, aesni_gcm_bswap (d[1]), kd->Hi[n_blocks - 2]);
367   if (n_blocks > 2)
368     ghash_mul_next (gd, aesni_gcm_bswap (d[2]), kd->Hi[n_blocks - 3]);
369   if (n_blocks > 3)
370     ghash_mul_next (gd, aesni_gcm_bswap (d[3]), kd->Hi[n_blocks - 4]);
371   ghash_reduce (gd);
372   ghash_reduce2 (gd);
373   return ghash_final (gd);
374 }
375
376
377 static_always_inline u8x16
378 aesni_gcm_enc (u8x16 T, aes_gcm_key_data_t * kd, u32x4 Y, u8x16u * inv,
379                u8x16u * outv, u32 n_left, int rounds)
380 {
381   u8x16 d[4];
382   u32 ctr = 1;
383
384   if (n_left == 0)
385     return T;
386
387   if (n_left < 64)
388     {
389       if (n_left > 48)
390         {
391           n_left &= 0x0f;
392           aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 4, n_left,
393                           /* with_ghash */ 0, /* is_encrypt */ 1);
394           return aesni_gcm_ghash_last (T, kd, d, 4, n_left);
395         }
396       else if (n_left > 32)
397         {
398           n_left &= 0x0f;
399           aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 3, n_left,
400                           /* with_ghash */ 0, /* is_encrypt */ 1);
401           return aesni_gcm_ghash_last (T, kd, d, 3, n_left);
402         }
403       else if (n_left > 16)
404         {
405           n_left &= 0x0f;
406           aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 2, n_left,
407                           /* with_ghash */ 0, /* is_encrypt */ 1);
408           return aesni_gcm_ghash_last (T, kd, d, 2, n_left);
409         }
410       else
411         {
412           n_left &= 0x0f;
413           aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 1, n_left,
414                           /* with_ghash */ 0, /* is_encrypt */ 1);
415           return aesni_gcm_ghash_last (T, kd, d, 1, n_left);
416         }
417     }
418
419   aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 4, 0,
420                   /* with_ghash */ 0, /* is_encrypt */ 1);
421
422   /* next */
423   n_left -= 64;
424   outv += 4;
425   inv += 4;
426
427   while (n_left >= 128)
428     {
429       T = aesni_gcm_calc_double (T, kd, d, &Y, &ctr, inv, outv, rounds,
430                                  /* is_encrypt */ 1);
431
432       /* next */
433       n_left -= 128;
434       outv += 8;
435       inv += 8;
436     }
437
438   if (n_left >= 64)
439     {
440       T = aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 4, 0,
441                           /* with_ghash */ 1, /* is_encrypt */ 1);
442
443       /* next */
444       n_left -= 64;
445       outv += 4;
446       inv += 4;
447     }
448
449   if (n_left == 0)
450     return aesni_gcm_ghash_last (T, kd, d, 4, 0);
451
452   if (n_left > 48)
453     {
454       n_left &= 0x0f;
455       T = aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 4, n_left,
456                           /* with_ghash */ 1, /* is_encrypt */ 1);
457       return aesni_gcm_ghash_last (T, kd, d, 4, n_left);
458     }
459
460   if (n_left > 32)
461     {
462       n_left &= 0x0f;
463       T = aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 3, n_left,
464                           /* with_ghash */ 1, /* is_encrypt */ 1);
465       return aesni_gcm_ghash_last (T, kd, d, 3, n_left);
466     }
467
468   if (n_left > 16)
469     {
470       n_left &= 0x0f;
471       T = aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 2, n_left,
472                           /* with_ghash */ 1, /* is_encrypt */ 1);
473       return aesni_gcm_ghash_last (T, kd, d, 2, n_left);
474     }
475
476   n_left &= 0x0f;
477   T = aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 1, n_left,
478                       /* with_ghash */ 1, /* is_encrypt */ 1);
479   return aesni_gcm_ghash_last (T, kd, d, 1, n_left);
480 }
481
482 static_always_inline u8x16
483 aesni_gcm_dec (u8x16 T, aes_gcm_key_data_t * kd, u32x4 Y, u8x16u * inv,
484                u8x16u * outv, u32 n_left, int rounds)
485 {
486   u8x16 d[8];
487   u32 ctr = 1;
488
489   while (n_left >= 128)
490     {
491       T = aesni_gcm_calc_double (T, kd, d, &Y, &ctr, inv, outv, rounds,
492                                  /* is_encrypt */ 0);
493
494       /* next */
495       n_left -= 128;
496       outv += 8;
497       inv += 8;
498     }
499
500   if (n_left >= 64)
501     {
502       T = aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 4, 0, 1, 0);
503
504       /* next */
505       n_left -= 64;
506       outv += 4;
507       inv += 4;
508     }
509
510   if (n_left == 0)
511     return T;
512
513   if (n_left > 48)
514     return aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 4,
515                            n_left - 48,
516                            /* with_ghash */ 1, /* is_encrypt */ 0);
517
518   if (n_left > 32)
519     return aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 3,
520                            n_left - 32,
521                            /* with_ghash */ 1, /* is_encrypt */ 0);
522
523   if (n_left > 16)
524     return aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 2,
525                            n_left - 16,
526                            /* with_ghash */ 1, /* is_encrypt */ 0);
527
528   return aesni_gcm_calc (T, kd, d, &Y, &ctr, inv, outv, rounds, 1, n_left,
529                          /* with_ghash */ 1, /* is_encrypt */ 0);
530 }
531
532 static_always_inline int
533 aes_gcm (u8x16u * in, u8x16u * out, u8x16u * addt, u8x16u * iv, u8x16u * tag,
534          u32 data_bytes, u32 aad_bytes, u8 tag_len, aes_gcm_key_data_t * kd,
535          int aes_rounds, int is_encrypt)
536 {
537   int i;
538   u8x16 r, T = { };
539   u32x4 Y0;
540   ghash_data_t _gd, *gd = &_gd;
541
542   _mm_prefetch (iv, _MM_HINT_T0);
543   _mm_prefetch (in, _MM_HINT_T0);
544   _mm_prefetch (in + CLIB_CACHE_LINE_BYTES, _MM_HINT_T0);
545
546   /* calculate ghash for AAD - optimized for ipsec common cases */
547   if (aad_bytes == 8)
548     T = aesni_gcm_ghash (T, kd, addt, 8);
549   else if (aad_bytes == 12)
550     T = aesni_gcm_ghash (T, kd, addt, 12);
551   else
552     T = aesni_gcm_ghash (T, kd, addt, aad_bytes);
553
554   /* initalize counter */
555   Y0 = (u32x4) aes_load_partial (iv, 12);
556   Y0[3] = clib_host_to_net_u32 (1);
557
558   /* ghash and encrypt/edcrypt  */
559   if (is_encrypt)
560     T = aesni_gcm_enc (T, kd, Y0, in, out, data_bytes, aes_rounds);
561   else
562     T = aesni_gcm_dec (T, kd, Y0, in, out, data_bytes, aes_rounds);
563
564   _mm_prefetch (tag, _MM_HINT_T0);
565
566   /* Finalize ghash  - data bytes and aad bytes converted to bits */
567   /* *INDENT-OFF* */
568   r = (u8x16) ((u64x2) {data_bytes, aad_bytes} << 3);
569   /* *INDENT-ON* */
570
571   /* interleaved computation of final ghash and E(Y0, k) */
572   ghash_mul_first (gd, r ^ T, kd->Hi[0]);
573   r = kd->Ke[0] ^ (u8x16) Y0;
574   for (i = 1; i < 5; i += 1)
575     r = aes_enc_round (r, kd->Ke[i]);
576   ghash_reduce (gd);
577   ghash_reduce2 (gd);
578   for (; i < 9; i += 1)
579     r = aes_enc_round (r, kd->Ke[i]);
580   T = ghash_final (gd);
581   for (; i < aes_rounds; i += 1)
582     r = aes_enc_round (r, kd->Ke[i]);
583   r = aes_enc_last_round (r, kd->Ke[aes_rounds]);
584   T = aesni_gcm_bswap (T) ^ r;
585
586   /* tag_len 16 -> 0 */
587   tag_len &= 0xf;
588
589   if (is_encrypt)
590     {
591       /* store tag */
592       if (tag_len)
593         aes_store_partial (tag, T, (1 << tag_len) - 1);
594       else
595         tag[0] = T;
596     }
597   else
598     {
599       /* check tag */
600       u16 tag_mask = tag_len ? (1 << tag_len) - 1 : 0xffff;
601       if ((u8x16_msb_mask (tag[0] == T) & tag_mask) != tag_mask)
602         return 0;
603     }
604   return 1;
605 }
606
607 static_always_inline u32
608 aesni_ops_enc_aes_gcm (vlib_main_t * vm, vnet_crypto_op_t * ops[],
609                        u32 n_ops, aes_key_size_t ks)
610 {
611   crypto_native_main_t *cm = &crypto_native_main;
612   vnet_crypto_op_t *op = ops[0];
613   aes_gcm_key_data_t *kd;
614   u32 n_left = n_ops;
615
616
617 next:
618   kd = (aes_gcm_key_data_t *) cm->key_data[op->key_index];
619   aes_gcm ((u8x16u *) op->src, (u8x16u *) op->dst, (u8x16u *) op->aad,
620            (u8x16u *) op->iv, (u8x16u *) op->tag, op->len, op->aad_len,
621            op->tag_len, kd, AES_KEY_ROUNDS (ks), /* is_encrypt */ 1);
622   op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
623
624   if (--n_left)
625     {
626       op += 1;
627       goto next;
628     }
629
630   return n_ops;
631 }
632
633 static_always_inline u32
634 aesni_ops_dec_aes_gcm (vlib_main_t * vm, vnet_crypto_op_t * ops[],
635                        u32 n_ops, aes_key_size_t ks)
636 {
637   crypto_native_main_t *cm = &crypto_native_main;
638   vnet_crypto_op_t *op = ops[0];
639   aes_gcm_key_data_t *kd;
640   u32 n_left = n_ops;
641   int rv;
642
643 next:
644   kd = (aes_gcm_key_data_t *) cm->key_data[op->key_index];
645   rv = aes_gcm ((u8x16u *) op->src, (u8x16u *) op->dst, (u8x16u *) op->aad,
646                 (u8x16u *) op->iv, (u8x16u *) op->tag, op->len,
647                 op->aad_len, op->tag_len, kd, AES_KEY_ROUNDS (ks),
648                 /* is_encrypt */ 0);
649
650   if (rv)
651     {
652       op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
653     }
654   else
655     {
656       op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC;
657       n_ops--;
658     }
659
660   if (--n_left)
661     {
662       op += 1;
663       goto next;
664     }
665
666   return n_ops;
667 }
668
669 static_always_inline void *
670 aesni_gcm_key_exp (vnet_crypto_key_t * key, aes_key_size_t ks)
671 {
672   aes_gcm_key_data_t *kd;
673   u8x16 H;
674
675   kd = clib_mem_alloc_aligned (sizeof (*kd), CLIB_CACHE_LINE_BYTES);
676
677   /* expand AES key */
678   aes_key_expand ((u8x16 *) kd->Ke, key->data, ks);
679
680   /* pre-calculate H */
681   H = aes_encrypt_block (u8x16_splat (0), kd->Ke, ks);
682   H = aesni_gcm_bswap (H);
683   ghash_precompute (H, (u8x16 *) kd->Hi, 8);
684   return kd;
685 }
686
687 #define foreach_aesni_gcm_handler_type _(128) _(192) _(256)
688
689 #define _(x) \
690 static u32 aesni_ops_dec_aes_gcm_##x                                         \
691 (vlib_main_t * vm, vnet_crypto_op_t * ops[], u32 n_ops)                      \
692 { return aesni_ops_dec_aes_gcm (vm, ops, n_ops, AES_KEY_##x); }              \
693 static u32 aesni_ops_enc_aes_gcm_##x                                         \
694 (vlib_main_t * vm, vnet_crypto_op_t * ops[], u32 n_ops)                      \
695 { return aesni_ops_enc_aes_gcm (vm, ops, n_ops, AES_KEY_##x); }              \
696 static void * aesni_gcm_key_exp_##x (vnet_crypto_key_t *key)                 \
697 { return aesni_gcm_key_exp (key, AES_KEY_##x); }
698
699 foreach_aesni_gcm_handler_type;
700 #undef _
701
702 clib_error_t *
703 #ifdef __VAES__
704 crypto_native_aes_gcm_init_vaes (vlib_main_t * vm)
705 #elif __AVX512F__
706 crypto_native_aes_gcm_init_avx512 (vlib_main_t * vm)
707 #elif __AVX2__
708 crypto_native_aes_gcm_init_avx2 (vlib_main_t * vm)
709 #else
710 crypto_native_aes_gcm_init_sse42 (vlib_main_t * vm)
711 #endif
712 {
713   crypto_native_main_t *cm = &crypto_native_main;
714
715 #define _(x) \
716   vnet_crypto_register_ops_handler (vm, cm->crypto_engine_index, \
717                                     VNET_CRYPTO_OP_AES_##x##_GCM_ENC, \
718                                     aesni_ops_enc_aes_gcm_##x); \
719   vnet_crypto_register_ops_handler (vm, cm->crypto_engine_index, \
720                                     VNET_CRYPTO_OP_AES_##x##_GCM_DEC, \
721                                     aesni_ops_dec_aes_gcm_##x); \
722   cm->key_fn[VNET_CRYPTO_ALG_AES_##x##_GCM] = aesni_gcm_key_exp_##x;
723   foreach_aesni_gcm_handler_type;
724 #undef _
725   return 0;
726 }
727
728 /*
729  * fd.io coding-style-patch-verification: ON
730  *
731  * Local Variables:
732  * eval: (c-set-style "gnu")
733  * End:
734  */