Add ARMv8/CE acceleration for AES-XTS
[libgcrypt.git] / cipher / cipher-selftest.c
1 /* cipher-selftest.c - Helper functions for bulk encryption selftests.
2  * Copyright (C) 2013 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 #include <config.h>
21 #ifdef HAVE_SYSLOG
22 # include <syslog.h>
23 #endif /*HAVE_SYSLOG*/
24
25 #include "types.h"
26 #include "g10lib.h"
27 #include "cipher.h"
28 #include "bufhelp.h"
29 #include "cipher-selftest.h"
30
31 #ifdef HAVE_STDINT_H
32 # include <stdint.h> /* uintptr_t */
33 #elif defined(HAVE_INTTYPES_H)
34 # include <inttypes.h>
35 #else
36 /* In this case, uintptr_t is provided by config.h. */
37 #endif
38
39 /* Helper macro to force alignment to 16 bytes.  */
40 #ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
41 # define ATTR_ALIGNED_16  __attribute__ ((aligned (16)))
42 #else
43 # define ATTR_ALIGNED_16
44 #endif
45
46
47 /* Return an allocated buffers of size CONTEXT_SIZE with an alignment
48    of 16.  The caller must free that buffer using the address returned
49    at R_MEM.  Returns NULL and sets ERRNO on failure.  */
50 void *
51 _gcry_cipher_selftest_alloc_ctx (const int context_size, unsigned char **r_mem)
52 {
53   int offs;
54   unsigned int ctx_aligned_size, memsize;
55
56   ctx_aligned_size = context_size + 15;
57   ctx_aligned_size -= ctx_aligned_size & 0xf;
58
59   memsize = ctx_aligned_size + 16;
60
61   *r_mem = xtrycalloc (1, memsize);
62   if (!*r_mem)
63     return NULL;
64
65   offs = (16 - ((uintptr_t)*r_mem & 15)) & 15;
66   return (void*)(*r_mem + offs);
67 }
68
69
70 /* Run the self-tests for <block cipher>-CBC-<block size>, tests bulk CBC
71    decryption.  Returns NULL on success. */
72 const char *
73 _gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey_func,
74                            gcry_cipher_encrypt_t encrypt_one,
75                            gcry_cipher_bulk_cbc_dec_t bulk_cbc_dec,
76                            const int nblocks, const int blocksize,
77                            const int context_size)
78 {
79   int i, offs;
80   unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
81   unsigned int ctx_aligned_size, memsize;
82
83   static const unsigned char key[16] ATTR_ALIGNED_16 = {
84       0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
85       0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22
86     };
87
88   /* Allocate buffers, align first two elements to 16 bytes and latter to
89      block size.  */
90   ctx_aligned_size = context_size + 15;
91   ctx_aligned_size -= ctx_aligned_size & 0xf;
92
93   memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
94
95   mem = xtrycalloc (1, memsize);
96   if (!mem)
97     return "failed to allocate memory";
98
99   offs = (16 - ((uintptr_t)mem & 15)) & 15;
100   ctx = (void*)(mem + offs);
101   iv = ctx + ctx_aligned_size;
102   iv2 = iv + blocksize;
103   plaintext = iv2 + blocksize;
104   plaintext2 = plaintext + nblocks * blocksize;
105   ciphertext = plaintext2 + nblocks * blocksize;
106
107   /* Initialize ctx */
108   if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
109    {
110      xfree(mem);
111      return "setkey failed";
112    }
113
114   /* Test single block code path */
115   memset (iv, 0x4e, blocksize);
116   memset (iv2, 0x4e, blocksize);
117   for (i = 0; i < blocksize; i++)
118     plaintext[i] = i;
119
120   /* CBC manually.  */
121   buf_xor (ciphertext, iv, plaintext, blocksize);
122   encrypt_one (ctx, ciphertext, ciphertext);
123   memcpy (iv, ciphertext, blocksize);
124
125   /* CBC decrypt.  */
126   bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, 1);
127   if (memcmp (plaintext2, plaintext, blocksize))
128     {
129       xfree (mem);
130 #ifdef HAVE_SYSLOG
131       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
132               "%s-CBC-%d test failed (plaintext mismatch)", cipher,
133               blocksize * 8);
134 #else
135       (void)cipher; /* Not used.  */
136 #endif
137       return "selftest for CBC failed - see syslog for details";
138     }
139
140   if (memcmp (iv2, iv, blocksize))
141     {
142       xfree (mem);
143 #ifdef HAVE_SYSLOG
144       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
145               "%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8);
146 #endif
147       return "selftest for CBC failed - see syslog for details";
148     }
149
150   /* Test parallelized code paths */
151   memset (iv, 0x5f, blocksize);
152   memset (iv2, 0x5f, blocksize);
153
154   for (i = 0; i < nblocks * blocksize; i++)
155     plaintext[i] = i;
156
157   /* Create CBC ciphertext manually.  */
158   for (i = 0; i < nblocks * blocksize; i+=blocksize)
159     {
160       buf_xor (&ciphertext[i], iv, &plaintext[i], blocksize);
161       encrypt_one (ctx, &ciphertext[i], &ciphertext[i]);
162       memcpy (iv, &ciphertext[i], blocksize);
163     }
164
165   /* Decrypt using bulk CBC and compare result.  */
166   bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
167
168   if (memcmp (plaintext2, plaintext, nblocks * blocksize))
169     {
170       xfree (mem);
171 #ifdef HAVE_SYSLOG
172       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
173               "%s-CBC-%d test failed (plaintext mismatch, parallel path)",
174               cipher, blocksize * 8);
175 #endif
176       return "selftest for CBC failed - see syslog for details";
177     }
178   if (memcmp (iv2, iv, blocksize))
179     {
180       xfree (mem);
181 #ifdef HAVE_SYSLOG
182       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
183               "%s-CBC-%d test failed (IV mismatch, parallel path)",
184               cipher, blocksize * 8);
185 #endif
186       return "selftest for CBC failed - see syslog for details";
187     }
188
189   xfree (mem);
190   return NULL;
191 }
192
193 /* Run the self-tests for <block cipher>-CFB-<block size>, tests bulk CFB
194    decryption.  Returns NULL on success. */
195 const char *
196 _gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey_func,
197                            gcry_cipher_encrypt_t encrypt_one,
198                            gcry_cipher_bulk_cfb_dec_t bulk_cfb_dec,
199                            const int nblocks, const int blocksize,
200                            const int context_size)
201 {
202   int i, offs;
203   unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
204   unsigned int ctx_aligned_size, memsize;
205
206   static const unsigned char key[16] ATTR_ALIGNED_16 = {
207       0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
208       0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33
209     };
210
211   /* Allocate buffers, align first two elements to 16 bytes and latter to
212      block size.  */
213   ctx_aligned_size = context_size + 15;
214   ctx_aligned_size -= ctx_aligned_size & 0xf;
215
216   memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
217
218   mem = xtrycalloc (1, memsize);
219   if (!mem)
220     return "failed to allocate memory";
221
222   offs = (16 - ((uintptr_t)mem & 15)) & 15;
223   ctx = (void*)(mem + offs);
224   iv = ctx + ctx_aligned_size;
225   iv2 = iv + blocksize;
226   plaintext = iv2 + blocksize;
227   plaintext2 = plaintext + nblocks * blocksize;
228   ciphertext = plaintext2 + nblocks * blocksize;
229
230   /* Initialize ctx */
231   if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
232    {
233      xfree(mem);
234      return "setkey failed";
235    }
236
237   /* Test single block code path */
238   memset(iv, 0xd3, blocksize);
239   memset(iv2, 0xd3, blocksize);
240   for (i = 0; i < blocksize; i++)
241     plaintext[i] = i;
242
243   /* CFB manually.  */
244   encrypt_one (ctx, ciphertext, iv);
245   buf_xor_2dst (iv, ciphertext, plaintext, blocksize);
246
247   /* CFB decrypt.  */
248   bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, 1);
249   if (memcmp(plaintext2, plaintext, blocksize))
250     {
251       xfree(mem);
252 #ifdef HAVE_SYSLOG
253       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
254               "%s-CFB-%d test failed (plaintext mismatch)", cipher,
255               blocksize * 8);
256 #else
257       (void)cipher; /* Not used.  */
258 #endif
259       return "selftest for CFB failed - see syslog for details";
260     }
261
262   if (memcmp(iv2, iv, blocksize))
263     {
264       xfree(mem);
265 #ifdef HAVE_SYSLOG
266       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
267               "%s-CFB-%d test failed (IV mismatch)", cipher, blocksize * 8);
268 #endif
269       return "selftest for CFB failed - see syslog for details";
270     }
271
272   /* Test parallelized code paths */
273   memset(iv, 0xe6, blocksize);
274   memset(iv2, 0xe6, blocksize);
275
276   for (i = 0; i < nblocks * blocksize; i++)
277     plaintext[i] = i;
278
279   /* Create CFB ciphertext manually.  */
280   for (i = 0; i < nblocks * blocksize; i+=blocksize)
281     {
282       encrypt_one (ctx, &ciphertext[i], iv);
283       buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize);
284     }
285
286   /* Decrypt using bulk CBC and compare result.  */
287   bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
288
289   if (memcmp(plaintext2, plaintext, nblocks * blocksize))
290     {
291       xfree(mem);
292 #ifdef HAVE_SYSLOG
293       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
294               "%s-CFB-%d test failed (plaintext mismatch, parallel path)",
295               cipher, blocksize * 8);
296 #endif
297       return "selftest for CFB failed - see syslog for details";
298     }
299   if (memcmp(iv2, iv, blocksize))
300     {
301       xfree(mem);
302 #ifdef HAVE_SYSLOG
303       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
304               "%s-CFB-%d test failed (IV mismatch, parallel path)", cipher,
305               blocksize * 8);
306 #endif
307       return "selftest for CFB failed - see syslog for details";
308     }
309
310   xfree(mem);
311   return NULL;
312 }
313
314 /* Run the self-tests for <block cipher>-CTR-<block size>, tests IV increment
315    of bulk CTR encryption.  Returns NULL on success. */
316 const char *
317 _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
318                            gcry_cipher_encrypt_t encrypt_one,
319                            gcry_cipher_bulk_ctr_enc_t bulk_ctr_enc,
320                            const int nblocks, const int blocksize,
321                            const int context_size)
322 {
323   int i, j, offs, diff;
324   unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *ciphertext2,
325                 *iv, *iv2, *mem;
326   unsigned int ctx_aligned_size, memsize;
327
328   static const unsigned char key[16] ATTR_ALIGNED_16 = {
329       0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
330       0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
331     };
332
333   /* Allocate buffers, align first two elements to 16 bytes and latter to
334      block size.  */
335   ctx_aligned_size = context_size + 15;
336   ctx_aligned_size -= ctx_aligned_size & 0xf;
337
338   memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 4) + 16;
339
340   mem = xtrycalloc (1, memsize);
341   if (!mem)
342     return "failed to allocate memory";
343
344   offs = (16 - ((uintptr_t)mem & 15)) & 15;
345   ctx = (void*)(mem + offs);
346   iv = ctx + ctx_aligned_size;
347   iv2 = iv + blocksize;
348   plaintext = iv2 + blocksize;
349   plaintext2 = plaintext + nblocks * blocksize;
350   ciphertext = plaintext2 + nblocks * blocksize;
351   ciphertext2 = ciphertext + nblocks * blocksize;
352
353   /* Initialize ctx */
354   if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
355    {
356      xfree(mem);
357      return "setkey failed";
358    }
359
360   /* Test single block code path */
361   memset (iv, 0xff, blocksize);
362   for (i = 0; i < blocksize; i++)
363     plaintext[i] = i;
364
365   /* CTR manually.  */
366   encrypt_one (ctx, ciphertext, iv);
367   for (i = 0; i < blocksize; i++)
368     ciphertext[i] ^= plaintext[i];
369   for (i = blocksize; i > 0; i--)
370     {
371       iv[i-1]++;
372       if (iv[i-1])
373         break;
374     }
375
376   memset (iv2, 0xff, blocksize);
377   bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, 1);
378
379   if (memcmp (plaintext2, plaintext, blocksize))
380     {
381       xfree (mem);
382 #ifdef HAVE_SYSLOG
383       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
384               "%s-CTR-%d test failed (plaintext mismatch)", cipher,
385               blocksize * 8);
386 #else
387       (void)cipher; /* Not used.  */
388 #endif
389       return "selftest for CTR failed - see syslog for details";
390     }
391
392   if (memcmp (iv2, iv, blocksize))
393     {
394       xfree (mem);
395 #ifdef HAVE_SYSLOG
396       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
397               "%s-CTR-%d test failed (IV mismatch)", cipher,
398               blocksize * 8);
399 #endif
400       return "selftest for CTR failed - see syslog for details";
401     }
402
403   /* Test bulk encryption with typical IV. */
404   memset(iv, 0x57, blocksize-4);
405   iv[blocksize-1] = 1;
406   iv[blocksize-2] = 0;
407   iv[blocksize-3] = 0;
408   iv[blocksize-4] = 0;
409   memset(iv2, 0x57, blocksize-4);
410   iv2[blocksize-1] = 1;
411   iv2[blocksize-2] = 0;
412   iv2[blocksize-3] = 0;
413   iv2[blocksize-4] = 0;
414
415   for (i = 0; i < blocksize * nblocks; i++)
416     plaintext2[i] = plaintext[i] = i;
417
418   /* Create CTR ciphertext manually.  */
419   for (i = 0; i < blocksize * nblocks; i+=blocksize)
420     {
421       encrypt_one (ctx, &ciphertext[i], iv);
422       for (j = 0; j < blocksize; j++)
423         ciphertext[i+j] ^= plaintext[i+j];
424       for (j = blocksize; j > 0; j--)
425         {
426           iv[j-1]++;
427           if (iv[j-1])
428             break;
429         }
430     }
431
432   bulk_ctr_enc (ctx, iv2, ciphertext2, plaintext2, nblocks);
433
434   if (memcmp (ciphertext2, ciphertext, blocksize * nblocks))
435     {
436       xfree (mem);
437 #ifdef HAVE_SYSLOG
438       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
439               "%s-CTR-%d test failed (ciphertext mismatch, bulk)", cipher,
440               blocksize * 8);
441 #endif
442       return "selftest for CTR failed - see syslog for details";
443     }
444   if (memcmp(iv2, iv, blocksize))
445     {
446       xfree (mem);
447 #ifdef HAVE_SYSLOG
448       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
449               "%s-CTR-%d test failed (IV mismatch, bulk)", cipher,
450               blocksize * 8);
451 #endif
452       return "selftest for CTR failed - see syslog for details";
453     }
454
455   /* Test parallelized code paths (check counter overflow handling) */
456   for (diff = 0; diff < nblocks; diff++) {
457     memset(iv, 0xff, blocksize);
458     iv[blocksize-1] -= diff;
459     iv[0] = iv[1] = 0;
460     iv[2] = 0x07;
461
462     for (i = 0; i < blocksize * nblocks; i++)
463       plaintext[i] = i;
464
465     /* Create CTR ciphertext manually.  */
466     for (i = 0; i < blocksize * nblocks; i+=blocksize)
467       {
468         encrypt_one (ctx, &ciphertext[i], iv);
469         for (j = 0; j < blocksize; j++)
470           ciphertext[i+j] ^= plaintext[i+j];
471         for (j = blocksize; j > 0; j--)
472           {
473             iv[j-1]++;
474             if (iv[j-1])
475               break;
476           }
477       }
478
479     /* Decrypt using bulk CTR and compare result.  */
480     memset(iv2, 0xff, blocksize);
481     iv2[blocksize-1] -= diff;
482     iv2[0] = iv2[1] = 0;
483     iv2[2] = 0x07;
484
485     bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, nblocks);
486
487     if (memcmp (plaintext2, plaintext, blocksize * nblocks))
488       {
489         xfree (mem);
490 #ifdef HAVE_SYSLOG
491         syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
492                 "%s-CTR-%d test failed (plaintext mismatch, diff: %d)", cipher,
493                 blocksize * 8, diff);
494 #endif
495         return "selftest for CTR failed - see syslog for details";
496       }
497     if (memcmp(iv2, iv, blocksize))
498       {
499         xfree (mem);
500 #ifdef HAVE_SYSLOG
501         syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
502                 "%s-CTR-%d test failed (IV mismatch, diff: %d)", cipher,
503                 blocksize * 8, diff);
504 #endif
505         return "selftest for CTR failed - see syslog for details";
506       }
507   }
508
509   xfree (mem);
510   return NULL;
511 }