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