Line data Source code
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 0 : _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 0 : ctx_aligned_size = context_size + 15;
57 0 : ctx_aligned_size -= ctx_aligned_size & 0xf;
58 :
59 0 : memsize = ctx_aligned_size + 16;
60 :
61 0 : *r_mem = xtrycalloc (1, memsize);
62 0 : if (!*r_mem)
63 0 : return NULL;
64 :
65 0 : offs = (16 - ((uintptr_t)*r_mem & 15)) & 15;
66 0 : 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 0 : _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 0 : ctx_aligned_size = context_size + 15;
91 0 : ctx_aligned_size -= ctx_aligned_size & 0xf;
92 :
93 0 : memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
94 :
95 0 : mem = xtrycalloc (1, memsize);
96 0 : if (!mem)
97 0 : return "failed to allocate memory";
98 :
99 0 : offs = (16 - ((uintptr_t)mem & 15)) & 15;
100 0 : ctx = (void*)(mem + offs);
101 0 : iv = ctx + ctx_aligned_size;
102 0 : iv2 = iv + blocksize;
103 0 : plaintext = iv2 + blocksize;
104 0 : plaintext2 = plaintext + nblocks * blocksize;
105 0 : ciphertext = plaintext2 + nblocks * blocksize;
106 :
107 : /* Initialize ctx */
108 0 : if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
109 : {
110 0 : xfree(mem);
111 0 : return "setkey failed";
112 : }
113 :
114 : /* Test single block code path */
115 0 : memset (iv, 0x4e, blocksize);
116 0 : memset (iv2, 0x4e, blocksize);
117 0 : for (i = 0; i < blocksize; i++)
118 0 : plaintext[i] = i;
119 :
120 : /* CBC manually. */
121 0 : buf_xor (ciphertext, iv, plaintext, blocksize);
122 0 : encrypt_one (ctx, ciphertext, ciphertext);
123 0 : memcpy (iv, ciphertext, blocksize);
124 :
125 : /* CBC decrypt. */
126 0 : bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, 1);
127 0 : if (memcmp (plaintext2, plaintext, blocksize))
128 : {
129 0 : xfree (mem);
130 : #ifdef HAVE_SYSLOG
131 0 : 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 0 : return "selftest for CBC failed - see syslog for details";
138 : }
139 :
140 0 : if (memcmp (iv2, iv, blocksize))
141 : {
142 0 : xfree (mem);
143 : #ifdef HAVE_SYSLOG
144 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
145 : "%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8);
146 : #endif
147 0 : return "selftest for CBC failed - see syslog for details";
148 : }
149 :
150 : /* Test parallelized code paths */
151 0 : memset (iv, 0x5f, blocksize);
152 0 : memset (iv2, 0x5f, blocksize);
153 :
154 0 : for (i = 0; i < nblocks * blocksize; i++)
155 0 : plaintext[i] = i;
156 :
157 : /* Create CBC ciphertext manually. */
158 0 : for (i = 0; i < nblocks * blocksize; i+=blocksize)
159 : {
160 0 : buf_xor (&ciphertext[i], iv, &plaintext[i], blocksize);
161 0 : encrypt_one (ctx, &ciphertext[i], &ciphertext[i]);
162 0 : memcpy (iv, &ciphertext[i], blocksize);
163 : }
164 :
165 : /* Decrypt using bulk CBC and compare result. */
166 0 : bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
167 :
168 0 : if (memcmp (plaintext2, plaintext, nblocks * blocksize))
169 : {
170 0 : xfree (mem);
171 : #ifdef HAVE_SYSLOG
172 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
173 : "%s-CBC-%d test failed (plaintext mismatch, parallel path)",
174 : cipher, blocksize * 8);
175 : #endif
176 0 : return "selftest for CBC failed - see syslog for details";
177 : }
178 0 : if (memcmp (iv2, iv, blocksize))
179 : {
180 0 : xfree (mem);
181 : #ifdef HAVE_SYSLOG
182 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
183 : "%s-CBC-%d test failed (IV mismatch, parallel path)",
184 : cipher, blocksize * 8);
185 : #endif
186 0 : return "selftest for CBC failed - see syslog for details";
187 : }
188 :
189 0 : xfree (mem);
190 0 : 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 0 : _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 0 : ctx_aligned_size = context_size + 15;
214 0 : ctx_aligned_size -= ctx_aligned_size & 0xf;
215 :
216 0 : memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
217 :
218 0 : mem = xtrycalloc (1, memsize);
219 0 : if (!mem)
220 0 : return "failed to allocate memory";
221 :
222 0 : offs = (16 - ((uintptr_t)mem & 15)) & 15;
223 0 : ctx = (void*)(mem + offs);
224 0 : iv = ctx + ctx_aligned_size;
225 0 : iv2 = iv + blocksize;
226 0 : plaintext = iv2 + blocksize;
227 0 : plaintext2 = plaintext + nblocks * blocksize;
228 0 : ciphertext = plaintext2 + nblocks * blocksize;
229 :
230 : /* Initialize ctx */
231 0 : if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
232 : {
233 0 : xfree(mem);
234 0 : return "setkey failed";
235 : }
236 :
237 : /* Test single block code path */
238 0 : memset(iv, 0xd3, blocksize);
239 0 : memset(iv2, 0xd3, blocksize);
240 0 : for (i = 0; i < blocksize; i++)
241 0 : plaintext[i] = i;
242 :
243 : /* CFB manually. */
244 0 : encrypt_one (ctx, ciphertext, iv);
245 0 : buf_xor_2dst (iv, ciphertext, plaintext, blocksize);
246 :
247 : /* CFB decrypt. */
248 0 : bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, 1);
249 0 : if (memcmp(plaintext2, plaintext, blocksize))
250 : {
251 0 : xfree(mem);
252 : #ifdef HAVE_SYSLOG
253 0 : 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 0 : return "selftest for CFB failed - see syslog for details";
260 : }
261 :
262 0 : if (memcmp(iv2, iv, blocksize))
263 : {
264 0 : xfree(mem);
265 : #ifdef HAVE_SYSLOG
266 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
267 : "%s-CFB-%d test failed (IV mismatch)", cipher, blocksize * 8);
268 : #endif
269 0 : return "selftest for CFB failed - see syslog for details";
270 : }
271 :
272 : /* Test parallelized code paths */
273 0 : memset(iv, 0xe6, blocksize);
274 0 : memset(iv2, 0xe6, blocksize);
275 :
276 0 : for (i = 0; i < nblocks * blocksize; i++)
277 0 : plaintext[i] = i;
278 :
279 : /* Create CFB ciphertext manually. */
280 0 : for (i = 0; i < nblocks * blocksize; i+=blocksize)
281 : {
282 0 : encrypt_one (ctx, &ciphertext[i], iv);
283 0 : buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize);
284 : }
285 :
286 : /* Decrypt using bulk CBC and compare result. */
287 0 : bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
288 :
289 0 : if (memcmp(plaintext2, plaintext, nblocks * blocksize))
290 : {
291 0 : xfree(mem);
292 : #ifdef HAVE_SYSLOG
293 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
294 : "%s-CFB-%d test failed (plaintext mismatch, parallel path)",
295 : cipher, blocksize * 8);
296 : #endif
297 0 : return "selftest for CFB failed - see syslog for details";
298 : }
299 0 : if (memcmp(iv2, iv, blocksize))
300 : {
301 0 : xfree(mem);
302 : #ifdef HAVE_SYSLOG
303 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
304 : "%s-CFB-%d test failed (IV mismatch, parallel path)", cipher,
305 : blocksize * 8);
306 : #endif
307 0 : return "selftest for CFB failed - see syslog for details";
308 : }
309 :
310 0 : xfree(mem);
311 0 : 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 0 : _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 0 : ctx_aligned_size = context_size + 15;
336 0 : ctx_aligned_size -= ctx_aligned_size & 0xf;
337 :
338 0 : memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 4) + 16;
339 :
340 0 : mem = xtrycalloc (1, memsize);
341 0 : if (!mem)
342 0 : return "failed to allocate memory";
343 :
344 0 : offs = (16 - ((uintptr_t)mem & 15)) & 15;
345 0 : ctx = (void*)(mem + offs);
346 0 : iv = ctx + ctx_aligned_size;
347 0 : iv2 = iv + blocksize;
348 0 : plaintext = iv2 + blocksize;
349 0 : plaintext2 = plaintext + nblocks * blocksize;
350 0 : ciphertext = plaintext2 + nblocks * blocksize;
351 0 : ciphertext2 = ciphertext + nblocks * blocksize;
352 :
353 : /* Initialize ctx */
354 0 : if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
355 : {
356 0 : xfree(mem);
357 0 : return "setkey failed";
358 : }
359 :
360 : /* Test single block code path */
361 0 : memset (iv, 0xff, blocksize);
362 0 : for (i = 0; i < blocksize; i++)
363 0 : plaintext[i] = i;
364 :
365 : /* CTR manually. */
366 0 : encrypt_one (ctx, ciphertext, iv);
367 0 : for (i = 0; i < blocksize; i++)
368 0 : ciphertext[i] ^= plaintext[i];
369 0 : for (i = blocksize; i > 0; i--)
370 : {
371 0 : iv[i-1]++;
372 0 : if (iv[i-1])
373 0 : break;
374 : }
375 :
376 0 : memset (iv2, 0xff, blocksize);
377 0 : bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, 1);
378 :
379 0 : if (memcmp (plaintext2, plaintext, blocksize))
380 : {
381 0 : xfree (mem);
382 : #ifdef HAVE_SYSLOG
383 0 : 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 0 : return "selftest for CTR failed - see syslog for details";
390 : }
391 :
392 0 : if (memcmp (iv2, iv, blocksize))
393 : {
394 0 : xfree (mem);
395 : #ifdef HAVE_SYSLOG
396 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
397 : "%s-CTR-%d test failed (IV mismatch)", cipher,
398 : blocksize * 8);
399 : #endif
400 0 : return "selftest for CTR failed - see syslog for details";
401 : }
402 :
403 : /* Test bulk encryption with typical IV. */
404 0 : memset(iv, 0x57, blocksize-4);
405 0 : iv[blocksize-1] = 1;
406 0 : iv[blocksize-2] = 0;
407 0 : iv[blocksize-3] = 0;
408 0 : iv[blocksize-4] = 0;
409 0 : memset(iv2, 0x57, blocksize-4);
410 0 : iv2[blocksize-1] = 1;
411 0 : iv2[blocksize-2] = 0;
412 0 : iv2[blocksize-3] = 0;
413 0 : iv2[blocksize-4] = 0;
414 :
415 0 : for (i = 0; i < blocksize * nblocks; i++)
416 0 : plaintext2[i] = plaintext[i] = i;
417 :
418 : /* Create CTR ciphertext manually. */
419 0 : for (i = 0; i < blocksize * nblocks; i+=blocksize)
420 : {
421 0 : encrypt_one (ctx, &ciphertext[i], iv);
422 0 : for (j = 0; j < blocksize; j++)
423 0 : ciphertext[i+j] ^= plaintext[i+j];
424 0 : for (j = blocksize; j > 0; j--)
425 : {
426 0 : iv[j-1]++;
427 0 : if (iv[j-1])
428 0 : break;
429 : }
430 : }
431 :
432 0 : bulk_ctr_enc (ctx, iv2, ciphertext2, plaintext2, nblocks);
433 :
434 0 : if (memcmp (ciphertext2, ciphertext, blocksize * nblocks))
435 : {
436 0 : xfree (mem);
437 : #ifdef HAVE_SYSLOG
438 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
439 : "%s-CTR-%d test failed (ciphertext mismatch, bulk)", cipher,
440 : blocksize * 8);
441 : #endif
442 0 : return "selftest for CTR failed - see syslog for details";
443 : }
444 0 : if (memcmp(iv2, iv, blocksize))
445 : {
446 0 : xfree (mem);
447 : #ifdef HAVE_SYSLOG
448 0 : syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
449 : "%s-CTR-%d test failed (IV mismatch, bulk)", cipher,
450 : blocksize * 8);
451 : #endif
452 0 : return "selftest for CTR failed - see syslog for details";
453 : }
454 :
455 : /* Test parallelized code paths (check counter overflow handling) */
456 0 : for (diff = 0; diff < nblocks; diff++) {
457 0 : memset(iv, 0xff, blocksize);
458 0 : iv[blocksize-1] -= diff;
459 0 : iv[0] = iv[1] = 0;
460 0 : iv[2] = 0x07;
461 :
462 0 : for (i = 0; i < blocksize * nblocks; i++)
463 0 : plaintext[i] = i;
464 :
465 : /* Create CTR ciphertext manually. */
466 0 : for (i = 0; i < blocksize * nblocks; i+=blocksize)
467 : {
468 0 : encrypt_one (ctx, &ciphertext[i], iv);
469 0 : for (j = 0; j < blocksize; j++)
470 0 : ciphertext[i+j] ^= plaintext[i+j];
471 0 : for (j = blocksize; j > 0; j--)
472 : {
473 0 : iv[j-1]++;
474 0 : if (iv[j-1])
475 0 : break;
476 : }
477 : }
478 :
479 : /* Decrypt using bulk CTR and compare result. */
480 0 : memset(iv2, 0xff, blocksize);
481 0 : iv2[blocksize-1] -= diff;
482 0 : iv2[0] = iv2[1] = 0;
483 0 : iv2[2] = 0x07;
484 :
485 0 : bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, nblocks);
486 :
487 0 : if (memcmp (plaintext2, plaintext, blocksize * nblocks))
488 : {
489 0 : xfree (mem);
490 : #ifdef HAVE_SYSLOG
491 0 : 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 0 : return "selftest for CTR failed - see syslog for details";
496 : }
497 0 : if (memcmp(iv2, iv, blocksize))
498 : {
499 0 : xfree (mem);
500 : #ifdef HAVE_SYSLOG
501 0 : 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 0 : return "selftest for CTR failed - see syslog for details";
506 : }
507 : }
508 :
509 0 : xfree (mem);
510 0 : return NULL;
511 : }
|