summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2009-12-09 11:21:17 +0000
committerWerner Koch <wk@gnupg.org>2009-12-09 11:21:17 +0000
commit3147b0eb8c0c42e4c77c4b4405be5e3f1af74534 (patch)
treed5867a6c2cefc2bf5d1422396a0377dcdcb4eb61
parent379ba9a761d1fa259e673ed9552fc2e73b5b2ea3 (diff)
downloadlibgcrypt-3147b0eb8c0c42e4c77c4b4405be5e3f1af74534.tar.gz
Implemented the AES-Wrap algorithm
-rw-r--r--NEWS6
-rw-r--r--cipher/ChangeLog13
-rw-r--r--cipher/cipher.c429
-rw-r--r--doc/gcrypt.texi14
-rw-r--r--src/ChangeLog4
-rw-r--r--src/gcrypt.h.in3
-rw-r--r--tests/ChangeLog4
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/aeswrap.c259
-rw-r--r--tests/benchmark.c3
10 files changed, 622 insertions, 115 deletions
diff --git a/NEWS b/NEWS
index a9812241..ba2c3abc 100644
--- a/NEWS
+++ b/NEWS
@@ -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);