summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cipher/Makefile.am1
-rw-r--r--cipher/cipher-ccm.c370
-rw-r--r--cipher/cipher-internal.h48
-rw-r--r--cipher/cipher.c107
-rw-r--r--doc/gcrypt.texi16
-rw-r--r--src/gcrypt.h.in8
-rw-r--r--tests/basic.c771
-rw-r--r--tests/benchmark.c80
8 files changed, 1376 insertions, 25 deletions
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index a2b2c8af..b0efd89d 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -40,6 +40,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES)
libcipher_la_SOURCES = \
cipher.c cipher-internal.h \
cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \
+cipher-ccm.c \
cipher-selftest.c cipher-selftest.h \
pubkey.c pubkey-internal.h pubkey-util.c \
md.c \
diff --git a/cipher/cipher-ccm.c b/cipher/cipher-ccm.c
new file mode 100644
index 00000000..38752d5d
--- /dev/null
+++ b/cipher/cipher-ccm.c
@@ -0,0 +1,370 @@
+/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "cipher.h"
+#include "ath.h"
+#include "bufhelp.h"
+#include "./cipher-internal.h"
+
+
+#define set_burn(burn, nburn) do { \
+ unsigned int __nburn = (nburn); \
+ (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0)
+
+
+static unsigned int
+do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen,
+ int do_padding)
+{
+ const unsigned int blocksize = 16;
+ unsigned char tmp[blocksize];
+ unsigned int burn = 0;
+ unsigned int unused = c->u_mode.ccm.mac_unused;
+ size_t nblocks;
+
+ if (inlen == 0 && (unused == 0 || !do_padding))
+ return 0;
+
+ do
+ {
+ if (inlen + unused < blocksize || unused > 0)
+ {
+ for (; inlen && unused < blocksize; inlen--)
+ c->u_mode.ccm.macbuf[unused++] = *inbuf++;
+ }
+ if (!inlen)
+ {
+ if (!do_padding)
+ break;
+
+ while (unused < blocksize)
+ c->u_mode.ccm.macbuf[unused++] = 0;
+ }
+
+ if (unused > 0)
+ {
+ /* Process one block from macbuf. */
+ buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize);
+ set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv,
+ c->u_iv.iv ));
+
+ unused = 0;
+ }
+
+ if (c->bulk.cbc_enc)
+ {
+ nblocks = inlen / blocksize;
+ c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1);
+ inbuf += nblocks * blocksize;
+ inlen -= nblocks * blocksize;
+
+ wipememory (tmp, sizeof(tmp));
+ }
+ else
+ {
+ while (inlen >= blocksize)
+ {
+ buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
+
+ set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_iv.iv,
+ c->u_iv.iv ));
+
+ inlen -= blocksize;
+ inbuf += blocksize;
+ }
+ }
+ }
+ while (inlen > 0);
+
+ c->u_mode.ccm.mac_unused = unused;
+
+ if (burn)
+ burn += 4 * sizeof(void *);
+
+ return burn;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
+ size_t noncelen)
+{
+ size_t L = 15 - noncelen;
+ size_t L_;
+
+ L_ = L - 1;
+
+ if (!nonce)
+ return GPG_ERR_INV_ARG;
+ /* Length field must be 2, 3, ..., or 8. */
+ if (L < 2 || L > 8)
+ return GPG_ERR_INV_LENGTH;
+
+ /* Reset state */
+ memset (&c->u_mode, 0, sizeof(c->u_mode));
+ memset (&c->marks, 0, sizeof(c->marks));
+ memset (&c->u_iv, 0, sizeof(c->u_iv));
+ memset (&c->u_ctr, 0, sizeof(c->u_ctr));
+ memset (c->lastiv, 0, sizeof(c->lastiv));
+ c->unused = 0;
+
+ /* Setup CTR */
+ c->u_ctr.ctr[0] = L_;
+ memcpy (&c->u_ctr.ctr[1], nonce, noncelen);
+ memset (&c->u_ctr.ctr[1 + noncelen], 0, L);
+
+ /* Setup IV */
+ c->u_iv.iv[0] = L_;
+ memcpy (&c->u_iv.iv[1], nonce, noncelen);
+ /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later
+ in set_aad. */
+ memset (&c->u_iv.iv[1 + noncelen], 0, L);
+
+ c->u_mode.ccm.nonce = 1;
+
+ return GPG_ERR_NO_ERROR;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_set_lengths (gcry_cipher_hd_t c, size_t encryptlen,
+ size_t aadlen, size_t taglen)
+{
+ unsigned int burn = 0;
+ unsigned char b0[16];
+ size_t noncelen = 15 - (c->u_iv.iv[0] + 1);
+ size_t M = taglen;
+ size_t M_;
+ int i;
+
+ M_ = (M - 2) / 2;
+
+ /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */
+ if ((M_ * 2 + 2) != M || M < 4 || M > 16)
+ return GPG_ERR_INV_LENGTH;
+ if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag)
+ return GPG_ERR_INV_STATE;
+ if (c->u_mode.ccm.lengths)
+ return GPG_ERR_INV_STATE;
+
+ c->u_mode.ccm.authlen = taglen;
+ c->u_mode.ccm.encryptlen = encryptlen;
+ c->u_mode.ccm.aadlen = aadlen;
+
+ /* Complete IV setup. */
+ c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8;
+ for (i = 16 - 1; i >= 1 + noncelen; i--)
+ {
+ c->u_iv.iv[i] = encryptlen & 0xff;
+ encryptlen >>= 8;
+ }
+
+ memcpy (b0, c->u_iv.iv, 16);
+ memset (c->u_iv.iv, 0, 16);
+
+ set_burn (burn, do_cbc_mac (c, b0, 16, 0));
+
+ if (aadlen == 0)
+ {
+ /* Do nothing. */
+ }
+ else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff)
+ {
+ b0[0] = (aadlen >> 8) & 0xff;
+ b0[1] = aadlen & 0xff;
+ set_burn (burn, do_cbc_mac (c, b0, 2, 0));
+ }
+ else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff)
+ {
+ b0[0] = 0xff;
+ b0[1] = 0xfe;
+ buf_put_be32(&b0[2], aadlen);
+ set_burn (burn, do_cbc_mac (c, b0, 6, 0));
+ }
+#ifdef HAVE_U64_TYPEDEF
+ else if (aadlen > (unsigned int)0xffffffff)
+ {
+ b0[0] = 0xff;
+ b0[1] = 0xff;
+ buf_put_be64(&b0[2], aadlen);
+ set_burn (burn, do_cbc_mac (c, b0, 10, 0));
+ }
+#endif
+
+ /* Generate S_0 and increase counter. */
+ set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0,
+ c->u_ctr.ctr ));
+ c->u_ctr.ctr[15]++;
+
+ if (burn)
+ _gcry_burn_stack (burn + sizeof(void *) * 5);
+
+ c->u_mode.ccm.lengths = 1;
+
+ return GPG_ERR_NO_ERROR;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf,
+ size_t abuflen)
+{
+ unsigned int burn;
+
+ if (abuflen > 0 && !abuf)
+ return GPG_ERR_INV_ARG;
+ if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.tag)
+ return GPG_ERR_INV_STATE;
+ if (abuflen > c->u_mode.ccm.aadlen)
+ return GPG_ERR_INV_LENGTH;
+
+ c->u_mode.ccm.aadlen -= abuflen;
+ burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0);
+
+ if (burn)
+ _gcry_burn_stack (burn + sizeof(void *) * 5);
+
+ return GPG_ERR_NO_ERROR;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf,
+ size_t outbuflen, int check)
+{
+ unsigned int burn;
+
+ if (!outbuf || outbuflen == 0)
+ return GPG_ERR_INV_ARG;
+ /* Tag length must be same as initial authlen. */
+ if (c->u_mode.ccm.authlen != outbuflen)
+ return GPG_ERR_INV_LENGTH;
+ if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.aadlen > 0)
+ return GPG_ERR_INV_STATE;
+ /* Initial encrypt length must match with length of actual data processed. */
+ if (c->u_mode.ccm.encryptlen > 0)
+ return GPG_ERR_UNFINISHED;
+
+ if (!c->u_mode.ccm.tag)
+ {
+ burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */
+
+ /* Add S_0 */
+ buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16);
+
+ wipememory (c->u_ctr.ctr, 16);
+ wipememory (c->u_mode.ccm.s0, 16);
+ wipememory (c->u_mode.ccm.macbuf, 16);
+
+ if (burn)
+ _gcry_burn_stack (burn + sizeof(void *) * 5);
+ }
+
+ if (!check)
+ {
+ memcpy (outbuf, c->u_iv.iv, outbuflen);
+ return GPG_ERR_NO_ERROR;
+ }
+ else
+ {
+ int diff, i;
+
+ /* Constant-time compare. */
+ for (i = 0, diff = 0; i < outbuflen; i++)
+ diff -= !!(outbuf[i] - c->u_iv.iv[i]);
+
+ return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
+ }
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
+ size_t taglen)
+{
+ return _gcry_cipher_ccm_tag (c, outtag, taglen, 0);
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
+ size_t taglen)
+{
+ return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1);
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
+ unsigned int outbuflen, const unsigned char *inbuf,
+ unsigned int inbuflen)
+{
+ unsigned int burn;
+
+ if (outbuflen < inbuflen)
+ return GPG_ERR_BUFFER_TOO_SHORT;
+ if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.lengths ||
+ c->u_mode.ccm.aadlen > 0)
+ return GPG_ERR_INV_STATE;
+ if (inbuflen > c->u_mode.ccm.encryptlen)
+ return GPG_ERR_INV_LENGTH;
+
+ c->u_mode.ccm.encryptlen -= inbuflen;
+ burn = do_cbc_mac (c, inbuf, inbuflen, 0);
+ if (burn)
+ _gcry_burn_stack (burn + sizeof(void *) * 5);
+
+ return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
+ unsigned int outbuflen, const unsigned char *inbuf,
+ unsigned int inbuflen)
+{
+ gcry_err_code_t err;
+ unsigned int burn;
+
+ if (outbuflen < inbuflen)
+ return GPG_ERR_BUFFER_TOO_SHORT;
+ if (!c->u_mode.ccm.nonce || c->u_mode.ccm.tag || !c->u_mode.ccm.lengths ||
+ c->u_mode.ccm.aadlen > 0)
+ return GPG_ERR_INV_STATE;
+ if (inbuflen > c->u_mode.ccm.encryptlen)
+ return GPG_ERR_INV_LENGTH;
+
+ err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+ if (err)
+ return err;
+
+ c->u_mode.ccm.encryptlen -= inbuflen;
+ burn = do_cbc_mac (c, outbuf, inbuflen, 0);
+ if (burn)
+ _gcry_burn_stack (burn + sizeof(void *) * 5);
+
+ return err;
+}
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index b60ef386..981caa83 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -100,7 +100,8 @@ struct gcry_cipher_handle
/* The initialization vector. For best performance we make sure
that it is properly aligned. In particular some implementations
- of bulk operations expect an 16 byte aligned IV. */
+ of bulk operations expect an 16 byte aligned IV. IV is also used
+ to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. */
union {
cipher_context_alignment_t iv_align;
unsigned char iv[MAX_BLOCKSIZE];
@@ -117,6 +118,26 @@ struct gcry_cipher_handle
unsigned char lastiv[MAX_BLOCKSIZE];
int unused; /* Number of unused bytes in LASTIV. */
+ union {
+ /* Mode specific storage for CCM mode. */
+ struct {
+ size_t encryptlen;
+ size_t aadlen;
+ unsigned int authlen;
+
+ /* Space to save partial input lengths for MAC. */
+ unsigned char macbuf[GCRY_CCM_BLOCK_LEN];
+ int mac_unused; /* Number of unprocessed bytes in MACBUF. */
+
+ unsigned char s0[GCRY_CCM_BLOCK_LEN];
+
+ unsigned int nonce:1;/* Set to 1 if nonce has been set. */
+ unsigned int lengths:1; /* Set to 1 if CCM length parameters has been
+ processed. */
+ unsigned int tag:1; /* Set to 1 if tag has been finalized. */
+ } ccm;
+ } u_mode;
+
/* What follows are two contexts of the cipher in use. The first
one needs to be aligned well enough for the cipher operation
whereas the second one is a copy created by cipher_setkey and
@@ -175,5 +196,30 @@ gcry_err_code_t _gcry_cipher_aeswrap_decrypt
const byte *inbuf, unsigned int inbuflen);
+/*-- cipher-ccm.c --*/
+gcry_err_code_t _gcry_cipher_ccm_encrypt
+/* */ (gcry_cipher_hd_t c,
+ unsigned char *outbuf, unsigned int outbuflen,
+ const unsigned char *inbuf, unsigned int inbuflen);
+gcry_err_code_t _gcry_cipher_ccm_decrypt
+/* */ (gcry_cipher_hd_t c,
+ unsigned char *outbuf, unsigned int outbuflen,
+ const unsigned char *inbuf, unsigned int inbuflen);
+gcry_err_code_t _gcry_cipher_ccm_set_nonce
+/* */ (gcry_cipher_hd_t c, const unsigned char *nonce,
+ size_t noncelen);
+gcry_err_code_t _gcry_cipher_ccm_authenticate
+/* */ (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen);
+gcry_err_code_t _gcry_cipher_ccm_set_lengths
+/* */ (gcry_cipher_hd_t c, size_t encryptedlen, size_t aadlen,
+ size_t taglen);
+gcry_err_code_t _gcry_cipher_ccm_get_tag
+/* */ (gcry_cipher_hd_t c,
+ unsigned char *outtag, size_t taglen);
+gcry_err_code_t _gcry_cipher_ccm_check_tag
+/* */ (gcry_cipher_hd_t c,
+ const unsigned char *intag, size_t taglen);
+
+
#endif /*G10_CIPHER_INTERNAL_H*/
diff --git a/cipher/cipher.c b/cipher/cipher.c
index d6d3021c..5214d26c 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -375,6 +375,13 @@ gcry_cipher_open (gcry_cipher_hd_t *handle,
if (! err)
switch (mode)
{
+ case GCRY_CIPHER_MODE_CCM:
+ if (spec->blocksize != GCRY_CCM_BLOCK_LEN)
+ err = GPG_ERR_INV_CIPHER_MODE;
+ if (!spec->encrypt || !spec->decrypt)
+ err = GPG_ERR_INV_CIPHER_MODE;
+ break;
+
case GCRY_CIPHER_MODE_ECB:
case GCRY_CIPHER_MODE_CBC:
case GCRY_CIPHER_MODE_CFB:
@@ -613,6 +620,8 @@ cipher_reset (gcry_cipher_hd_t c)
memset (c->u_iv.iv, 0, c->spec->blocksize);
memset (c->lastiv, 0, c->spec->blocksize);
memset (c->u_ctr.ctr, 0, c->spec->blocksize);
+ memset (&c->u_mode, 0, sizeof c->u_mode);
+ c->unused = 0;
}
@@ -718,6 +727,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen,
inbuf, inbuflen);
break;
+ case GCRY_CIPHER_MODE_CCM:
+ rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
c->spec->stencrypt (&c->context.c,
outbuf, (byte*)/*arggg*/inbuf, inbuflen);
@@ -811,6 +824,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen,
inbuf, inbuflen);
break;
+ case GCRY_CIPHER_MODE_CCM:
+ rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
c->spec->stdecrypt (&c->context.c,
outbuf, (byte*)/*arggg*/inbuf, inbuflen);
@@ -885,8 +902,19 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen)
gcry_error_t
_gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen)
{
- cipher_setiv (hd, iv, ivlen);
- return 0;
+ gcry_err_code_t rc = GPG_ERR_NO_ERROR;
+
+ switch (hd->mode)
+ {
+ case GCRY_CIPHER_MODE_CCM:
+ rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen);
+ break;
+
+ default:
+ cipher_setiv (hd, iv, ivlen);
+ break;
+ }
+ return gpg_error (rc);
}
/* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of
@@ -914,34 +942,61 @@ gcry_error_t
_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf,
size_t abuflen)
{
- log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode);
+ gcry_err_code_t rc;
+
+ switch (hd->mode)
+ {
+ case GCRY_CIPHER_MODE_CCM:
+ rc = _gcry_cipher_ccm_authenticate (hd, abuf, abuflen);
+ break;
- (void)abuf;
- (void)abuflen;
+ default:
+ log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode);
+ rc = GPG_ERR_INV_CIPHER_MODE;
+ break;
+ }
- return gpg_error (GPG_ERR_INV_CIPHER_MODE);
+ return gpg_error (rc);
}
gcry_error_t
_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen)
{
- log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode);
+ gcry_err_code_t rc;
+
+ switch (hd->mode)
+ {
+ case GCRY_CIPHER_MODE_CCM:
+ rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen);
+ break;
- (void)outtag;
- (void)taglen;
+ default:
+ log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode);
+ rc = GPG_ERR_INV_CIPHER_MODE;
+ break;
+ }
- return gpg_error (GPG_ERR_INV_CIPHER_MODE);
+ return gpg_error (rc);
}
gcry_error_t
_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen)
{
- log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode);
+ gcry_err_code_t rc;
+
+ switch (hd->mode)
+ {
+ case GCRY_CIPHER_MODE_CCM:
+ rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen);
+ break;
- (void)intag;
- (void)taglen;
+ default:
+ log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode);
+ rc = GPG_ERR_INV_CIPHER_MODE;
+ break;
+ }
- return gpg_error (GPG_ERR_INV_CIPHER_MODE);
+ return gpg_error (rc);
}
@@ -980,6 +1035,30 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
h->flags &= ~GCRY_CIPHER_CBC_MAC;
break;
+ case GCRYCTL_SET_CCM_LENGTHS:
+ {
+ size_t params[3];
+ size_t encryptedlen;
+ size_t aadlen;
+ size_t authtaglen;
+
+ if (h->mode != GCRY_CIPHER_MODE_CCM)
+ return gcry_error (GPG_ERR_INV_CIPHER_MODE);
+
+ if (!buffer || buflen != 3 * sizeof(size_t))
+ return gcry_error (GPG_ERR_INV_ARG);
+
+ /* This command is used to pass additional length parameters needed
+ by CCM mode to initialize CBC-MAC. */
+ memcpy (params, buffer, sizeof(params));
+ encryptedlen = params[0];
+ aadlen = params[1];
+ authtaglen = params[2];
+
+ rc = _gcry_cipher_ccm_set_lengths (h, encryptedlen, aadlen, authtaglen);
+ }
+ break;
+
case GCRYCTL_DISABLE_ALGO:
/* This command expects NULL for H and BUFFER to point to an
integer with the algo number. */
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 0049fa04..91fe399c 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -1635,6 +1635,12 @@ 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.
+@item GCRY_CIPHER_MODE_CCM
+@cindex CCM, Counter with CBC-MAC mode
+Counter with CBC-MAC mode is an Authenticated Encryption with
+Associated Data (AEAD) block cipher mode, which is specified in
+'NIST Special Publication 800-38C' and RFC 3610.
+
@end table
@node Working with cipher handles
@@ -1661,11 +1667,13 @@ The cipher mode to use must be specified via @var{mode}. See
@xref{Available cipher modes}, for a list of supported cipher modes
and the according constants. Note that some modes are incompatible
with some algorithms - in particular, stream mode
-(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. Any
-block cipher mode (@code{GCRY_CIPHER_MODE_ECB},
+(@code{GCRY_CIPHER_MODE_STREAM}) only works with stream ciphers. The
+block cipher modes (@code{GCRY_CIPHER_MODE_ECB},
@code{GCRY_CIPHER_MODE_CBC}, @code{GCRY_CIPHER_MODE_CFB},
-@code{GCRY_CIPHER_MODE_OFB} or @code{GCRY_CIPHER_MODE_CTR}) will work
-with any block cipher algorithm.
+@code{GCRY_CIPHER_MODE_OFB} and @code{GCRY_CIPHER_MODE_CTR}) will work
+with any block cipher algorithm. The @code{GCRY_CIPHER_MODE_CCM} will
+only work with block cipher algorithms which have the block size of
+16 bytes.
The third argument @var{flags} can either be passed as @code{0} or as
the bit-wise OR of the following constants.
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index f0ae927a..948202d5 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -325,7 +325,8 @@ enum gcry_ctl_cmds
GCRYCTL_SET_PREFERRED_RNG_TYPE = 65,
GCRYCTL_GET_CURRENT_RNG_TYPE = 66,
GCRYCTL_DISABLE_LOCKED_SECMEM = 67,
- GCRYCTL_DISABLE_PRIV_DROP = 68
+ GCRYCTL_DISABLE_PRIV_DROP = 68,
+ GCRYCTL_SET_CCM_LENGTHS = 69
};
/* Perform various operations defined by CMD. */
@@ -884,7 +885,8 @@ enum gcry_cipher_modes
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_AESWRAP= 7 /* AES-WRAP algorithm. */
+ GCRY_CIPHER_MODE_AESWRAP= 7, /* AES-WRAP algorithm. */
+ GCRY_CIPHER_MODE_CCM = 8 /* Counter with CBC-MAC. */
};
/* Flags used with the open function. */
@@ -896,6 +898,8 @@ enum gcry_cipher_flags
GCRY_CIPHER_CBC_MAC = 8 /* Enable CBC message auth. code (MAC). */
};
+/* CCM works only with blocks of 128 bits. */
+#define GCRY_CCM_BLOCK_LEN (128 / 8)
/* Create a handle for algorithm ALGO to be used in MODE. FLAGS may
be given as an bitwise OR of the gcry_cipher_flags values. */
diff --git a/tests/basic.c b/tests/basic.c
index 1d6e637c..21af21d8 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -1139,6 +1139,776 @@ check_ofb_cipher (void)
static void
+check_ccm_cipher (void)
+{
+ static const struct tv
+ {
+ int algo;
+ int keylen;
+ const char *key;
+ int noncelen;
+ const char *nonce;
+ int aadlen;
+ const char *aad;
+ int plainlen;
+ const char *plaintext;
+ int cipherlen;
+ const char *ciphertext;
+ } tv[] =
+ {
+ /* RFC 3610 */
+ { GCRY_CIPHER_AES, /* Packet Vector #1 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 23,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E",
+ 31,
+ "\x58\x8C\x97\x9A\x61\xC6\x63\xD2\xF0\x66\xD0\xC2\xC0\xF9\x89\x80\x6D\x5F\x6B\x61\xDA\xC3\x84\x17\xE8\xD1\x2C\xFD\xF9\x26\xE0"},
+ { GCRY_CIPHER_AES, /* Packet Vector #2 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 24,
+ "\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,
+ "\x72\xC9\x1A\x36\xE1\x35\xF8\xCF\x29\x1C\xA8\x94\x08\x5C\x87\xE3\xCC\x15\xC4\x39\xC9\xE4\x3A\x3B\xA0\x91\xD5\x6E\x10\x40\x09\x16"},
+ { GCRY_CIPHER_AES, /* Packet Vector #3 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 25,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20",
+ 33,
+ "\x51\xB1\xE5\xF4\x4A\x19\x7D\x1D\xA4\x6B\x0F\x8E\x2D\x28\x2A\xE8\x71\xE8\x38\xBB\x64\xDA\x85\x96\x57\x4A\xDA\xA7\x6F\xBD\x9F\xB0\xC5"},
+ { GCRY_CIPHER_AES, /* Packet Vector #4 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 19,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E",
+ 27,
+ "\xA2\x8C\x68\x65\x93\x9A\x9A\x79\xFA\xAA\x5C\x4C\x2A\x9D\x4A\x91\xCD\xAC\x8C\x96\xC8\x61\xB9\xC9\xE6\x1E\xF1"},
+ { GCRY_CIPHER_AES, /* Packet Vector #5 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 20,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+ 28,
+ "\xDC\xF1\xFB\x7B\x5D\x9E\x23\xFB\x9D\x4E\x13\x12\x53\x65\x8A\xD8\x6E\xBD\xCA\x3E\x51\xE8\x3F\x07\x7D\x9C\x2D\x93"},
+ { GCRY_CIPHER_AES, /* Packet Vector #6 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 21,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20",
+ 29,
+ "\x6F\xC1\xB0\x11\xF0\x06\x56\x8B\x51\x71\xA4\x2D\x95\x3D\x46\x9B\x25\x70\xA4\xBD\x87\x40\x5A\x04\x43\xAC\x91\xCB\x94"},
+ { GCRY_CIPHER_AES, /* Packet Vector #7 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 23,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E",
+ 33,
+ "\x01\x35\xD1\xB2\xC9\x5F\x41\xD5\xD1\xD4\xFE\xC1\x85\xD1\x66\xB8\x09\x4E\x99\x9D\xFE\xD9\x6C\x04\x8C\x56\x60\x2C\x97\xAC\xBB\x74\x90"},
+ { GCRY_CIPHER_AES, /* Packet Vector #8 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 24,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+ 34,
+ "\x7B\x75\x39\x9A\xC0\x83\x1D\xD2\xF0\xBB\xD7\x58\x79\xA2\xFD\x8F\x6C\xAE\x6B\x6C\xD9\xB7\xDB\x24\xC1\x7B\x44\x33\xF4\x34\x96\x3F\x34\xB4"},
+ { GCRY_CIPHER_AES, /* Packet Vector #9 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 25,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20",
+ 35,
+ "\x82\x53\x1A\x60\xCC\x24\x94\x5A\x4B\x82\x79\x18\x1A\xB5\xC8\x4D\xF2\x1C\xE7\xF9\xB7\x3F\x42\xE1\x97\xEA\x9C\x07\xE5\x6B\x5E\xB1\x7E\x5F\x4E"},
+ { GCRY_CIPHER_AES, /* Packet Vector #10 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 19,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E",
+ 29,
+ "\x07\x34\x25\x94\x15\x77\x85\x15\x2B\x07\x40\x98\x33\x0A\xBB\x14\x1B\x94\x7B\x56\x6A\xA9\x40\x6B\x4D\x99\x99\x88\xDD"},
+ { GCRY_CIPHER_AES, /* Packet Vector #11 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 20,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+ 30,
+ "\x67\x6B\xB2\x03\x80\xB0\xE3\x01\xE8\xAB\x79\x59\x0A\x39\x6D\xA7\x8B\x83\x49\x34\xF5\x3A\xA2\xE9\x10\x7A\x8B\x6C\x02\x2C"},
+ { GCRY_CIPHER_AES, /* Packet Vector #12 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 21,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20",
+ 31,
+ "\xC0\xFF\xA0\xD6\xF0\x5B\xDB\x67\xF2\x4D\x43\xA4\x33\x8D\x2A\xA4\xBE\xD7\xB2\x0E\x43\xCD\x1A\xA3\x16\x62\xE7\xAD\x65\xD6\xDB"},
+ { GCRY_CIPHER_AES, /* Packet Vector #13 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x41\x2B\x4E\xA9\xCD\xBE\x3C\x96\x96\x76\x6C\xFA",
+ 8, "\x0B\xE1\xA8\x8B\xAC\xE0\x18\xB1",
+ 23,
+ "\x08\xE8\xCF\x97\xD8\x20\xEA\x25\x84\x60\xE9\x6A\xD9\xCF\x52\x89\x05\x4D\x89\x5C\xEA\xC4\x7C",
+ 31,
+ "\x4C\xB9\x7F\x86\xA2\xA4\x68\x9A\x87\x79\x47\xAB\x80\x91\xEF\x53\x86\xA6\xFF\xBD\xD0\x80\xF8\xE7\x8C\xF7\xCB\x0C\xDD\xD7\xB3"},
+ { GCRY_CIPHER_AES, /* Packet Vector #14 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x33\x56\x8E\xF7\xB2\x63\x3C\x96\x96\x76\x6C\xFA",
+ 8, "\x63\x01\x8F\x76\xDC\x8A\x1B\xCB",
+ 24,
+ "\x90\x20\xEA\x6F\x91\xBD\xD8\x5A\xFA\x00\x39\xBA\x4B\xAF\xF9\xBF\xB7\x9C\x70\x28\x94\x9C\xD0\xEC",
+ 32,
+ "\x4C\xCB\x1E\x7C\xA9\x81\xBE\xFA\xA0\x72\x6C\x55\xD3\x78\x06\x12\x98\xC8\x5C\x92\x81\x4A\xBC\x33\xC5\x2E\xE8\x1D\x7D\x77\xC0\x8A"},
+ { GCRY_CIPHER_AES, /* Packet Vector #15 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x10\x3F\xE4\x13\x36\x71\x3C\x96\x96\x76\x6C\xFA",
+ 8, "\xAA\x6C\xFA\x36\xCA\xE8\x6B\x40",
+ 25,
+ "\xB9\x16\xE0\xEA\xCC\x1C\x00\xD7\xDC\xEC\x68\xEC\x0B\x3B\xBB\x1A\x02\xDE\x8A\x2D\x1A\xA3\x46\x13\x2E",
+ 33,
+ "\xB1\xD2\x3A\x22\x20\xDD\xC0\xAC\x90\x0D\x9A\xA0\x3C\x61\xFC\xF4\xA5\x59\xA4\x41\x77\x67\x08\x97\x08\xA7\x76\x79\x6E\xDB\x72\x35\x06"},
+ { GCRY_CIPHER_AES, /* Packet Vector #16 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x76\x4C\x63\xB8\x05\x8E\x3C\x96\x96\x76\x6C\xFA",
+ 12, "\xD0\xD0\x73\x5C\x53\x1E\x1B\xEC\xF0\x49\xC2\x44",
+ 19,
+ "\x12\xDA\xAC\x56\x30\xEF\xA5\x39\x6F\x77\x0C\xE1\xA6\x6B\x21\xF7\xB2\x10\x1C",
+ 27,
+ "\x14\xD2\x53\xC3\x96\x7B\x70\x60\x9B\x7C\xBB\x7C\x49\x91\x60\x28\x32\x45\x26\x9A\x6F\x49\x97\x5B\xCA\xDE\xAF"},
+ { GCRY_CIPHER_AES, /* Packet Vector #17 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\xF8\xB6\x78\x09\x4E\x3B\x3C\x96\x96\x76\x6C\xFA",
+ 12, "\x77\xB6\x0F\x01\x1C\x03\xE1\x52\x58\x99\xBC\xAE",
+ 20,
+ "\xE8\x8B\x6A\x46\xC7\x8D\x63\xE5\x2E\xB8\xC5\x46\xEF\xB5\xDE\x6F\x75\xE9\xCC\x0D",
+ 28,
+ "\x55\x45\xFF\x1A\x08\x5E\xE2\xEF\xBF\x52\xB2\xE0\x4B\xEE\x1E\x23\x36\xC7\x3E\x3F\x76\x2C\x0C\x77\x44\xFE\x7E\x3C"},
+ { GCRY_CIPHER_AES, /* Packet Vector #18 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\xD5\x60\x91\x2D\x3F\x70\x3C\x96\x96\x76\x6C\xFA",
+ 12, "\xCD\x90\x44\xD2\xB7\x1F\xDB\x81\x20\xEA\x60\xC0",
+ 21,
+ "\x64\x35\xAC\xBA\xFB\x11\xA8\x2E\x2F\x07\x1D\x7C\xA4\xA5\xEB\xD9\x3A\x80\x3B\xA8\x7F",
+ 29,
+ "\x00\x97\x69\xEC\xAB\xDF\x48\x62\x55\x94\xC5\x92\x51\xE6\x03\x57\x22\x67\x5E\x04\xC8\x47\x09\x9E\x5A\xE0\x70\x45\x51"},
+ { GCRY_CIPHER_AES, /* Packet Vector #19 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x42\xFF\xF8\xF1\x95\x1C\x3C\x96\x96\x76\x6C\xFA",
+ 8, "\xD8\x5B\xC7\xE6\x9F\x94\x4F\xB8",
+ 23,
+ "\x8A\x19\xB9\x50\xBC\xF7\x1A\x01\x8E\x5E\x67\x01\xC9\x17\x87\x65\x98\x09\xD6\x7D\xBE\xDD\x18",
+ 33,
+ "\xBC\x21\x8D\xAA\x94\x74\x27\xB6\xDB\x38\x6A\x99\xAC\x1A\xEF\x23\xAD\xE0\xB5\x29\x39\xCB\x6A\x63\x7C\xF9\xBE\xC2\x40\x88\x97\xC6\xBA"},
+ { GCRY_CIPHER_AES, /* Packet Vector #20 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x92\x0F\x40\xE5\x6C\xDC\x3C\x96\x96\x76\x6C\xFA",
+ 8, "\x74\xA0\xEB\xC9\x06\x9F\x5B\x37",
+ 24,
+ "\x17\x61\x43\x3C\x37\xC5\xA3\x5F\xC1\xF3\x9F\x40\x63\x02\xEB\x90\x7C\x61\x63\xBE\x38\xC9\x84\x37",
+ 34,
+ "\x58\x10\xE6\xFD\x25\x87\x40\x22\xE8\x03\x61\xA4\x78\xE3\xE9\xCF\x48\x4A\xB0\x4F\x44\x7E\xFF\xF6\xF0\xA4\x77\xCC\x2F\xC9\xBF\x54\x89\x44"},
+ { GCRY_CIPHER_AES, /* Packet Vector #21 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x27\xCA\x0C\x71\x20\xBC\x3C\x96\x96\x76\x6C\xFA",
+ 8, "\x44\xA3\xAA\x3A\xAE\x64\x75\xCA",
+ 25,
+ "\xA4\x34\xA8\xE5\x85\x00\xC6\xE4\x15\x30\x53\x88\x62\xD6\x86\xEA\x9E\x81\x30\x1B\x5A\xE4\x22\x6B\xFA",
+ 35,
+ "\xF2\xBE\xED\x7B\xC5\x09\x8E\x83\xFE\xB5\xB3\x16\x08\xF8\xE2\x9C\x38\x81\x9A\x89\xC8\xE7\x76\xF1\x54\x4D\x41\x51\xA4\xED\x3A\x8B\x87\xB9\xCE"},
+ { GCRY_CIPHER_AES, /* Packet Vector #22 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x5B\x8C\xCB\xCD\x9A\xF8\x3C\x96\x96\x76\x6C\xFA",
+ 12, "\xEC\x46\xBB\x63\xB0\x25\x20\xC3\x3C\x49\xFD\x70",
+ 19,
+ "\xB9\x6B\x49\xE2\x1D\x62\x17\x41\x63\x28\x75\xDB\x7F\x6C\x92\x43\xD2\xD7\xC2",
+ 29,
+ "\x31\xD7\x50\xA0\x9D\xA3\xED\x7F\xDD\xD4\x9A\x20\x32\xAA\xBF\x17\xEC\x8E\xBF\x7D\x22\xC8\x08\x8C\x66\x6B\xE5\xC1\x97"},
+ { GCRY_CIPHER_AES, /* Packet Vector #23 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x3E\xBE\x94\x04\x4B\x9A\x3C\x96\x96\x76\x6C\xFA",
+ 12, "\x47\xA6\x5A\xC7\x8B\x3D\x59\x42\x27\xE8\x5E\x71",
+ 20,
+ "\xE2\xFC\xFB\xB8\x80\x44\x2C\x73\x1B\xF9\x51\x67\xC8\xFF\xD7\x89\x5E\x33\x70\x76",
+ 30,
+ "\xE8\x82\xF1\xDB\xD3\x8C\xE3\xED\xA7\xC2\x3F\x04\xDD\x65\x07\x1E\xB4\x13\x42\xAC\xDF\x7E\x00\xDC\xCE\xC7\xAE\x52\x98\x7D"},
+ { GCRY_CIPHER_AES, /* Packet Vector #24 */
+ 16, "\xD7\x82\x8D\x13\xB2\xB0\xBD\xC3\x25\xA7\x62\x36\xDF\x93\xCC\x6B",
+ 13, "\x00\x8D\x49\x3B\x30\xAE\x8B\x3C\x96\x96\x76\x6C\xFA",
+ 12, "\x6E\x37\xA6\xEF\x54\x6D\x95\x5D\x34\xAB\x60\x59",
+ 21,
+ "\xAB\xF2\x1C\x0B\x02\xFE\xB8\x8F\x85\x6D\xF4\xA3\x73\x81\xBC\xE3\xCC\x12\x85\x17\xD4",
+ 31,
+ "\xF3\x29\x05\xB8\x8A\x64\x1B\x04\xB9\xC9\xFF\xB5\x8C\xC3\x90\x90\x0F\x3D\xA1\x2A\xB1\x6D\xCE\x9E\x82\xEF\xA1\x6D\xA6\x20\x59"},
+ /* RFC 5528 */
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #1 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x03\x02\x01\x00\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 23,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E",
+ 31,
+ "\xBA\x73\x71\x85\xE7\x19\x31\x04\x92\xF3\x8A\x5F\x12\x51\xDA\x55\xFA\xFB\xC9\x49\x84\x8A\x0D\xFC\xAE\xCE\x74\x6B\x3D\xB9\xAD"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #2 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x04\x03\x02\x01\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 24,
+ "\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,
+ "\x5D\x25\x64\xBF\x8E\xAF\xE1\xD9\x95\x26\xEC\x01\x6D\x1B\xF0\x42\x4C\xFB\xD2\xCD\x62\x84\x8F\x33\x60\xB2\x29\x5D\xF2\x42\x83\xE8"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #3 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x05\x04\x03\x02\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 25,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20",
+ 33,
+ "\x81\xF6\x63\xD6\xC7\x78\x78\x17\xF9\x20\x36\x08\xB9\x82\xAD\x15\xDC\x2B\xBD\x87\xD7\x56\xF7\x92\x04\xF5\x51\xD6\x68\x2F\x23\xAA\x46"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #4 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x06\x05\x04\x03\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 19,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E",
+ 27,
+ "\xCA\xEF\x1E\x82\x72\x11\xB0\x8F\x7B\xD9\x0F\x08\xC7\x72\x88\xC0\x70\xA4\xA0\x8B\x3A\x93\x3A\x63\xE4\x97\xA0"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #5 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x07\x06\x05\x04\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 20,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+ 28,
+ "\x2A\xD3\xBA\xD9\x4F\xC5\x2E\x92\xBE\x43\x8E\x82\x7C\x10\x23\xB9\x6A\x8A\x77\x25\x8F\xA1\x7B\xA7\xF3\x31\xDB\x09"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #6 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x08\x07\x06\x05\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 21,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20",
+ 29,
+ "\xFE\xA5\x48\x0B\xA5\x3F\xA8\xD3\xC3\x44\x22\xAA\xCE\x4D\xE6\x7F\xFA\x3B\xB7\x3B\xAB\xAB\x36\xA1\xEE\x4F\xE0\xFE\x28"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #7 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x09\x08\x07\x06\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 23,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E",
+ 33,
+ "\x54\x53\x20\x26\xE5\x4C\x11\x9A\x8D\x36\xD9\xEC\x6E\x1E\xD9\x74\x16\xC8\x70\x8C\x4B\x5C\x2C\xAC\xAF\xA3\xBC\xCF\x7A\x4E\xBF\x95\x73"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #8 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0A\x09\x08\x07\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 24,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+ 34,
+ "\x8A\xD1\x9B\x00\x1A\x87\xD1\x48\xF4\xD9\x2B\xEF\x34\x52\x5C\xCC\xE3\xA6\x3C\x65\x12\xA6\xF5\x75\x73\x88\xE4\x91\x3E\xF1\x47\x01\xF4\x41"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #9 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0B\x0A\x09\x08\xA0\xA1\xA2\xA3\xA4\xA5",
+ 8, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ 25,
+ "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20",
+ 35,
+ "\x5D\xB0\x8D\x62\x40\x7E\x6E\x31\xD6\x0F\x9C\xA2\xC6\x04\x74\x21\x9A\xC0\xBE\x50\xC0\xD4\xA5\x77\x87\x94\xD6\xE2\x30\xCD\x25\xC9\xFE\xBF\x87"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #10 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0C\x0B\x0A\x09\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 19,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E",
+ 29,
+ "\xDB\x11\x8C\xCE\xC1\xB8\x76\x1C\x87\x7C\xD8\x96\x3A\x67\xD6\xF3\xBB\xBC\x5C\xD0\x92\x99\xEB\x11\xF3\x12\xF2\x32\x37"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #11 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0D\x0C\x0B\x0A\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 20,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+ 30,
+ "\x7C\xC8\x3D\x8D\xC4\x91\x03\x52\x5B\x48\x3D\xC5\xCA\x7E\xA9\xAB\x81\x2B\x70\x56\x07\x9D\xAF\xFA\xDA\x16\xCC\xCF\x2C\x4E"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #12 */
+ 16, "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF",
+ 13, "\x00\x00\x00\x0E\x0D\x0C\x0B\xA0\xA1\xA2\xA3\xA4\xA5",
+ 12, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B",
+ 21,
+ "\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20",
+ 31,
+ "\x2C\xD3\x5B\x88\x20\xD2\x3E\x7A\xA3\x51\xB0\xE9\x2F\xC7\x93\x67\x23\x8B\x2C\xC7\x48\xCB\xB9\x4C\x29\x47\x79\x3D\x64\xAF\x75"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #13 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\xA9\x70\x11\x0E\x19\x27\xB1\x60\xB6\xA3\x1C\x1C",
+ 8, "\x6B\x7F\x46\x45\x07\xFA\xE4\x96",
+ 23,
+ "\xC6\xB5\xF3\xE6\xCA\x23\x11\xAE\xF7\x47\x2B\x20\x3E\x73\x5E\xA5\x61\xAD\xB1\x7D\x56\xC5\xA3",
+ 31,
+ "\xA4\x35\xD7\x27\x34\x8D\xDD\x22\x90\x7F\x7E\xB8\xF5\xFD\xBB\x4D\x93\x9D\xA6\x52\x4D\xB4\xF6\x45\x58\xC0\x2D\x25\xB1\x27\xEE"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #14 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\x83\xCD\x8C\xE0\xCB\x42\xB1\x60\xB6\xA3\x1C\x1C",
+ 8, "\x98\x66\x05\xB4\x3D\xF1\x5D\xE7",
+ 24,
+ "\x01\xF6\xCE\x67\x64\xC5\x74\x48\x3B\xB0\x2E\x6B\xBF\x1E\x0A\xBD\x26\xA2\x25\x72\xB4\xD8\x0E\xE7",
+ 32,
+ "\x8A\xE0\x52\x50\x8F\xBE\xCA\x93\x2E\x34\x6F\x05\xE0\xDC\x0D\xFB\xCF\x93\x9E\xAF\xFA\x3E\x58\x7C\x86\x7D\x6E\x1C\x48\x70\x38\x06"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #15 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\x5F\x54\x95\x0B\x18\xF2\xB1\x60\xB6\xA3\x1C\x1C",
+ 8, "\x48\xF2\xE7\xE1\xA7\x67\x1A\x51",
+ 25,
+ "\xCD\xF1\xD8\x40\x6F\xC2\xE9\x01\x49\x53\x89\x70\x05\xFB\xFB\x8B\xA5\x72\x76\xF9\x24\x04\x60\x8E\x08",
+ 33,
+ "\x08\xB6\x7E\xE2\x1C\x8B\xF2\x6E\x47\x3E\x40\x85\x99\xE9\xC0\x83\x6D\x6A\xF0\xBB\x18\xDF\x55\x46\x6C\xA8\x08\x78\xA7\x90\x47\x6D\xE5"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #16 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\xEC\x60\x08\x63\x31\x9A\xB1\x60\xB6\xA3\x1C\x1C",
+ 12, "\xDE\x97\xDF\x3B\x8C\xBD\x6D\x8E\x50\x30\xDA\x4C",
+ 19,
+ "\xB0\x05\xDC\xFA\x0B\x59\x18\x14\x26\xA9\x61\x68\x5A\x99\x3D\x8C\x43\x18\x5B",
+ 27,
+ "\x63\xB7\x8B\x49\x67\xB1\x9E\xDB\xB7\x33\xCD\x11\x14\xF6\x4E\xB2\x26\x08\x93\x68\xC3\x54\x82\x8D\x95\x0C\xC5"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #17 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\x60\xCF\xF1\xA3\x1E\xA1\xB1\x60\xB6\xA3\x1C\x1C",
+ 12, "\xA5\xEE\x93\xE4\x57\xDF\x05\x46\x6E\x78\x2D\xCF",
+ 20,
+ "\x2E\x20\x21\x12\x98\x10\x5F\x12\x9D\x5E\xD9\x5B\x93\xF7\x2D\x30\xB2\xFA\xCC\xD7",
+ 28,
+ "\x0B\xC6\xBB\xE2\xA8\xB9\x09\xF4\x62\x9E\xE6\xDC\x14\x8D\xA4\x44\x10\xE1\x8A\xF4\x31\x47\x38\x32\x76\xF6\x6A\x9F"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #18 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\x0F\x85\xCD\x99\x5C\x97\xB1\x60\xB6\xA3\x1C\x1C",
+ 12, "\x24\xAA\x1B\xF9\xA5\xCD\x87\x61\x82\xA2\x50\x74",
+ 21,
+ "\x26\x45\x94\x1E\x75\x63\x2D\x34\x91\xAF\x0F\xC0\xC9\x87\x6C\x3B\xE4\xAA\x74\x68\xC9",
+ 29,
+ "\x22\x2A\xD6\x32\xFA\x31\xD6\xAF\x97\x0C\x34\x5F\x7E\x77\xCA\x3B\xD0\xDC\x25\xB3\x40\xA1\xA3\xD3\x1F\x8D\x4B\x44\xB7"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #19 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\xC2\x9B\x2C\xAA\xC4\xCD\xB1\x60\xB6\xA3\x1C\x1C",
+ 8, "\x69\x19\x46\xB9\xCA\x07\xBE\x87",
+ 23,
+ "\x07\x01\x35\xA6\x43\x7C\x9D\xB1\x20\xCD\x61\xD8\xF6\xC3\x9C\x3E\xA1\x25\xFD\x95\xA0\xD2\x3D",
+ 33,
+ "\x05\xB8\xE1\xB9\xC4\x9C\xFD\x56\xCF\x13\x0A\xA6\x25\x1D\xC2\xEC\xC0\x6C\xCC\x50\x8F\xE6\x97\xA0\x06\x6D\x57\xC8\x4B\xEC\x18\x27\x68"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #20 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\x2C\x6B\x75\x95\xEE\x62\xB1\x60\xB6\xA3\x1C\x1C",
+ 8, "\xD0\xC5\x4E\xCB\x84\x62\x7D\xC4",
+ 24,
+ "\xC8\xC0\x88\x0E\x6C\x63\x6E\x20\x09\x3D\xD6\x59\x42\x17\xD2\xE1\x88\x77\xDB\x26\x4E\x71\xA5\xCC",
+ 34,
+ "\x54\xCE\xB9\x68\xDE\xE2\x36\x11\x57\x5E\xC0\x03\xDF\xAA\x1C\xD4\x88\x49\xBD\xF5\xAE\x2E\xDB\x6B\x7F\xA7\x75\xB1\x50\xED\x43\x83\xC5\xA9"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #21 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\xC5\x3C\xD4\xC2\xAA\x24\xB1\x60\xB6\xA3\x1C\x1C",
+ 8, "\xE2\x85\xE0\xE4\x80\x8C\xDA\x3D",
+ 25,
+ "\xF7\x5D\xAA\x07\x10\xC4\xE6\x42\x97\x79\x4D\xC2\xB7\xD2\xA2\x07\x57\xB1\xAA\x4E\x44\x80\x02\xFF\xAB",
+ 35,
+ "\xB1\x40\x45\x46\xBF\x66\x72\x10\xCA\x28\xE3\x09\xB3\x9B\xD6\xCA\x7E\x9F\xC8\x28\x5F\xE6\x98\xD4\x3C\xD2\x0A\x02\xE0\xBD\xCA\xED\x20\x10\xD3"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #22 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\xBE\xE9\x26\x7F\xBA\xDC\xB1\x60\xB6\xA3\x1C\x1C",
+ 12, "\x6C\xAE\xF9\x94\x11\x41\x57\x0D\x7C\x81\x34\x05",
+ 19,
+ "\xC2\x38\x82\x2F\xAC\x5F\x98\xFF\x92\x94\x05\xB0\xAD\x12\x7A\x4E\x41\x85\x4E",
+ 29,
+ "\x94\xC8\x95\x9C\x11\x56\x9A\x29\x78\x31\xA7\x21\x00\x58\x57\xAB\x61\xB8\x7A\x2D\xEA\x09\x36\xB6\xEB\x5F\x62\x5F\x5D"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #23 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\xDF\xA8\xB1\x24\x50\x07\xB1\x60\xB6\xA3\x1C\x1C",
+ 12, "\x36\xA5\x2C\xF1\x6B\x19\xA2\x03\x7A\xB7\x01\x1E",
+ 20,
+ "\x4D\xBF\x3E\x77\x4A\xD2\x45\xE5\xD5\x89\x1F\x9D\x1C\x32\xA0\xAE\x02\x2C\x85\xD7",
+ 30,
+ "\x58\x69\xE3\xAA\xD2\x44\x7C\x74\xE0\xFC\x05\xF9\xA4\xEA\x74\x57\x7F\x4D\xE8\xCA\x89\x24\x76\x42\x96\xAD\x04\x11\x9C\xE7"},
+ { GCRY_CIPHER_CAMELLIA128, /* Packet Vector #24 */
+ 16, "\xD7\x5C\x27\x78\x07\x8C\xA9\x3D\x97\x1F\x96\xFD\xE7\x20\xF4\xCD",
+ 13, "\x00\x3B\x8F\xD8\xD3\xA9\x37\xB1\x60\xB6\xA3\x1C\x1C",
+ 12, "\xA4\xD4\x99\xF7\x84\x19\x72\x8C\x19\x17\x8B\x0C",
+ 21,
+ "\x9D\xC9\xED\xAE\x2F\xF5\xDF\x86\x36\xE8\xC6\xDE\x0E\xED\x55\xF7\x86\x7E\x33\x33\x7D",
+ 31,
+ "\x4B\x19\x81\x56\x39\x3B\x0F\x77\x96\x08\x6A\xAF\xB4\x54\xF8\xC3\xF0\x34\xCC\xA9\x66\x94\x5F\x1F\xCE\xA7\xE1\x1B\xEE\x6A\x2F"}
+ };
+ static const int cut[] = { 0, 1, 8, 10, 16, 19, -1 };
+ gcry_cipher_hd_t hde, hdd;
+ unsigned char out[MAX_DATA_LEN];
+ size_t ctl_params[3];
+ int split, aadsplit;
+ size_t j, i, keylen, blklen, authlen;
+ gcry_error_t err = 0;
+
+ if (verbose)
+ fprintf (stderr, " Starting CCM checks.\n");
+
+ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+ {
+ if (verbose)
+ fprintf (stderr, " checking CCM mode for %s [%i]\n",
+ gcry_cipher_algo_name (tv[i].algo),
+ tv[i].algo);
+
+ for (j = 0; j < sizeof (cut) / sizeof (cut[0]); j++)
+ {
+ split = cut[j] < 0 ? tv[i].plainlen : cut[j];
+ if (tv[i].plainlen < split)
+ continue;
+
+ err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0);
+ if (!err)
+ err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CCM, 0);
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_open failed: %s\n",
+ gpg_strerror (err));
+ return;
+ }
+
+ keylen = gcry_cipher_get_algo_keylen(tv[i].algo);
+ if (!keylen)
+ {
+ fail ("cipher-ccm, gcry_cipher_get_algo_keylen failed\n");
+ return;
+ }
+
+ err = gcry_cipher_setkey (hde, tv[i].key, keylen);
+ if (!err)
+ err = gcry_cipher_setkey (hdd, tv[i].key, keylen);
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_setkey failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+ blklen = gcry_cipher_get_algo_blklen(tv[i].algo);
+ if (!blklen)
+ {
+ fail ("cipher-ccm, gcry_cipher_get_algo_blklen failed\n");
+ return;
+ }
+
+ err = gcry_cipher_setiv (hde, tv[i].nonce, tv[i].noncelen);
+ if (!err)
+ err = gcry_cipher_setiv (hdd, tv[i].nonce, tv[i].noncelen);
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_setiv failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+ authlen = tv[i].cipherlen - tv[i].plainlen;
+ ctl_params[0] = tv[i].plainlen; /* encryptedlen */
+ ctl_params[1] = tv[i].aadlen; /* aadlen */
+ ctl_params[2] = authlen; /* authtaglen */
+ err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params,
+ sizeof(ctl_params));
+ if (!err)
+ err = gcry_cipher_ctl (hdd, GCRYCTL_SET_CCM_LENGTHS, ctl_params,
+ sizeof(ctl_params));
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS "
+ "failed: %s\n", gpg_strerror (err));
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+ aadsplit = split > tv[i].aadlen ? 0 : split;
+
+ err = gcry_cipher_authenticate (hde, tv[i].aad,
+ tv[i].aadlen - aadsplit);
+ if (!err)
+ err = gcry_cipher_authenticate (hde,
+ &tv[i].aad[tv[i].aadlen - aadsplit],
+ aadsplit);
+ if (!err)
+ err = gcry_cipher_authenticate (hdd, tv[i].aad,
+ tv[i].aadlen - aadsplit);
+ if (!err)
+ err = gcry_cipher_authenticate (hdd,
+ &tv[i].aad[tv[i].aadlen - aadsplit],
+ aadsplit);
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_authenticate failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+ err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN, tv[i].plaintext,
+ tv[i].plainlen - split);
+ if (!err)
+ err = gcry_cipher_encrypt (hde, &out[tv[i].plainlen - split],
+ MAX_DATA_LEN - (tv[i].plainlen - split),
+ &tv[i].plaintext[tv[i].plainlen - split],
+ split);
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_encrypt (%d:%d) failed: %s\n",
+ i, j, gpg_strerror (err));
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+ err = gcry_cipher_gettag (hde, &out[tv[i].plainlen], authlen);
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_gettag (%d:%d) failed: %s\n",
+ i, j, gpg_strerror (err));
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+ if (memcmp (tv[i].ciphertext, out, tv[i].cipherlen))
+ fail ("cipher-ccm, encrypt mismatch entry %d:%d\n", i, j);
+
+ err = gcry_cipher_decrypt (hdd, out, tv[i].plainlen - split, NULL, 0);
+ if (!err)
+ err = gcry_cipher_decrypt (hdd, &out[tv[i].plainlen - split], split,
+ NULL, 0);
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_decrypt (%d:%d) failed: %s\n",
+ i, j, gpg_strerror (err));
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+ if (memcmp (tv[i].plaintext, out, tv[i].plainlen))
+ fail ("cipher-ccm, decrypt mismatch entry %d:%d\n", i, j);
+
+ err = gcry_cipher_checktag (hdd, &out[tv[i].plainlen], authlen);
+ if (err)
+ {
+ fail ("cipher-ccm, gcry_cipher_checktag (%d:%d) failed: %s\n",
+ i, j, gpg_strerror (err));
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ }
+ }
+
+ /* Large buffer tests. */
+
+ /* Test encoding of aadlen > 0xfeff. */
+ {
+ static const char key[]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
+ 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f};
+ static const char iv[]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19};
+ static const char tag[]={0x9C,0x76,0xE7,0x33,0xD5,0x15,0xB3,0x6C,
+ 0xBA,0x76,0x95,0xF7,0xFB,0x91};
+ char buf[1024];
+ size_t enclen = 0x20000;
+ size_t aadlen = 0x20000;
+ size_t taglen = sizeof(tag);
+
+ err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0);
+ if (err)
+ {
+ fail ("cipher-ccm-large, gcry_cipher_open failed: %s\n",
+ gpg_strerror (err));
+ return;
+ }
+
+ err = gcry_cipher_setkey (hde, key, sizeof (key));
+ if (err)
+ {
+ fail ("cipher-ccm-large, gcry_cipher_setkey failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+
+ err = gcry_cipher_setiv (hde, iv, sizeof (iv));
+ if (err)
+ {
+ fail ("cipher-ccm-large, gcry_cipher_setiv failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+
+ ctl_params[0] = enclen; /* encryptedlen */
+ ctl_params[1] = aadlen; /* aadlen */
+ ctl_params[2] = taglen; /* authtaglen */
+ err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params,
+ sizeof(ctl_params));
+ if (err)
+ {
+ fail ("cipher-ccm-large, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS "
+ "failed: %s\n", gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+
+ memset (buf, 0xaa, sizeof(buf));
+
+ for (i = 0; i < aadlen; i += sizeof(buf))
+ {
+ err = gcry_cipher_authenticate (hde, buf, sizeof (buf));
+ if (err)
+ {
+ fail ("cipher-ccm-large, gcry_cipher_authenticate failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+ }
+
+ for (i = 0; i < enclen; i += sizeof(buf))
+ {
+ memset (buf, 0xee, sizeof(buf));
+ err = gcry_cipher_encrypt (hde, buf, sizeof (buf), NULL, 0);
+ if (err)
+ {
+ fail ("cipher-ccm-large, gcry_cipher_encrypt failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+ }
+
+ err = gcry_cipher_gettag (hde, buf, taglen);
+ if (err)
+ {
+ fail ("cipher-ccm-large, gcry_cipher_gettag failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+
+ if (memcmp (buf, tag, taglen) != 0)
+ fail ("cipher-ccm-large, encrypt mismatch entry\n");
+ }
+
+#if 0
+ /* Test encoding of aadlen > 0xffffffff. */
+ {
+ static const char key[]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
+ 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f};
+ static const char iv[]={0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19};
+ static const char tag[]={0x01,0xB2,0xC3,0x4A,0xA6,0x6A,0x07,0x6D,
+ 0xBC,0xBD,0xEA,0x17,0xD3,0x73,0xD7,0xD4};
+ char buf[1024];
+ size_t enclen = (size_t)0xffffffff + 1 + 1024;
+ size_t aadlen = (size_t)0xffffffff + 1 + 1024;
+ size_t taglen = sizeof(tag);
+
+ err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CCM, 0);
+ if (err)
+ {
+ fail ("cipher-ccm-huge, gcry_cipher_open failed: %s\n",
+ gpg_strerror (err));
+ return;
+ }
+
+ err = gcry_cipher_setkey (hde, key, sizeof (key));
+ if (err)
+ {
+ fail ("cipher-ccm-huge, gcry_cipher_setkey failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+
+ err = gcry_cipher_setiv (hde, iv, sizeof (iv));
+ if (err)
+ {
+ fail ("cipher-ccm-huge, gcry_cipher_setiv failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+
+ ctl_params[0] = enclen; /* encryptedlen */
+ ctl_params[1] = aadlen; /* aadlen */
+ ctl_params[2] = taglen; /* authtaglen */
+ err = gcry_cipher_ctl (hde, GCRYCTL_SET_CCM_LENGTHS, ctl_params,
+ sizeof(ctl_params));
+ if (err)
+ {
+ fail ("cipher-ccm-huge, gcry_cipher_ctl GCRYCTL_SET_CCM_LENGTHS failed:"
+ "%s\n", gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+
+ memset (buf, 0xaa, sizeof(buf));
+
+ for (i = 0; i < aadlen; i += sizeof(buf))
+ {
+ err = gcry_cipher_authenticate (hde, buf, sizeof (buf));
+ if (err)
+ {
+ fail ("cipher-ccm-huge, gcry_cipher_authenticate failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+ }
+
+ for (i = 0; i < enclen; i += sizeof(buf))
+ {
+ memset (buf, 0xee, sizeof(buf));
+ err = gcry_cipher_encrypt (hde, buf, sizeof (buf), NULL, 0);
+ if (err)
+ {
+ fail ("cipher-ccm-huge, gcry_cipher_encrypt failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+ }
+
+ err = gcry_cipher_gettag (hde, buf, taglen);
+ if (err)
+ {
+ fail ("cipher-ccm-huge, gcry_cipher_gettag failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hde);
+ return;
+ }
+
+ if (memcmp (buf, tag, taglen) != 0)
+ fail ("cipher-ccm-huge, encrypt mismatch entry\n");
+ }
+#endif
+
+ if (verbose)
+ fprintf (stderr, " Completed CCM checks.\n");
+}
+
+
+static void
check_stream_cipher (void)
{
struct tv
@@ -2455,6 +3225,7 @@ check_cipher_modes(void)
check_ctr_cipher ();
check_cfb_cipher ();
check_ofb_cipher ();
+ check_ccm_cipher ();
check_stream_cipher ();
check_stream_cipher_large_block ();
diff --git a/tests/benchmark.c b/tests/benchmark.c
index ecda0d3c..d3ef1a23 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -435,6 +435,40 @@ md_bench ( const char *algoname )
fflush (stdout);
}
+
+static void ccm_aead_init(gcry_cipher_hd_t hd, size_t buflen, int authlen)
+{
+ const int _L = 4;
+ const int noncelen = 15 - _L;
+ char nonce[noncelen];
+ size_t params[3];
+ gcry_error_t err = GPG_ERR_NO_ERROR;
+
+ memset (nonce, 0x33, noncelen);
+
+ err = gcry_cipher_setiv (hd, nonce, noncelen);
+ if (err)
+ {
+ fprintf (stderr, "gcry_cipher_setiv failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hd);
+ exit (1);
+ }
+
+ params[0] = buflen; /* encryptedlen */
+ params[1] = 0; /* aadlen */
+ params[2] = authlen; /* authtaglen */
+ err = gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(params));
+ if (err)
+ {
+ fprintf (stderr, "gcry_cipher_setiv failed: %s\n",
+ gpg_strerror (err));
+ gcry_cipher_close (hd);
+ exit (1);
+ }
+}
+
+
static void
cipher_bench ( const char *algoname )
{
@@ -448,12 +482,21 @@ cipher_bench ( const char *algoname )
char *raw_outbuf, *raw_buf;
size_t allocated_buflen, buflen;
int repetitions;
- static struct { int mode; const char *name; int blocked; } modes[] = {
+ static const struct {
+ int mode;
+ const char *name;
+ int blocked;
+ void (* const aead_init)(gcry_cipher_hd_t hd, size_t buflen, int authlen);
+ int req_blocksize;
+ int authlen;
+ } modes[] = {
{ GCRY_CIPHER_MODE_ECB, " ECB/Stream", 1 },
{ GCRY_CIPHER_MODE_CBC, " CBC", 1 },
{ GCRY_CIPHER_MODE_CFB, " CFB", 0 },
{ GCRY_CIPHER_MODE_OFB, " OFB", 0 },
{ GCRY_CIPHER_MODE_CTR, " CTR", 0 },
+ { GCRY_CIPHER_MODE_CCM, " CCM", 0,
+ ccm_aead_init, GCRY_CCM_BLOCK_LEN, 8 },
{ GCRY_CIPHER_MODE_STREAM, "", 0 },
{0}
};
@@ -542,9 +585,16 @@ cipher_bench ( const char *algoname )
for (modeidx=0; modes[modeidx].mode; modeidx++)
{
if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM)
- | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
+ || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
continue;
+ if (modes[modeidx].req_blocksize > 0
+ && blklen != modes[modeidx].req_blocksize)
+ {
+ printf (" %7s %7s", "-", "-" );
+ continue;
+ }
+
for (i=0; i < sizeof buf; i++)
buf[i] = i;
@@ -585,7 +635,18 @@ cipher_bench ( const char *algoname )
exit (1);
}
}
- err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen);
+ if (modes[modeidx].aead_init)
+ {
+ (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen);
+ err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen);
+ if (err)
+ break;
+ err = gcry_cipher_gettag (hd, outbuf, modes[modeidx].authlen);
+ }
+ else
+ {
+ err = gcry_cipher_encrypt (hd, outbuf, buflen, buf, buflen);
+ }
}
stop_timer ();
@@ -632,7 +693,18 @@ cipher_bench ( const char *algoname )
exit (1);
}
}
- err = gcry_cipher_decrypt ( hd, outbuf, buflen, buf, buflen);
+ if (modes[modeidx].aead_init)
+ {
+ (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen);
+ err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen);
+ if (err)
+ break;
+ err = gcry_cipher_checktag (hd, outbuf, modes[modeidx].authlen);
+ if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
+ err = gpg_error (GPG_ERR_NO_ERROR);
+ }
+ else
+ err = gcry_cipher_decrypt (hd, outbuf, buflen, buf, buflen);
}
stop_timer ();
printf (" %s", elapsed_time ());