diff options
author | Werner Koch <wk@gnupg.org> | 2009-12-09 11:21:17 +0000 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2009-12-09 11:21:17 +0000 |
commit | 3147b0eb8c0c42e4c77c4b4405be5e3f1af74534 (patch) | |
tree | d5867a6c2cefc2bf5d1422396a0377dcdcb4eb61 | |
parent | 379ba9a761d1fa259e673ed9552fc2e73b5b2ea3 (diff) | |
download | libgcrypt-3147b0eb8c0c42e4c77c4b4405be5e3f1af74534.tar.gz |
Implemented the AES-Wrap algorithm
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | cipher/ChangeLog | 13 | ||||
-rw-r--r-- | cipher/cipher.c | 429 | ||||
-rw-r--r-- | doc/gcrypt.texi | 14 | ||||
-rw-r--r-- | src/ChangeLog | 4 | ||||
-rw-r--r-- | src/gcrypt.h.in | 3 | ||||
-rw-r--r-- | tests/ChangeLog | 4 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/aeswrap.c | 259 | ||||
-rw-r--r-- | tests/benchmark.c | 3 |
10 files changed, 622 insertions, 115 deletions
@@ -1,6 +1,12 @@ Noteworthy changes in version 1.5.x (unreleased) ------------------------------------------------ + * New cipher algorithm mode for AES-WRAP. + + * Interface changes relative to the 1.4.2 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GCRY_CIPHER_MODE_AESWRAP NEW. + Noteworthy changes in version 1.4.4 (2009-01-22) ------------------------------------------------ diff --git a/cipher/ChangeLog b/cipher/ChangeLog index f07a60f0..2ddd1d95 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,16 @@ +2009-12-09 Werner Koch <wk@g10code.com> + + * cipher.c (gcry_cipher_open): Allow for GCRY_CIPHER_MODE_AESWRAP. + (cipher_encrypt, cipher_decrypt): Ditto. + (do_aeswrap_encrypt, do_aeswrap_decrypt): New. + (struct gcry_cipher_handle): Add field marks. + (cipher_setkey, cipher_setiv): Update marks flags. + (cipher_reset): Reset marks. + (cipher_encrypt, cipher_decrypt): Add new arg OUTBUFLEN. + (gcry_cipher_encrypt, gcry_cipher_decrypt): Pass outbuflen to + cipher_encrypt. Replace GPG_ERR_TOO_SHORT by + GPG_ERR_BUFFER_TOO_SHORT. + 2009-08-21 Werner Koch <wk@g10code.com> * dsa.c (dsa_generate_ext): Release retfactors array before diff --git a/cipher/cipher.c b/cipher/cipher.c index 6d97c194..355ba689 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -192,6 +192,11 @@ struct gcry_cipher_handle int mode; unsigned int flags; + struct { + unsigned int key:1; /* Set to 1 if a key has been set. */ + unsigned int iv:1; /* Set to 1 if ae IV has been set. */ + } marks; + /* The initialization vector. To help code optimization we make sure that it is aligned on an unsigned long and u32 boundary. */ union { @@ -724,6 +729,7 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, case GCRY_CIPHER_MODE_CFB: case GCRY_CIPHER_MODE_OFB: case GCRY_CIPHER_MODE_CTR: + case GCRY_CIPHER_MODE_AESWRAP: if ((cipher->encrypt == dummy_encrypt_block) || (cipher->decrypt == dummy_decrypt_block)) err = GPG_ERR_INV_CIPHER_MODE; @@ -882,7 +888,10 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen) memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize), (void *) &c->context.c, c->cipher->contextsize); + c->marks.key = 1; } + else + c->marks.key = 0; return gcry_error (ret); } @@ -905,7 +914,10 @@ cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen ) if (ivlen > c->cipher->blocksize) ivlen = c->cipher->blocksize; memcpy (c->u_iv.iv, iv, ivlen); + c->marks.iv = 1; } + else + c->marks.iv = 0; c->unused = 0; } @@ -918,6 +930,7 @@ cipher_reset (gcry_cipher_hd_t c) memcpy (&c->context.c, (char *) &c->context.c + c->cipher->contextsize, c->cipher->contextsize); + memset (&c->marks, 0, sizeof c->marks); memset (c->u_iv.iv, 0, c->cipher->blocksize); memset (c->lastiv, 0, c->cipher->blocksize); memset (c->ctr, 0, c->cipher->blocksize); @@ -1391,63 +1404,241 @@ do_ctr_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, } +/* Perform the AES-Wrap algorithm as specified by RFC3394. We + implement this as a mode usable with any cipher algorithm of + blocksize 128. */ +static gcry_err_code_t +do_aeswrap_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, + const byte *inbuf, unsigned int inbuflen ) +{ + int j, x; + unsigned int n, i; + unsigned char *r, *a, *b; + unsigned char t[8]; + +#if MAX_BLOCKSIZE < 8 +#error Invalid block size +#endif + /* We require a cipher with a 128 bit block length. */ + if (c->cipher->blocksize != 16) + return GPG_ERR_INV_LENGTH; + + /* The output buffer must be able to hold the input data plus one + additional block. */ + if (outbuflen < inbuflen + 8) + return GPG_ERR_BUFFER_TOO_SHORT; + /* Input data must be multiple of 64 bits. */ + if (inbuflen % 8) + return GPG_ERR_INV_ARG; + + n = inbuflen / 8; + + /* We need at least two 64 bit blocks. */ + if (n < 2) + return GPG_ERR_INV_ARG; + + r = outbuf; + a = outbuf; /* We store A directly in OUTBUF. */ + b = c->ctr; /* B is also used to concatenate stuff. */ + + /* If an IV has been set we use that IV as the Alternative Initial + Value; if it has not been set we use the standard value. */ + if (c->marks.iv) + memcpy (a, c->u_iv.iv, 8); + else + memset (a, 0xa6, 8); + + /* Copy the inbuf to the outbuf. */ + memmove (r+8, inbuf, inbuflen); + + memset (t, 0, sizeof t); /* t := 0. */ + + for (j = 0; j <= 5; j++) + { + for (i = 1; i <= n; i++) + { + /* B := AES_k( A | R[i] ) */ + memcpy (b, a, 8); + memcpy (b+8, r+i*8, 8); + c->cipher->encrypt (&c->context.c, b, b); + /* t := t + 1 */ + for (x = 7; x >= 0; x--) + { + t[x]++; + if (t[x]) + break; + } + /* A := MSB_64(B) ^ t */ + for (x=0; x < 8; x++) + a[x] = b[x] ^ t[x]; + /* R[i] := LSB_64(B) */ + memcpy (r+i*8, b+8, 8); + } + } + + return 0; +} + +/* Perform the AES-Unwrap algorithm as specified by RFC3394. We + implement this as a mode usable with any cipher algorithm of + blocksize 128. */ +static gcry_err_code_t +do_aeswrap_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, + const byte *inbuf, unsigned int inbuflen) +{ + int j, x; + unsigned int n, i; + unsigned char *r, *a, *b; + unsigned char t[8]; + +#if MAX_BLOCKSIZE < 8 +#error Invalid block size +#endif + /* We require a cipher with a 128 bit block length. */ + if (c->cipher->blocksize != 16) + return GPG_ERR_INV_LENGTH; + + /* The output buffer must be able to hold the input data minus one + additional block. Fixme: The caller has more restrictive checks + - we may want to fix them for this mode. */ + if (outbuflen + 8 < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + /* Input data must be multiple of 64 bits. */ + if (inbuflen % 8) + return GPG_ERR_INV_ARG; + + n = inbuflen / 8; + + /* We need at least three 64 bit blocks. */ + if (n < 3) + return GPG_ERR_INV_ARG; + + r = outbuf; + a = c->lastiv; /* We use c->LASTIV as buffer for A. */ + b = c->ctr; /* B is also used to concatenate stuff. */ + + /* Copy the inbuf to the outbuf and save A. */ + memcpy (a, inbuf, 8); + memmove (r, inbuf+8, inbuflen-8); + n--; /* Reduce to actual number of data blocks. */ + + /* t := 6 * n */ + i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */ + for (x=0; x < 8 && x < sizeof (i); x++) + t[7-x] = i >> (8*x); + for (; x < 8; x++) + t[7-x] = 0; + + for (j = 5; j >= 0; j--) + { + for (i = n; i >= 1; i--) + { + /* B := AES_k^1( (A ^ t)| R[i] ) */ + for (x = 0; x < 8; x++) + b[x] = a[x] ^ t[x]; + memcpy (b+8, r+(i-1)*8, 8); + c->cipher->decrypt (&c->context.c, b, b); + /* t := t - 1 */ + for (x = 7; x >= 0; x--) + { + t[x]--; + if (t[x] != 0xff) + break; + } + /* A := MSB_64(B) */ + memcpy (a, b, 8); + /* R[i] := LSB_64(B) */ + memcpy (r+(i-1)*8, b+8, 8); + } + } + + /* If an IV has been set we compare against this Alternative Initial + Value; if it has not been set we compare against the standard IV. */ + if (c->marks.iv) + j = memcmp (a, c->u_iv.iv, 8); + else + { + for (j=0, x=0; x < 8; x++) + if (a[x] != 0xa6) + { + j=1; + break; + } + } + return j? GPG_ERR_CHECKSUM : 0; +} + + /**************** * Encrypt INBUF to OUTBUF with the mode selected at open. * inbuf and outbuf may overlap or be the same. - * Depending on the mode some constraints apply to NBYTES. + * Depending on the mode some constraints apply to INBUFLEN. */ static gcry_err_code_t -cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, - const byte *inbuf, unsigned int nbytes) +cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, + const byte *inbuf, unsigned int inbuflen) { - gcry_err_code_t rc = GPG_ERR_NO_ERROR; + gcry_err_code_t rc = 0; - switch( c->mode ) { - case GCRY_CIPHER_MODE_ECB: - if (!(nbytes%c->cipher->blocksize)) - do_ecb_encrypt(c, outbuf, inbuf, nbytes/c->cipher->blocksize ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CBC: - if (!(nbytes%c->cipher->blocksize) - || (nbytes > c->cipher->blocksize - && (c->flags & GCRY_CIPHER_CBC_CTS))) - do_cbc_encrypt(c, outbuf, inbuf, nbytes ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CFB: - do_cfb_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_OFB: - do_ofb_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_CTR: - do_ctr_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_STREAM: - c->cipher->stencrypt ( &c->context.c, - outbuf, (byte*)/*arggg*/inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_NONE: - if (fips_mode () || !_gcry_get_debug_flag (0)) - { - fips_signal_error ("cipher mode NONE used"); - rc = GPG_ERR_INV_CIPHER_MODE; - } - else - { - if ( inbuf != outbuf ) - memmove (outbuf, inbuf, nbytes); - } - break; - default: - log_fatal("cipher_encrypt: invalid mode %d\n", c->mode ); - rc = GPG_ERR_INV_CIPHER_MODE; - break; + switch (c->mode) + { + case GCRY_CIPHER_MODE_ECB: + if (!(inbuflen % c->cipher->blocksize)) + do_ecb_encrypt(c, outbuf, inbuf, inbuflen/c->cipher->blocksize ); + else + rc = GPG_ERR_INV_ARG; + break; + + case GCRY_CIPHER_MODE_CBC: + if (!(inbuflen % c->cipher->blocksize) + || (inbuflen > c->cipher->blocksize + && (c->flags & GCRY_CIPHER_CBC_CTS))) + do_cbc_encrypt(c, outbuf, inbuf, inbuflen ); + else + rc = GPG_ERR_INV_ARG; + break; + + case GCRY_CIPHER_MODE_CFB: + do_cfb_encrypt(c, outbuf, inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_OFB: + do_ofb_encrypt(c, outbuf, inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_CTR: + do_ctr_encrypt(c, outbuf, inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_AESWRAP: + rc = do_aeswrap_encrypt (c, outbuf, outbuflen, inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_STREAM: + c->cipher->stencrypt (&c->context.c, + outbuf, (byte*)/*arggg*/inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) + { + fips_signal_error ("cipher mode NONE used"); + rc = GPG_ERR_INV_CIPHER_MODE; + } + else + { + if ( inbuf != outbuf ) + memmove (outbuf, inbuf, inbuflen); + } + break; + + default: + log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; } - return rc; + + return rc; } @@ -1463,14 +1654,12 @@ gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, if (!in) { - /* Caller requested in-place encryption. */ - /* Actually cipher_encrypt() does not need to know about it, but - * we may change it in the future to get better performance. */ - err = cipher_encrypt (h, out, out, outsize); + /* Caller requested in-place encryption. */ + err = cipher_encrypt (h, out, outsize, out, outsize); } else if (outsize < ((h->flags & GCRY_CIPHER_CBC_MAC) ? h->cipher->blocksize : inlen)) - err = GPG_ERR_TOO_SHORT; + err = GPG_ERR_BUFFER_TOO_SHORT; else if ((h->mode == GCRY_CIPHER_MODE_ECB || (h->mode == GCRY_CIPHER_MODE_CBC && (! ((h->flags & GCRY_CIPHER_CBC_CTS) @@ -1478,12 +1667,12 @@ gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, && (inlen % h->cipher->blocksize)) err = GPG_ERR_INV_ARG; else - err = cipher_encrypt (h, out, in, inlen); + err = cipher_encrypt (h, out, outsize, in, inlen); + /* Failsafe: Make sure that the plaintext will never make it into + OUT if the encryption returned an error. */ if (err && out) - memset (out, 0x42, outsize); /* Failsafe: Make sure that the - plaintext will never make it into - OUT. */ + memset (out, 0x42, outsize); return gcry_error (err); } @@ -1496,57 +1685,70 @@ gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, * Depending on the mode some some contraints apply to NBYTES. */ static gcry_err_code_t -cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nbytes) +cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, + const byte *inbuf, unsigned int inbuflen) { - gcry_err_code_t rc = GPG_ERR_NO_ERROR; + gcry_err_code_t rc = 0; - switch( c->mode ) { - case GCRY_CIPHER_MODE_ECB: - if (!(nbytes%c->cipher->blocksize)) - do_ecb_decrypt(c, outbuf, inbuf, nbytes/c->cipher->blocksize ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CBC: - if (!(nbytes%c->cipher->blocksize) - || (nbytes > c->cipher->blocksize - && (c->flags & GCRY_CIPHER_CBC_CTS))) - do_cbc_decrypt(c, outbuf, inbuf, nbytes ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CFB: - do_cfb_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_OFB: - do_ofb_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_CTR: - do_ctr_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_STREAM: - c->cipher->stdecrypt ( &c->context.c, - outbuf, (byte*)/*arggg*/inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_NONE: - if (fips_mode () || !_gcry_get_debug_flag (0)) - { - fips_signal_error ("cipher mode NONE used"); - rc = GPG_ERR_INV_CIPHER_MODE; - } - else - { - if (inbuf != outbuf) - memmove (outbuf, inbuf, nbytes); - } - break; - default: - log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); - rc = GPG_ERR_INV_CIPHER_MODE; - break; + switch (c->mode) + { + case GCRY_CIPHER_MODE_ECB: + if (!(inbuflen % c->cipher->blocksize)) + do_ecb_decrypt (c, outbuf, inbuf, inbuflen/c->cipher->blocksize ); + else + rc = GPG_ERR_INV_ARG; + break; + + case GCRY_CIPHER_MODE_CBC: + if (!(inbuflen % c->cipher->blocksize) + || (inbuflen > c->cipher->blocksize + && (c->flags & GCRY_CIPHER_CBC_CTS))) + do_cbc_decrypt (c, outbuf, inbuf, inbuflen ); + else + rc = GPG_ERR_INV_ARG; + break; + + case GCRY_CIPHER_MODE_CFB: + do_cfb_decrypt (c, outbuf, inbuf, inbuflen ); + + break; + case GCRY_CIPHER_MODE_OFB: + do_ofb_decrypt (c, outbuf, inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_CTR: + do_ctr_decrypt (c, outbuf, inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_AESWRAP: + rc = do_aeswrap_decrypt (c, outbuf, outbuflen, inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_STREAM: + c->cipher->stdecrypt (&c->context.c, + outbuf, (byte*)/*arggg*/inbuf, inbuflen ); + break; + + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) + { + fips_signal_error ("cipher mode NONE used"); + rc = GPG_ERR_INV_CIPHER_MODE; + } + else + { + if (inbuf != outbuf) + memmove (outbuf, inbuf, inbuflen); + } + break; + + default: + log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; } - return rc; + + return rc; } @@ -1559,12 +1761,15 @@ gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize, if (!in) { /* Caller requested in-place encryption. */ - /* Actually cipher_encrypt() does not need to know about it, but - * we may change it in the future to get better performance. */ - err = cipher_decrypt (h, out, out, outsize); + err = cipher_decrypt (h, out, outsize, out, outsize); + } + else if (outsize < inlen && h->mode != GCRY_CIPHER_MODE_AESWRAP) + { + /* Note that do_aeswrap_decrypt does its own length checking. + Fixme: we should move all buffer length checkings to teh + actual decryption functions. */ + err = GPG_ERR_BUFFER_TOO_SHORT; } - else if (outsize < inlen) - err = GPG_ERR_TOO_SHORT; else if (((h->mode == GCRY_CIPHER_MODE_ECB) || ((h->mode == GCRY_CIPHER_MODE_CBC) && (! ((h->flags & GCRY_CIPHER_CBC_CTS) @@ -1572,7 +1777,7 @@ gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize, && (inlen % h->cipher->blocksize) != 0) err = GPG_ERR_INV_ARG; else - err = cipher_decrypt (h, out, in, inlen); + err = cipher_decrypt (h, out, outsize, in, inlen); return gcry_error (err); } diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 6cb4bddf..5e736244 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1644,6 +1644,20 @@ Output Feedback mode. @cindex CTR, Counter mode Counter mode. +@item GCRY_CIPHER_MODE_AESWRAP +@cindex AES-Wrap mode +This mode is used to implement the AES-Wrap algorithm according to +RFC-3394. It may be used with any 128 bit block length algorithm, +however the specs require one of the 3 AES algorithms. These special +conditions apply: If @code{gcry_cipher_setiv} has not been used the +standard IV is used; if it has been used the lower 64 bit of the IV +are used as the Alternative Initial Value. On encryption the provided +output buffer must be 64 bit (8 byte) larger than the input buffer; +in-place encryption is still allowed. On decryption the output buffer +may be specified 64 bit (8 byte) shorter than then input buffer. As +per specs the input length must be at least 128 bits and the length +must be a multiple of 64 bits. + @end table @node Working with cipher handles diff --git a/src/ChangeLog b/src/ChangeLog index c883d05e..bfd616de 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2009-12-08 Werner Koch <wk@g10code.com> + + * gcrypt.h.in (GCRY_CIPHER_MODE_AESWRAP): New. + 2009-12-08 Marcus Brinkmann <marcus@g10code.de> * Makefile.am (LTRCCOMPILE): Refactor with ... diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 37390b21..33dc1456 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -849,7 +849,8 @@ enum gcry_cipher_modes GCRY_CIPHER_MODE_CBC = 3, /* Cipher block chaining. */ GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ - GCRY_CIPHER_MODE_CTR = 6 /* Counter. */ + GCRY_CIPHER_MODE_CTR = 6, /* Counter. */ + GCRY_CIPHER_MODE_AESWRAP= 7 /* AES-WRAP algorithm. */ }; /* Flags used with the open function. */ diff --git a/tests/ChangeLog b/tests/ChangeLog index c3376ddd..c8332a6e 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2009-12-09 Werner Koch <wk@g10code.com> + + * aeswrap.c: New. + 2009-07-09 Werner Koch <wk@g10code.com> * benchmark.c (progress_cb): New. diff --git a/tests/Makefile.am b/tests/Makefile.am index 1288aad3..b2c12398 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -19,7 +19,7 @@ ## Process this file with automake to produce Makefile.in TESTS = version t-mpi-bit prime register ac ac-schemes ac-data basic \ - mpitests tsexp keygen pubkey hmac keygrip fips186-dsa + mpitests tsexp keygen pubkey hmac keygrip fips186-dsa aeswrap # random.c uses fork() thus a test for W32 does not make any sense. diff --git a/tests/aeswrap.c b/tests/aeswrap.c new file mode 100644 index 00000000..a8f5a5b0 --- /dev/null +++ b/tests/aeswrap.c @@ -0,0 +1,259 @@ +/* aeswrap.c - AESWRAP mode regression tests + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "../src/gcrypt.h" + +static int verbose; +static int error_count; + +static void +fail (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + error_count++; +} + +static void +die (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + exit (1); +} + + + +static void +check (int algo, + const void *kek, size_t keklen, + const void *data, size_t datalen, + const void *expected, size_t expectedlen) +{ + gcry_error_t err; + gcry_cipher_hd_t hd; + unsigned char outbuf[32+8]; + size_t outbuflen; + + err = gcry_cipher_open (&hd, algo, GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) + { + fail ("gcrypt_cipher_open failed: %s\n", gpg_strerror (err)); + return; + } + + err = gcry_cipher_setkey (hd, kek, keklen); + if (err) + { + fail ("grcy_cipher_setkey failed: %s\n", gpg_strerror (err)); + return; + } + + outbuflen = datalen + 8; + if (outbuflen > sizeof outbuf) + err = gpg_error (GPG_ERR_INTERNAL); + else + err = gcry_cipher_encrypt (hd, outbuf, outbuflen, data, datalen); + if (err) + { + fail ("grcy_cipher_encrypt failed: %s\n", gpg_strerror (err)); + return; + } + + if (outbuflen != expectedlen || memcmp (outbuf, expected, expectedlen)) + { + const unsigned char *s; + int i; + + fail ("mismatch at encryption!\n"); + fprintf (stderr, "computed: "); + for (i = 0; i < outbuflen; i++) + fprintf (stderr, "%02x ", outbuf[i]); + fprintf (stderr, "\nexpected: "); + for (s = expected, i = 0; i < expectedlen; s++, i++) + fprintf (stderr, "%02x ", *s); + putc ('\n', stderr); + } + + + outbuflen = expectedlen - 8; + if (outbuflen > sizeof outbuf) + err = gpg_error (GPG_ERR_INTERNAL); + else + err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen); + if (err) + { + fail ("grcy_cipher_decrypt failed: %s\n", gpg_strerror (err)); + return; + } + + if (outbuflen != datalen || memcmp (outbuf, data, datalen)) + { + const unsigned char *s; + int i; + + fail ("mismatch at decryption!\n"); + fprintf (stderr, "computed: "); + for (i = 0; i < outbuflen; i++) + fprintf (stderr, "%02x ", outbuf[i]); + fprintf (stderr, "\nexpected: "); + for (s = data, i = 0; i < datalen; s++, i++) + fprintf (stderr, "%02x ", *s); + putc ('\n', stderr); + } + + /* Now the last step again with a key reset. */ + gcry_cipher_reset (hd); + + outbuflen = expectedlen - 8; + if (outbuflen > sizeof outbuf) + err = gpg_error (GPG_ERR_INTERNAL); + else + err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen); + if (err) + { + fail ("grcy_cipher_decrypt(2) failed: %s\n", gpg_strerror (err)); + return; + } + + if (outbuflen != datalen || memcmp (outbuf, data, datalen)) + fail ("mismatch at decryption(2)!\n"); + + /* And once ore without a key reset. */ + outbuflen = expectedlen - 8; + if (outbuflen > sizeof outbuf) + err = gpg_error (GPG_ERR_INTERNAL); + else + err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen); + if (err) + { + fail ("grcy_cipher_decrypt(3) failed: %s\n", gpg_strerror (err)); + return; + } + + if (outbuflen != datalen || memcmp (outbuf, data, datalen)) + fail ("mismatch at decryption(3)!\n"); + + gcry_cipher_close (hd); +} + + +static void +check_all (void) +{ + if (verbose) + fprintf (stderr, "4.1 Wrap 128 bits of Key Data with a 128-bit KEK\n"); + check + (GCRY_CIPHER_AES128, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", 16, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF", 16, + "\x1F\xA6\x8B\x0A\x81\x12\xB4\x47\xAE\xF3\x4B\xD8\xFB\x5A\x7B\x82" + "\x9D\x3E\x86\x23\x71\xD2\xCF\xE5", 24); + + if (verbose) + fprintf (stderr, "4.2 Wrap 128 bits of Key Data with a 192-bit KEK\n"); + check + (GCRY_CIPHER_AES192, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17", 24, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF", 16, + "\x96\x77\x8B\x25\xAE\x6C\xA4\x35\xF9\x2B\x5B\x97\xC0\x50\xAE\xD2" + "\x46\x8A\xB8\xA1\x7A\xD8\x4E\x5D", 24); + + if (verbose) + fprintf (stderr, "4.3 Wrap 128 bits of Key Data with a 256-bit KEK\n"); + check + (GCRY_CIPHER_AES256, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 32, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF", 16, + "\x64\xE8\xC3\xF9\xCE\x0F\x5B\xA2\x63\xE9\x77\x79\x05\x81\x8A\x2A" + "\x93\xC8\x19\x1E\x7D\x6E\x8A\xE7", 24); + + if (verbose) + fprintf (stderr, "4.4 Wrap 192 bits of Key Data with a 192-bit KEK\n"); + check + (GCRY_CIPHER_AES192, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17", 24, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" + "\x00\x01\x02\x03\x04\x05\x06\x07", 24, + "\x03\x1D\x33\x26\x4E\x15\xD3\x32\x68\xF2\x4E\xC2\x60\x74\x3E\xDC" + "\xE1\xC6\xC7\xDD\xEE\x72\x5A\x93\x6B\xA8\x14\x91\x5C\x67\x62\xD2", 32); + + if (verbose) + fprintf (stderr, "4.5 Wrap 192 bits of Key Data with a 256-bit KEK\n"); + check + (GCRY_CIPHER_AES256, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 32, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" + "\x00\x01\x02\x03\x04\x05\x06\x07", 24, + "\xA8\xF9\xBC\x16\x12\xC6\x8B\x3F\xF6\xE6\xF4\xFB\xE3\x0E\x71\xE4" + "\x76\x9C\x8B\x80\xA3\x2C\xB8\x95\x8C\xD5\xD1\x7D\x6B\x25\x4D\xA1", 32); + + if (verbose) + fprintf (stderr, "4.6 Wrap 256 bits of Key Data with a 256-bit KEK\n"); + check + (GCRY_CIPHER_AES, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 32, + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", 32, + "\x28\xC9\xF4\x04\xC4\xB8\x10\xF4\xCB\xCC\xB3\x5C\xFB\x87\xF8\x26" + "\x3F\x57\x86\xE2\xD8\x0E\xD3\x26\xCB\xC7\xF0\xE7\x1A\x99\xF4\x3B" + "\xFB\x98\x8B\x9B\x7A\x02\xDD\x21", 40); +} + +int +main (int argc, char **argv) +{ + int debug = 0; + + if (argc > 1 && !strcmp (argv[1], "--verbose")) + verbose = 1; + else if (argc > 1 && !strcmp (argv[1], "--debug")) + verbose = debug = 1; + + if (!gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch\n"); + + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + if (debug) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); + check_all (); + + return error_count ? 1 : 0; +} diff --git a/tests/benchmark.c b/tests/benchmark.c index 17199e50..83ddf373 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -1092,7 +1092,8 @@ main( int argc, char **argv ) if (use_random_daemon) gcry_control (GCRYCTL_USE_RANDOM_DAEMON, 1); - gcry_set_progress_handler (progress_cb, NULL); + if (with_progress) + gcry_set_progress_handler (progress_cb, NULL); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); |