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