[RFC PATCH 3/3] Add Counter with CBC-MAC mode (CCM)

Jussi Kivilinna jussi.kivilinna at iki.fi
Sun Oct 13 12:02:38 CEST 2013


--

Patch adds CCM (Counter with CBC-MAC) mode as defined in RFC 3610 and NIST
Special Publication 800-38C.
---
 cipher/Makefile.am       |    1 
 cipher/cipher-ccm.c      |  349 ++++++++++++++++++++++++++++++
 cipher/cipher-internal.h |   41 +++-
 cipher/cipher.c          |   88 ++++++--
 src/gcrypt.h.in          |    5 
 tests/basic.c            |  532 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/benchmark.c        |   67 +++++-
 7 files changed, 1063 insertions(+), 20 deletions(-)
 create mode 100644 cipher/cipher-ccm.c

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index a2b2c8a..b0efd89 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 0000000..94ffbea
--- /dev/null
+++ b/cipher/cipher-ccm.c
@@ -0,0 +1,349 @@
+/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna at 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, unsigned int inlen,
+            int do_padding)
+{
+  unsigned int burn = 0;
+  unsigned int unused = c->u_mode.ccm.mac_unused;
+  unsigned int blocksize = 16;
+
+  if (inlen == 0 && unused == 0)
+    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;
+        }
+
+      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_aead_init (gcry_cipher_hd_t c, const unsigned char *nonce,
+                            unsigned int noncelen, unsigned int authlen,
+                            size_t encryptlen)
+{
+  unsigned int L = 15 - noncelen;
+  unsigned int M = authlen;
+  unsigned int L_, M_;
+  int i;
+
+  M_ = (M - 2) / 2;
+  L_ = L - 1;
+
+  if (!nonce)
+    return GPG_ERR_INV_ARG;
+  /* 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;
+  /* 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;
+
+  c->u_mode.ccm.authlen = authlen;
+  c->u_mode.ccm.encryptlen = encryptlen;
+
+  /* Setup IV & CTR */
+  c->u_iv.iv[0] = M_ * 8 + L_; /* Do not yet know if addlen > 0.  */
+  memcpy (&c->u_iv.iv[1], nonce, noncelen);
+  for (i = 16 - 1; i >= 1 + noncelen; i--)
+    {
+      c->u_iv.iv[i] = encryptlen & 0xff;
+      encryptlen >>= 8;
+    }
+  c->u_ctr.ctr[0] = L_;
+  memcpy (&c->u_ctr.ctr[1], nonce, noncelen);
+  memset (&c->u_ctr.ctr[1 + noncelen], 0, L);
+
+  c->u_mode.ccm.aead = 1;
+
+  return GPG_ERR_NO_ERROR;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *aadbuf,
+                               unsigned int aadbuflen)
+{
+  unsigned int burn = 0;
+  unsigned char b0[16];
+
+  if (aadbuflen > 0 && !aadbuf)
+    return GPG_ERR_INV_ARG;
+  if (!c->u_mode.ccm.aead || c->u_mode.ccm.tag)
+    return GPG_ERR_INV_STATE;
+  if (c->u_mode.ccm.aad)
+    return GPG_ERR_INV_STATE;
+
+  memcpy (b0, c->u_iv.iv, 16);
+  memset (c->u_iv.iv, 0, 16);
+
+  b0[0] |= (aadbuflen > 0) * 64;
+
+  set_burn (burn, do_cbc_mac (c, b0, 16, 0));
+
+  if (aadbuflen > 0 && aadbuflen <= (unsigned int)0xfeff)
+    {
+      b0[0] = (aadbuflen >> 8) & 0xff;
+      b0[1] = aadbuflen & 0xff;
+      set_burn (burn, do_cbc_mac (c, b0, 2, 0));
+    }
+  else if (aadbuflen > 0xfeff && aadbuflen <= (unsigned int)0xffffffff)
+    {
+      b0[0] = 0xff;
+      b0[1] = 0xfe;
+      buf_put_be32(&b0[2], aadbuflen);
+      set_burn (burn, do_cbc_mac (c, b0, 6, 0));
+    }
+#ifdef HAVE_U64_TYPEDEF
+  else if (aadbuflen > (unsigned int)0xffffffff)
+    {
+      b0[0] = 0xff;
+      b0[1] = 0xff;
+      buf_put_be64(&b0[2], aadbuflen);
+      set_burn (burn, do_cbc_mac (c, b0, 10, 0));
+    }
+#endif
+
+  if (aadbuflen > 0)
+    set_burn (burn, do_cbc_mac (c, aadbuf, aadbuflen, 1));
+
+
+  /* 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.aad = 1;
+
+  return GPG_ERR_NO_ERROR;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf,
+                      unsigned int outbuflen, int check)
+{
+  gcry_err_code_t err;
+  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.aead)
+    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.aad)
+    {
+      err = _gcry_cipher_ccm_authenticate (c, NULL, 0);
+      if (err)
+        return err;
+    }
+
+  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_encrypt (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 + c->u_mode.ccm.authlen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+  if (!c->u_mode.ccm.aead || c->u_mode.ccm.tag)
+    return GPG_ERR_INV_STATE;
+  if (inbuflen != c->u_mode.ccm.encryptlen)
+    return GPG_ERR_INV_LENGTH;
+
+  if (!c->u_mode.ccm.aad)
+    {
+      err = _gcry_cipher_ccm_authenticate (c, NULL, 0);
+      if (err)
+        return err;
+    }
+
+  c->u_mode.ccm.encryptlen -= inbuflen;
+  burn = do_cbc_mac (c, inbuf, inbuflen, 0);
+  if (burn)
+    _gcry_burn_stack (burn + sizeof(void *) * 5);
+
+  err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+  if (err)
+    return err;
+
+  /* Generate and append MAC.  */
+  return _gcry_cipher_ccm_tag (c, &outbuf[inbuflen], c->u_mode.ccm.authlen, 0);
+}
+
+
+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;
+  unsigned int datalen;
+
+  if (inbuflen < c->u_mode.ccm.authlen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+  if (outbuflen < inbuflen - c->u_mode.ccm.authlen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+  if (!c->u_mode.ccm.aead || c->u_mode.ccm.tag)
+    return GPG_ERR_INV_STATE;
+  datalen = inbuflen - c->u_mode.ccm.authlen;
+  if (datalen != c->u_mode.ccm.encryptlen)
+    return GPG_ERR_INV_LENGTH;
+
+  if (!c->u_mode.ccm.aad)
+    {
+      err = _gcry_cipher_ccm_authenticate (c, NULL, 0);
+      if (err)
+        return err;
+    }
+
+  err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, datalen);
+  if (err)
+    return err;
+
+  c->u_mode.ccm.encryptlen -= datalen;
+  burn = do_cbc_mac (c, outbuf, datalen, 0);
+  if (burn)
+    _gcry_burn_stack (burn + sizeof(void *) * 5);
+
+  err = _gcry_cipher_ccm_tag (c, (unsigned char *)&inbuf[datalen],
+                              c->u_mode.ccm.authlen, 1);
+  if (err)
+    {
+      /* MAC check failed!  */
+      wipememory (outbuf, outbuflen);
+      wipememory (c->u_iv.iv, 16);
+    }
+  return err;
+}
+
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index b60ef38..abd70f4 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,24 @@ 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 {
+      /* 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 authlen;
+      unsigned int encryptlen;
+
+      unsigned int aead:1;/* Set to 1 if AEAD mode has been initialized.  */
+      unsigned int aad:1; /* Set to 1 if AAD 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 +194,25 @@ 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_aead_init
+/*           */ (gcry_cipher_hd_t c,
+                 const unsigned char *nonce, unsigned int noncelen,
+                 unsigned int authlen, size_t encryptlen);
+gcry_err_code_t _gcry_cipher_ccm_authenticate
+/*           */ (gcry_cipher_hd_t c,
+                 const unsigned char *aadbuf, unsigned int aadbuflen);
+gcry_err_code_t _gcry_cipher_ccm_tag
+/*           */ (gcry_cipher_hd_t c,
+                 unsigned char *outbuf, unsigned int outbuflen, int check);
+
 
 #endif /*G10_CIPHER_INTERNAL_H*/
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 8ebab7c..42fecce 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:
@@ -718,6 +725,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 +822,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 +900,20 @@ _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:
+        log_fatal ("cipher_setiv: invalid mode %d\n", hd->mode );
+        rc = GPG_ERR_INV_CIPHER_MODE;
+        break;
+
+      default:
+        cipher_setiv (hd, iv, ivlen);
+        break;
+    }
+  return gpg_error (rc);
 }
 
 /* Set counter for CTR mode.  (CTR,CTRLEN) must denote a buffer of
@@ -915,35 +942,70 @@ gcry_error_t
 _gcry_cipher_authenticate (gcry_cipher_hd_t hd,
                            const void *aad, size_t aadsize)
 {
-  log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode );
+  gcry_err_code_t rc = GPG_ERR_NO_ERROR;
+
+  switch (hd->mode)
+    {
+    case GCRY_CIPHER_MODE_CCM:
+      rc = _gcry_cipher_ccm_authenticate (hd, aad, aadsize);
+      break;
 
-  (void)aad;
-  (void)aadsize;
+    default:
+      log_fatal ("gcry_cipher_tag: 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_tag (gcry_cipher_hd_t hd, void *out, size_t outsize)
 {
-  log_fatal ("gcry_cipher_tag: invalid mode %d\n", hd->mode );
+  gcry_err_code_t rc = GPG_ERR_NO_ERROR;
 
-  (void)out;
-  (void)outsize;
+  switch (hd->mode)
+    {
+    case GCRY_CIPHER_MODE_CCM:
+      rc = _gcry_cipher_ccm_tag (hd, out, outsize, 0);
+      break;
+
+    default:
+      log_fatal ("gcry_cipher_tag: 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_aead_vinit (gcry_cipher_hd_t hd, va_list arg_ptr)
 {
-  log_fatal ("gcry_cipher_aead_init: invalid mode %d\n", hd->mode );
+  gcry_err_code_t rc;
 
-  (void)arg_ptr;
+  switch (hd->mode)
+    {
+    case GCRY_CIPHER_MODE_CCM:
+      {
+        const void *nonce = va_arg(arg_ptr, const void *);
+        unsigned int nonce_len = va_arg(arg_ptr, unsigned int);
+        unsigned int auth_len = va_arg(arg_ptr, unsigned int);
+        size_t encrypt_len = va_arg(arg_ptr, size_t);
+
+        rc = _gcry_cipher_ccm_aead_init (hd, nonce, nonce_len, auth_len,
+                                         encrypt_len);
+        break;
+      }
+    default:
+      log_fatal ("gcry_cipher_aead_init: 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);
 }
 
 
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 2fffd69..88e9c36 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -871,7 +871,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. */
@@ -883,6 +884,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 ee04900..78f6a48 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -1139,6 +1139,537 @@ 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"}
+    };
+  gcry_cipher_hd_t hde, hdd;
+  unsigned char out[MAX_DATA_LEN];
+  int 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);
+      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;
+        }
+
+      authlen = tv[i].cipherlen - tv[i].plainlen;
+      err = gcry_cipher_aead_init (hde, tv[i].nonce, tv[i].noncelen,
+                                   authlen, tv[i].plainlen);
+      if (!err)
+        err = gcry_cipher_aead_init (hdd, tv[i].nonce, tv[i].noncelen,
+                                     authlen, tv[i].plainlen);
+      if (err)
+        {
+          fail ("cipher-ccm, gcry_cipher_aead_init failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      err = gcry_cipher_authenticate (hde, tv[i].aad, tv[i].aadlen);
+      if (!err)
+        err = gcry_cipher_authenticate (hdd, tv[i].aad, tv[i].aadlen);
+      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);
+      if (err)
+        {
+          fail ("cipher-ccm, gcry_cipher_encrypt (%d) failed: %s\n",
+                i, 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\n", i);
+
+      err = gcry_cipher_decrypt (hdd, out, tv[i].cipherlen, NULL, 0);
+      if (err)
+        {
+          fail ("cipher-ccm, gcry_cipher_decrypt (%d) failed: %s\n",
+                i, 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);
+
+      memset (out, 0, sizeof(out));
+      err = gcry_cipher_tag (hdd, out, authlen);
+      if (err)
+        {
+          fail ("cipher-ccm, gcry_cipher_tag (%d) failed: %s\n",
+                i, gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      if (memcmp (&tv[i].ciphertext[tv[i].plainlen], out, authlen))
+        fail ("cipher-ccm, decrypt auth-tag mismatch entry %d\n", i);
+
+      gcry_cipher_close (hde);
+      gcry_cipher_close (hdd);
+    }
+  if (verbose)
+    fprintf (stderr, "  Completed CCM checks.\n");
+}
+
+
+static void
 check_stream_cipher (void)
 {
   struct tv
@@ -2455,6 +2986,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 5d1434a..21ae176 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -435,6 +435,36 @@ 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];
+  gcry_error_t err = GPG_ERR_NO_ERROR;
+
+  memset (nonce, 0x33, noncelen);
+
+  err = gcry_cipher_aead_init (hd, nonce, noncelen, authlen, buflen - authlen);
+  if (err)
+    {
+      fprintf (stderr, "gcry_cipher_aead_init failed: %s\n",
+               gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  err = gcry_cipher_authenticate (hd, NULL, 0);
+  if (err)
+    {
+      fprintf (stderr, "gcry_cipher_authenticate failed: %s\n",
+               gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+}
+
+
 static void
 cipher_bench ( const char *algoname )
 {
@@ -446,14 +476,23 @@ cipher_bench ( const char *algoname )
   char key[128];
   char *outbuf, *buf;
   char *raw_outbuf, *raw_buf;
-  size_t allocated_buflen, buflen;
+  size_t allocated_buflen, buflen, plainlen;
   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 +581,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;
 
@@ -570,6 +616,7 @@ cipher_bench ( const char *algoname )
       buflen = allocated_buflen;
       if (modes[modeidx].blocked)
         buflen = (buflen / blklen) * blklen;
+      plainlen = buflen - modes[modeidx].authlen;
 
       start_timer ();
       for (i=err=0; !err && i < repetitions; i++)
@@ -585,7 +632,9 @@ 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, plainlen);
         }
       stop_timer ();
 
@@ -632,7 +681,15 @@ 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, plainlen, buf, buflen);
+              if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
+                err = gpg_error (GPG_ERR_NO_ERROR);
+            }
+          else
+            err = gcry_cipher_decrypt (hd, outbuf, plainlen, buf, buflen);
         }
       stop_timer ();
       printf (" %s", elapsed_time ());




More information about the Gcrypt-devel mailing list