w32: Fix alignment problem with AESNI on Windows >= 8
[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 #endif
135       return "selftest for CBC failed - see syslog for details";
136     }
137
138   if (memcmp (iv2, iv, blocksize))
139     {
140       xfree (mem);
141 #ifdef HAVE_SYSLOG
142       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
143               "%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8);
144 #endif
145       return "selftest for CBC failed - see syslog for details";
146     }
147
148   /* Test parallelized code paths */
149   memset (iv, 0x5f, blocksize);
150   memset (iv2, 0x5f, blocksize);
151
152   for (i = 0; i < nblocks * blocksize; i++)
153     plaintext[i] = i;
154
155   /* Create CBC ciphertext manually.  */
156   for (i = 0; i < nblocks * blocksize; i+=blocksize)
157     {
158       buf_xor (&ciphertext[i], iv, &plaintext[i], blocksize);
159       encrypt_one (ctx, &ciphertext[i], &ciphertext[i]);
160       memcpy (iv, &ciphertext[i], blocksize);
161     }
162
163   /* Decrypt using bulk CBC and compare result.  */
164   bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
165
166   if (memcmp (plaintext2, plaintext, nblocks * blocksize))
167     {
168       xfree (mem);
169 #ifdef HAVE_SYSLOG
170       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
171               "%s-CBC-%d test failed (plaintext mismatch, parallel path)",
172               cipher, blocksize * 8);
173 #endif
174       return "selftest for CBC failed - see syslog for details";
175     }
176   if (memcmp (iv2, iv, blocksize))
177     {
178       xfree (mem);
179 #ifdef HAVE_SYSLOG
180       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
181               "%s-CBC-%d test failed (IV mismatch, parallel path)",
182               cipher, blocksize * 8);
183 #endif
184       return "selftest for CBC failed - see syslog for details";
185     }
186
187   xfree (mem);
188   return NULL;
189 }
190
191 /* Run the self-tests for <block cipher>-CFB-<block size>, tests bulk CFB
192    decryption.  Returns NULL on success. */
193 const char *
194 _gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey_func,
195                            gcry_cipher_encrypt_t encrypt_one,
196                            gcry_cipher_bulk_cfb_dec_t bulk_cfb_dec,
197                            const int nblocks, const int blocksize,
198                            const int context_size)
199 {
200   int i, offs;
201   unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
202   unsigned int ctx_aligned_size, memsize;
203
204   static const unsigned char key[16] ATTR_ALIGNED_16 = {
205       0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
206       0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33
207     };
208
209   /* Allocate buffers, align first two elements to 16 bytes and latter to
210      block size.  */
211   ctx_aligned_size = context_size + 15;
212   ctx_aligned_size -= ctx_aligned_size & 0xf;
213
214   memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
215
216   mem = xtrycalloc (1, memsize);
217   if (!mem)
218     return "failed to allocate memory";
219
220   offs = (16 - ((uintptr_t)mem & 15)) & 15;
221   ctx = (void*)(mem + offs);
222   iv = ctx + ctx_aligned_size;
223   iv2 = iv + blocksize;
224   plaintext = iv2 + blocksize;
225   plaintext2 = plaintext + nblocks * blocksize;
226   ciphertext = plaintext2 + nblocks * blocksize;
227
228   /* Initialize ctx */
229   if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
230    {
231      xfree(mem);
232      return "setkey failed";
233    }
234
235   /* Test single block code path */
236   memset(iv, 0xd3, blocksize);
237   memset(iv2, 0xd3, blocksize);
238   for (i = 0; i < blocksize; i++)
239     plaintext[i] = i;
240
241   /* CFB manually.  */
242   encrypt_one (ctx, ciphertext, iv);
243   buf_xor_2dst (iv, ciphertext, plaintext, blocksize);
244
245   /* CFB decrypt.  */
246   bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, 1);
247   if (memcmp(plaintext2, plaintext, blocksize))
248     {
249       xfree(mem);
250 #ifdef HAVE_SYSLOG
251       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
252               "%s-CFB-%d test failed (plaintext mismatch)", cipher,
253               blocksize * 8);
254 #endif
255       return "selftest for CFB failed - see syslog for details";
256     }
257
258   if (memcmp(iv2, iv, blocksize))
259     {
260       xfree(mem);
261 #ifdef HAVE_SYSLOG
262       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
263               "%s-CFB-%d test failed (IV mismatch)", cipher, blocksize * 8);
264 #endif
265       return "selftest for CFB failed - see syslog for details";
266     }
267
268   /* Test parallelized code paths */
269   memset(iv, 0xe6, blocksize);
270   memset(iv2, 0xe6, blocksize);
271
272   for (i = 0; i < nblocks * blocksize; i++)
273     plaintext[i] = i;
274
275   /* Create CFB ciphertext manually.  */
276   for (i = 0; i < nblocks * blocksize; i+=blocksize)
277     {
278       encrypt_one (ctx, &ciphertext[i], iv);
279       buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize);
280     }
281
282   /* Decrypt using bulk CBC and compare result.  */
283   bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
284
285   if (memcmp(plaintext2, plaintext, nblocks * blocksize))
286     {
287       xfree(mem);
288 #ifdef HAVE_SYSLOG
289       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
290               "%s-CFB-%d test failed (plaintext mismatch, parallel path)",
291               cipher, blocksize * 8);
292 #endif
293       return "selftest for CFB failed - see syslog for details";
294     }
295   if (memcmp(iv2, iv, blocksize))
296     {
297       xfree(mem);
298 #ifdef HAVE_SYSLOG
299       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
300               "%s-CFB-%d test failed (IV mismatch, parallel path)", cipher,
301               blocksize * 8);
302 #endif
303       return "selftest for CFB failed - see syslog for details";
304     }
305
306   xfree(mem);
307   return NULL;
308 }
309
310 /* Run the self-tests for <block cipher>-CTR-<block size>, tests IV increment
311    of bulk CTR encryption.  Returns NULL on success. */
312 const char *
313 _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
314                            gcry_cipher_encrypt_t encrypt_one,
315                            gcry_cipher_bulk_ctr_enc_t bulk_ctr_enc,
316                            const int nblocks, const int blocksize,
317                            const int context_size)
318 {
319   int i, j, offs, diff;
320   unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *ciphertext2,
321                 *iv, *iv2, *mem;
322   unsigned int ctx_aligned_size, memsize;
323
324   static const unsigned char key[16] ATTR_ALIGNED_16 = {
325       0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
326       0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
327     };
328
329   /* Allocate buffers, align first two elements to 16 bytes and latter to
330      block size.  */
331   ctx_aligned_size = context_size + 15;
332   ctx_aligned_size -= ctx_aligned_size & 0xf;
333
334   memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 4) + 16;
335
336   mem = xtrycalloc (1, memsize);
337   if (!mem)
338     return "failed to allocate memory";
339
340   offs = (16 - ((uintptr_t)mem & 15)) & 15;
341   ctx = (void*)(mem + offs);
342   iv = ctx + ctx_aligned_size;
343   iv2 = iv + blocksize;
344   plaintext = iv2 + blocksize;
345   plaintext2 = plaintext + nblocks * blocksize;
346   ciphertext = plaintext2 + nblocks * blocksize;
347   ciphertext2 = ciphertext + nblocks * blocksize;
348
349   /* Initialize ctx */
350   if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
351    {
352      xfree(mem);
353      return "setkey failed";
354    }
355
356   /* Test single block code path */
357   memset (iv, 0xff, blocksize);
358   for (i = 0; i < blocksize; i++)
359     plaintext[i] = i;
360
361   /* CTR manually.  */
362   encrypt_one (ctx, ciphertext, iv);
363   for (i = 0; i < blocksize; i++)
364     ciphertext[i] ^= plaintext[i];
365   for (i = blocksize; i > 0; i--)
366     {
367       iv[i-1]++;
368       if (iv[i-1])
369         break;
370     }
371
372   memset (iv2, 0xff, blocksize);
373   bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, 1);
374
375   if (memcmp (plaintext2, plaintext, blocksize))
376     {
377       xfree (mem);
378 #ifdef HAVE_SYSLOG
379       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
380               "%s-CTR-%d test failed (plaintext mismatch)", cipher,
381               blocksize * 8);
382 #endif
383       return "selftest for CTR failed - see syslog for details";
384     }
385
386   if (memcmp (iv2, iv, blocksize))
387     {
388       xfree (mem);
389 #ifdef HAVE_SYSLOG
390       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
391               "%s-CTR-%d test failed (IV mismatch)", cipher,
392               blocksize * 8);
393 #endif
394       return "selftest for CTR failed - see syslog for details";
395     }
396
397   /* Test bulk encryption with typical IV. */
398   memset(iv, 0x57, blocksize-4);
399   iv[blocksize-1] = 1;
400   iv[blocksize-2] = 0;
401   iv[blocksize-3] = 0;
402   iv[blocksize-4] = 0;
403   memset(iv2, 0x57, blocksize-4);
404   iv2[blocksize-1] = 1;
405   iv2[blocksize-2] = 0;
406   iv2[blocksize-3] = 0;
407   iv2[blocksize-4] = 0;
408
409   for (i = 0; i < blocksize * nblocks; i++)
410     plaintext2[i] = plaintext[i] = i;
411
412   /* Create CTR ciphertext manually.  */
413   for (i = 0; i < blocksize * nblocks; i+=blocksize)
414     {
415       encrypt_one (ctx, &ciphertext[i], iv);
416       for (j = 0; j < blocksize; j++)
417         ciphertext[i+j] ^= plaintext[i+j];
418       for (j = blocksize; j > 0; j--)
419         {
420           iv[j-1]++;
421           if (iv[j-1])
422             break;
423         }
424     }
425
426   bulk_ctr_enc (ctx, iv2, ciphertext2, plaintext2, nblocks);
427
428   if (memcmp (ciphertext2, ciphertext, blocksize * nblocks))
429     {
430       xfree (mem);
431 #ifdef HAVE_SYSLOG
432       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
433               "%s-CTR-%d test failed (ciphertext mismatch, bulk)", cipher,
434               blocksize * 8);
435 #endif
436       return "selftest for CTR failed - see syslog for details";
437     }
438   if (memcmp(iv2, iv, blocksize))
439     {
440       xfree (mem);
441 #ifdef HAVE_SYSLOG
442       syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
443               "%s-CTR-%d test failed (IV mismatch, bulk)", cipher,
444               blocksize * 8);
445 #endif
446       return "selftest for CTR failed - see syslog for details";
447     }
448
449   /* Test parallelized code paths (check counter overflow handling) */
450   for (diff = 0; diff < nblocks; diff++) {
451     memset(iv, 0xff, blocksize);
452     iv[blocksize-1] -= diff;
453     iv[0] = iv[1] = 0;
454     iv[2] = 0x07;
455
456     for (i = 0; i < blocksize * nblocks; i++)
457       plaintext[i] = i;
458
459     /* Create CTR ciphertext manually.  */
460     for (i = 0; i < blocksize * nblocks; i+=blocksize)
461       {
462         encrypt_one (ctx, &ciphertext[i], iv);
463         for (j = 0; j < blocksize; j++)
464           ciphertext[i+j] ^= plaintext[i+j];
465         for (j = blocksize; j > 0; j--)
466           {
467             iv[j-1]++;
468             if (iv[j-1])
469               break;
470           }
471       }
472
473     /* Decrypt using bulk CTR and compare result.  */
474     memset(iv2, 0xff, blocksize);
475     iv2[blocksize-1] -= diff;
476     iv2[0] = iv2[1] = 0;
477     iv2[2] = 0x07;
478
479     bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, nblocks);
480
481     if (memcmp (plaintext2, plaintext, blocksize * nblocks))
482       {
483         xfree (mem);
484 #ifdef HAVE_SYSLOG
485         syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
486                 "%s-CTR-%d test failed (plaintext mismatch, diff: %d)", cipher,
487                 blocksize * 8, diff);
488 #endif
489         return "selftest for CTR failed - see syslog for details";
490       }
491     if (memcmp(iv2, iv, blocksize))
492       {
493         xfree (mem);
494 #ifdef HAVE_SYSLOG
495         syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
496                 "%s-CTR-%d test failed (IV mismatch, diff: %d)", cipher,
497                 blocksize * 8, diff);
498 #endif
499         return "selftest for CTR failed - see syslog for details";
500       }
501   }
502
503   xfree (mem);
504   return NULL;
505 }