[git] GCRYPT - branch, master, updated. libgcrypt-1.8.1-40-g0b55f34

by Jussi Kivilinna cvs at cvs.gnupg.org
Mon Jan 22 21:23:17 CET 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  0b55f349a8b8f4b0ac9ed724c2d5b8dcc9f5401c (commit)
       via  bd75f0e89817b5708c57efab49e3eb4e035186e2 (commit)
       via  e8629e535bd0e9711b07904d4501de8ad57aaecd (commit)
       via  cd7ed2e3546b12dd98df4211949f1cdbf5827013 (commit)
      from  93503c127a52c1f6a193750e2bf181a744ba3e6b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 0b55f349a8b8f4b0ac9ed724c2d5b8dcc9f5401c
Author: Jussi Kivilinna <jussi.kivilinna at iki.fi>
Date:   Mon Jan 22 22:17:50 2018 +0200

    Fix use of AVX instructions in Chaha20 SSSE3 implementation
    
    * cipher/chacha20-amd64-ssse3.S: Replace two 'vmovdqa' instructions
    with 'movdqa'.
    --
    
    Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>

diff --git a/cipher/chacha20-amd64-ssse3.S b/cipher/chacha20-amd64-ssse3.S
index 7ad1c0a..f237228 100644
--- a/cipher/chacha20-amd64-ssse3.S
+++ b/cipher/chacha20-amd64-ssse3.S
@@ -190,8 +190,8 @@ _gcry_chacha20_amd64_ssse3_blocks4:
 	mov $20, ROUND;
 
 	/* Construct counter vectors X12 and X13 */
-	vmovdqa .Linc_counter RIP, X0;
-	vmovdqa .Lunsigned_cmp RIP, X2;
+	movdqa .Linc_counter RIP, X0;
+	movdqa .Lunsigned_cmp RIP, X2;
 	pbroadcastd((12 * 4)(INPUT), X12);
 	pbroadcastd((13 * 4)(INPUT), X13);
 	paddd X0, X12;

commit bd75f0e89817b5708c57efab49e3eb4e035186e2
Author: Jussi Kivilinna <jussi.kivilinna at iki.fi>
Date:   Sat Jan 20 21:12:12 2018 +0200

    doc: fix double "See" in front of reference
    
    * doc/gcrypt.texi: Change @xref to @ref when text already has 'see' in
    the front.
    --
    
    @xref references start with `See ...'. Use @ref instead
    when text already has 'see' in front.
    
    Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>

diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index ccb4b82..bba07a4 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -1743,7 +1743,7 @@ other cipher functions and returns a handle to it in `hd'.  In case of
 an error, an according error code is returned.
 
 The ID of algorithm to use must be specified via @var{algo}.  See
- at xref{Available ciphers}, for a list of supported ciphers and the
+ at ref{Available ciphers}, for a list of supported ciphers and the
 according constants.
 
 Besides using the constants directly, the function
@@ -1751,7 +1751,7 @@ Besides using the constants directly, the function
 an algorithm into the according numeric ID.
 
 The cipher mode to use must be specified via @var{mode}.  See
- at xref{Available cipher modes}, for a list of supported cipher modes
+ at ref{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.
@@ -3310,7 +3310,7 @@ may be given as @code{0} if the algorithms to use are later set using
 @code{gcry_md_enable}. @var{hd} is guaranteed to either receive a valid
 handle or NULL.
 
-For a list of supported algorithms, see @xref{Available hash
+For a list of supported algorithms, see @ref{Available hash
 algorithms}.
 
 The flags allowed for @var{mode} are:
@@ -3329,7 +3329,7 @@ algorithm is not an extendable-output function.  Note that the function
 @code{gcry_md_setkey} must be used to set the MAC key.  The size of the
 MAC is equal to the message digest of the underlying hash algorithm.
 If you want CBC message authentication codes based on a cipher,
-see @xref{Working with cipher handles}.
+see @ref{Working with cipher handles}.
 
 @item GCRY_MD_FLAG_BUGEMU1
 @cindex bug emulation
@@ -3847,7 +3847,7 @@ bitwise OR of constants described below. @var{hd} is guaranteed to either
 receive a valid handle or NULL. @var{ctx} is context object to associate MAC
 object with. @var{ctx} maybe set to NULL.
 
-For a list of supported algorithms, see @xref{Available MAC algorithms}.
+For a list of supported algorithms, see @ref{Available MAC algorithms}.
 
 The flags allowed for @var{mode} are:
 
@@ -5626,7 +5626,7 @@ self-contained functions.  Due to the wide variety of parameters
 required by different algorithms S-expressions, as flexible way to
 convey these parameters, are used.  There is a set of helper functions
 to work with these S-expressions.
- at c see @xref{S-expression Subsystem Architecture}.
+ at c see @ref{S-expression Subsystem Architecture}.
 
 Aside of functions to register new algorithms, map algorithms names to
 algorithms identifiers and to lookup properties of a key, the

commit e8629e535bd0e9711b07904d4501de8ad57aaecd
Author: Jussi Kivilinna <jussi.kivilinna at iki.fi>
Date:   Sat Jan 20 21:08:37 2018 +0200

    Add EAX mode
    
    * cipher/Makefile.am: Add 'cipher-eax.c'.
    * cipher/cipher-cmac.c (cmac_write): Rename to ...
    (_gcry_cmac_write): ... this; Take CMAC context as new input
    parameter; Return error code.
    (cmac_generate_subkeys): Rename to ...
    (_gcry_cmac_generate_subkeys): ... this; Take CMAC context as new
    input parameter; Return error code.
    (cmac_final): Rename to ...
    (_gcry_cmac_final): ... this; Take CMAC context as new input
    parameter; Return error code.
    (cmac_tag): Take CMAC context as new input parameter.
    (_gcry_cmac_reset): New.
    (_gcry_cipher_cmac_authenticate): Remove duplicate tag flag check;
    Adapt to changes above.
    (_gcry_cipher_cmac_get_tag): Adapt to changes above.
    (_gcry_cipher_cmac_check_tag): Ditto.
    (_gcry_cipher_cmac_set_subkeys): Ditto.
    * cipher-eax.c: New.
    * cipher-internal.h (gcry_cmac_context_t): New.
    (gcry_cipher_handle): Update u_mode.cmac; Add u_mode.eax.
    (_gcry_cmac_write, _gcry_cmac_generate_subkeys, _gcry_cmac_final)
    (_gcry_cmac_reset, _gcry_cipher_eax_encrypt, _gcry_cipher_eax_decrypt)
    (_gcry_cipher_eax_set_nonce, _gcry_cipher_eax_authenticate)
    (_gcry_cipher_eax_get_tag, _gcry_cipher_eax_check_tag)
    (_gcry_cipher_eax_setkey): New prototypes.
    * cipher/cipher.c (_gcry_cipher_open_internal, cipher_setkey)
    (cipher_reset, cipher_encrypt, cipher_decrypt, _gcry_cipher_setiv)
    (_gcry_cipher_authenticate, _gcry_cipher_gettag, _gcry_cipher_checktag)
    (_gcry_cipher_info): Add EAX mode.
    * doc/gcrypt.texi: Add EAX mode.
    * src/gcrypt.h.in (GCRY_CIPHER_MODE_EAX): New.
    * tests/basic.c (_check_gcm_cipher, _check_poly1305_cipher): Constify
    test vectors array.
    (_check_eax_cipher, check_eax_cipher): New.
    (check_ciphers, check_cipher_modes): Add EAX mode.
    * tests/bench-slope.c (bench_eax_encrypt_do_bench)
    (bench_eax_decrypt_do_bench, bench_eax_authenticate_do_bench)
    (eax_encrypt_ops, eax_decrypt_ops, eax_authenticate_ops): New.
    (cipher_modes): Add EAX mode.
    * tests/benchmark.c (cipher_bench): Add EAX mode.
    --
    
    Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index bba815b..6e6c5ac 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -44,7 +44,7 @@ cipher.c cipher-internal.h \
 cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \
 cipher-ccm.c cipher-cmac.c cipher-gcm.c cipher-gcm-intel-pclmul.c \
   cipher-gcm-armv8-aarch32-ce.S cipher-gcm-armv8-aarch64-ce.S \
-cipher-poly1305.c cipher-ocb.c cipher-xts.c \
+cipher-poly1305.c cipher-ocb.c cipher-xts.c cipher-eax.c \
 cipher-selftest.c cipher-selftest.h \
 pubkey.c pubkey-internal.h pubkey-util.c \
 md.c \
diff --git a/cipher/cipher-cmac.c b/cipher/cipher-cmac.c
index da3ef75..30567b7 100644
--- a/cipher/cipher-cmac.c
+++ b/cipher/cipher-cmac.c
@@ -1,5 +1,5 @@
 /* cmac.c - CMAC, Cipher-based MAC.
- * Copyright (C) 2013 Jussi Kivilinna <jussi.kivilinna at iki.fi>
+ * Copyright (C) 2013,2018 Jussi Kivilinna <jussi.kivilinna at iki.fi>
  *
  * This file is part of Libgcrypt.
  *
@@ -33,8 +33,9 @@
   (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0)
 
 
-static void
-cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen)
+gcry_err_code_t
+_gcry_cmac_write (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx,
+		  const byte * inbuf, size_t inlen)
 {
   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
   const unsigned int blocksize = c->spec->blocksize;
@@ -42,31 +43,37 @@ cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen)
   unsigned int burn = 0;
   unsigned int nblocks;
 
+  if (ctx->tag)
+    return GPG_ERR_INV_STATE;
+
   /* Tell compiler that we require a cipher with a 64bit or 128 bit block
    * length, to allow better optimization of this function.  */
   if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
-    return;
+    return GPG_ERR_INV_CIPHER_MODE;
 
-  if (!inlen || !inbuf)
-    return;
+  if (!inbuf)
+    return GPG_ERR_INV_ARG;
+
+  if (inlen == 0)
+    return 0;
 
   /* Last block is needed for cmac_final.  */
-  if (c->unused + inlen <= blocksize)
+  if (ctx->mac_unused + inlen <= blocksize)
     {
-      for (; inlen && c->unused < blocksize; inlen--)
-        c->lastiv[c->unused++] = *inbuf++;
-      return;
+      for (; inlen && ctx->mac_unused < blocksize; inlen--)
+        ctx->macbuf[ctx->mac_unused++] = *inbuf++;
+      return 0;
     }
 
-  if (c->unused)
+  if (ctx->mac_unused)
     {
-      for (; inlen && c->unused < blocksize; inlen--)
-        c->lastiv[c->unused++] = *inbuf++;
+      for (; inlen && ctx->mac_unused < blocksize; inlen--)
+        ctx->macbuf[ctx->mac_unused++] = *inbuf++;
 
-      buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
-      set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv));
+      buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize);
+      set_burn (burn, enc_fn (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv));
 
-      c->unused = 0;
+      ctx->mac_unused = 0;
     }
 
   if (c->bulk.cbc_enc && inlen > blocksize)
@@ -74,7 +81,7 @@ cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen)
       nblocks = inlen / blocksize;
       nblocks -= (nblocks * blocksize == inlen);
 
-      c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, 1);
+      c->bulk.cbc_enc (&c->context.c, ctx->u_iv.iv, outbuf, inbuf, nblocks, 1);
       inbuf += nblocks * blocksize;
       inlen -= nblocks * blocksize;
 
@@ -83,8 +90,8 @@ cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen)
   else
     while (inlen > blocksize)
       {
-        buf_xor (c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
-        set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv));
+        buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, inbuf, blocksize);
+        set_burn (burn, enc_fn (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv));
         inlen -= blocksize;
         inbuf += blocksize;
       }
@@ -93,16 +100,18 @@ cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen)
   if (inlen == 0)
     BUG ();
 
-  for (; inlen && c->unused < blocksize; inlen--)
-    c->lastiv[c->unused++] = *inbuf++;
+  for (; inlen && ctx->mac_unused < blocksize; inlen--)
+    ctx->macbuf[ctx->mac_unused++] = *inbuf++;
 
   if (burn)
     _gcry_burn_stack (burn + 4 * sizeof (void *));
+
+  return 0;
 }
 
 
-static void
-cmac_generate_subkeys (gcry_cipher_hd_t c)
+gcry_err_code_t
+_gcry_cmac_generate_subkeys (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx)
 {
   const unsigned int blocksize = c->spec->blocksize;
   byte rb, carry, t, bi;
@@ -117,7 +126,7 @@ cmac_generate_subkeys (gcry_cipher_hd_t c)
   /* Tell compiler that we require a cipher with a 64bit or 128 bit block
    * length, to allow better optimization of this function.  */
   if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
-    return;
+    return GPG_ERR_INV_CIPHER_MODE;
 
   if (MAX_BLOCKSIZE < blocksize)
     BUG ();
@@ -127,7 +136,7 @@ cmac_generate_subkeys (gcry_cipher_hd_t c)
   burn = c->spec->encrypt (&c->context.c, u.buf, u.buf);
 
   /* Currently supported blocksizes are 16 and 8. */
-  rb = blocksize == 16 ? 0x87 : 0x1B /*blocksize == 8 */ ;
+  rb = blocksize == 16 ? 0x87 : 0x1B /* blocksize == 8 */ ;
 
   for (j = 0; j < 2; j++)
     {
@@ -139,93 +148,113 @@ cmac_generate_subkeys (gcry_cipher_hd_t c)
           t = carry | (bi << 1);
           carry = bi >> 7;
           u.buf[i] = t & 0xff;
-          c->u_mode.cmac.subkeys[j][i] = u.buf[i];
+          ctx->subkeys[j][i] = u.buf[i];
         }
       u.buf[blocksize - 1] ^= carry ? rb : 0;
-      c->u_mode.cmac.subkeys[j][blocksize - 1] = u.buf[blocksize - 1];
+      ctx->subkeys[j][blocksize - 1] = u.buf[blocksize - 1];
     }
 
   wipememory (&u, sizeof (u));
   if (burn)
     _gcry_burn_stack (burn + 4 * sizeof (void *));
+
+  return 0;
 }
 
 
-static void
-cmac_final (gcry_cipher_hd_t c)
+gcry_err_code_t
+_gcry_cmac_final (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx)
 {
   const unsigned int blocksize = c->spec->blocksize;
-  unsigned int count = c->unused;
+  unsigned int count = ctx->mac_unused;
   unsigned int burn;
   byte *subkey;
 
   /* Tell compiler that we require a cipher with a 64bit or 128 bit block
    * length, to allow better optimization of this function.  */
   if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
-    return;
+    return GPG_ERR_INV_CIPHER_MODE;
 
   if (count == blocksize)
-    subkey = c->u_mode.cmac.subkeys[0];        /* K1 */
+    subkey = ctx->subkeys[0];        /* K1 */
   else
     {
-      subkey = c->u_mode.cmac.subkeys[1];      /* K2 */
-      c->lastiv[count++] = 0x80;
+      subkey = ctx->subkeys[1];      /* K2 */
+      ctx->macbuf[count++] = 0x80;
       while (count < blocksize)
-        c->lastiv[count++] = 0;
+        ctx->macbuf[count++] = 0;
     }
 
-  buf_xor (c->lastiv, c->lastiv, subkey, blocksize);
+  buf_xor (ctx->macbuf, ctx->macbuf, subkey, blocksize);
 
-  buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
-  burn = c->spec->encrypt (&c->context.c, c->u_iv.iv, c->u_iv.iv);
+  buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize);
+  burn = c->spec->encrypt (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv);
   if (burn)
     _gcry_burn_stack (burn + 4 * sizeof (void *));
 
-  c->unused = 0;
+  ctx->mac_unused = 0;
+
+  return 0;
 }
 
 
 static gcry_err_code_t
-cmac_tag (gcry_cipher_hd_t c, unsigned char *tag, size_t taglen, int check)
+cmac_tag (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx,
+	  unsigned char *tag, size_t taglen, int check)
 {
+  gcry_err_code_t ret;
+
   if (!tag || taglen == 0 || taglen > c->spec->blocksize)
     return GPG_ERR_INV_ARG;
 
-  if (!c->u_mode.cmac.tag)
+  if (!ctx->tag)
     {
-      cmac_final (c);
-      c->u_mode.cmac.tag = 1;
+      ret = _gcry_cmac_final (c, ctx);
+      if (ret != 0)
+	return ret;
+
+      ctx->tag = 1;
     }
 
   if (!check)
     {
-      memcpy (tag, c->u_iv.iv, taglen);
+      memcpy (tag, ctx->u_iv.iv, taglen);
       return GPG_ERR_NO_ERROR;
     }
   else
     {
-      return buf_eq_const (tag, c->u_iv.iv, taglen) ?
+      return buf_eq_const (tag, ctx->u_iv.iv, taglen) ?
         GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
     }
 }
 
 
+void
+_gcry_cmac_reset (gcry_cmac_context_t *ctx)
+{
+  char tmp_buf[sizeof(ctx->subkeys)];
+
+  /* Only keep subkeys when reseting context. */
+
+  buf_cpy (tmp_buf, ctx->subkeys, sizeof(ctx->subkeys));
+  memset (ctx, 0, sizeof(*ctx));
+  buf_cpy (ctx->subkeys, tmp_buf, sizeof(ctx->subkeys));
+  wipememory (tmp_buf, sizeof(tmp_buf));
+}
+
+
 gcry_err_code_t
 _gcry_cipher_cmac_authenticate (gcry_cipher_hd_t c,
                                 const unsigned char *abuf, size_t abuflen)
 {
   if (abuflen > 0 && !abuf)
     return GPG_ERR_INV_ARG;
-  if (c->u_mode.cmac.tag)
-    return GPG_ERR_INV_STATE;
   /* To support new blocksize, update cmac_generate_subkeys() then add new
      blocksize here. */
   if (c->spec->blocksize != 16 && c->spec->blocksize != 8)
     return GPG_ERR_INV_CIPHER_MODE;
 
-  cmac_write (c, abuf, abuflen);
-
-  return GPG_ERR_NO_ERROR;
+  return _gcry_cmac_write (c, &c->u_mode.cmac, abuf, abuflen);
 }
 
 
@@ -233,7 +262,7 @@ gcry_err_code_t
 _gcry_cipher_cmac_get_tag (gcry_cipher_hd_t c,
                            unsigned char *outtag, size_t taglen)
 {
-  return cmac_tag (c, outtag, taglen, 0);
+  return cmac_tag (c, &c->u_mode.cmac, outtag, taglen, 0);
 }
 
 
@@ -241,13 +270,11 @@ gcry_err_code_t
 _gcry_cipher_cmac_check_tag (gcry_cipher_hd_t c,
                              const unsigned char *intag, size_t taglen)
 {
-  return cmac_tag (c, (unsigned char *) intag, taglen, 1);
+  return cmac_tag (c, &c->u_mode.cmac, (unsigned char *) intag, taglen, 1);
 }
 
 gcry_err_code_t
 _gcry_cipher_cmac_set_subkeys (gcry_cipher_hd_t c)
 {
-  cmac_generate_subkeys (c);
-
-  return GPG_ERR_NO_ERROR;
+  return _gcry_cmac_generate_subkeys (c, &c->u_mode.cmac);
 }
diff --git a/cipher/cipher-eax.c b/cipher/cipher-eax.c
new file mode 100644
index 0000000..1ce4797
--- /dev/null
+++ b/cipher/cipher-eax.c
@@ -0,0 +1,248 @@
+/* cipher-eax.c  -  EAX implementation
+ * Copyright (C) 2018 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 "bufhelp.h"
+#include "./cipher-internal.h"
+
+
+gcry_err_code_t
+_gcry_cipher_eax_encrypt (gcry_cipher_hd_t c,
+                          byte *outbuf, size_t outbuflen,
+                          const byte *inbuf, size_t inbuflen)
+{
+  gcry_err_code_t err;
+
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+  if (c->marks.tag)
+    return GPG_ERR_INV_STATE;
+
+  if (!c->marks.iv)
+    {
+      err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
+      if (err != 0)
+	return err;
+    }
+
+  err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+  if (err != 0)
+    return err;
+
+  return _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, outbuf, inbuflen);
+}
+
+
+gcry_err_code_t
+_gcry_cipher_eax_decrypt (gcry_cipher_hd_t c,
+                          byte *outbuf, size_t outbuflen,
+                          const byte *inbuf, size_t inbuflen)
+{
+  gcry_err_code_t err;
+
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+  if (c->marks.tag)
+    return GPG_ERR_INV_STATE;
+
+  if (!c->marks.iv)
+    {
+      err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
+      if (err != 0)
+	return err;
+    }
+
+  err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, inbuf, inbuflen);
+  if (err != 0)
+    return err;
+
+  return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+}
+
+
+gcry_err_code_t
+_gcry_cipher_eax_authenticate (gcry_cipher_hd_t c,
+                               const byte * aadbuf, size_t aadbuflen)
+{
+  gcry_err_code_t err;
+
+  if (c->marks.tag)
+    return GPG_ERR_INV_STATE;
+
+  if (!c->marks.iv)
+    {
+      err = _gcry_cipher_eax_set_nonce (c, NULL, 0);
+      if (err != 0)
+	return err;
+    }
+
+  return _gcry_cmac_write (c, &c->u_mode.eax.cmac_header, aadbuf, aadbuflen);
+}
+
+
+gcry_err_code_t
+_gcry_cipher_eax_setkey (gcry_cipher_hd_t c)
+{
+  gcry_err_code_t err;
+
+  err = _gcry_cmac_generate_subkeys (c, &c->u_mode.eax.cmac_header);
+  if (err != 0)
+    return err;
+
+  buf_cpy (c->u_mode.eax.cmac_ciphertext.subkeys,
+	   c->u_mode.eax.cmac_header.subkeys,
+	   sizeof(c->u_mode.eax.cmac_header.subkeys));
+
+  return 0;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_eax_set_nonce (gcry_cipher_hd_t c, const byte *nonce,
+			    size_t noncelen)
+{
+  gcry_cmac_context_t nonce_cmac;
+  unsigned char initbuf[MAX_BLOCKSIZE];
+  gcry_err_code_t err;
+
+  c->marks.iv = 0;
+  c->marks.tag = 0;
+
+  _gcry_cmac_reset (&c->u_mode.eax.cmac_header);
+  _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext);
+
+  /* Calculate nonce CMAC */
+
+  memset(&nonce_cmac, 0, sizeof(nonce_cmac));
+  memset(&initbuf, 0, sizeof(initbuf));
+
+  buf_cpy (&nonce_cmac.subkeys, c->u_mode.eax.cmac_header.subkeys,
+	   sizeof(c->u_mode.eax.cmac_header.subkeys));
+
+  err = _gcry_cmac_write (c, &nonce_cmac, initbuf, c->spec->blocksize);
+  if (err != 0)
+    return err;
+
+  if (noncelen != 0)
+    {
+      err = _gcry_cmac_write (c, &nonce_cmac, nonce, noncelen);
+      if (err != 0)
+        return err;
+    }
+
+  err = _gcry_cmac_final (c, &nonce_cmac);
+  if (err != 0)
+    return err;
+
+  buf_cpy (c->u_iv.iv, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE);
+  buf_cpy (c->u_ctr.ctr, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE);
+
+  wipememory (&nonce_cmac, sizeof(nonce_cmac));
+
+  /* Prepare header CMAC */
+
+  initbuf[c->spec->blocksize - 1] = 1;
+  err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_header, initbuf,
+			  c->spec->blocksize);
+  if (err != 0)
+    return err;
+
+  /* Prepare ciphertext CMAC */
+
+  initbuf[c->spec->blocksize - 1] = 2;
+  err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, initbuf,
+			  c->spec->blocksize);
+  if (err != 0)
+    return err;
+
+  c->marks.iv = 1;
+  c->marks.tag = 0;
+
+  return 0;
+}
+
+
+static gcry_err_code_t
+_gcry_cipher_eax_tag (gcry_cipher_hd_t c,
+                      byte *outbuf, size_t outbuflen, int check)
+{
+  gcry_err_code_t err;
+
+  if (!c->marks.tag)
+    {
+      err = _gcry_cmac_final (c, &c->u_mode.eax.cmac_header);
+      if (err != 0)
+	return err;
+
+      err = _gcry_cmac_final (c, &c->u_mode.eax.cmac_ciphertext);
+      if (err != 0)
+	return err;
+
+      buf_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_header.u_iv.iv, MAX_BLOCKSIZE);
+      buf_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_ciphertext.u_iv.iv,
+		 MAX_BLOCKSIZE);
+
+      _gcry_cmac_reset (&c->u_mode.eax.cmac_header);
+      _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext);
+
+      c->marks.tag = 1;
+    }
+
+  if (!check)
+    {
+      if (outbuflen > c->spec->blocksize)
+        outbuflen = c->spec->blocksize;
+
+      /* NB: We already checked that OUTBUF is large enough to hold
+       * the result or has valid truncated length.  */
+      memcpy (outbuf, c->u_iv.iv, outbuflen);
+    }
+  else
+    {
+      /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF
+       * and thus we need to compare its length first.  */
+      if (!(outbuflen <= c->spec->blocksize)
+          || !buf_eq_const (outbuf, c->u_iv.iv, outbuflen))
+        return GPG_ERR_CHECKSUM;
+    }
+
+  return 0;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_eax_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
+                          size_t taglen)
+{
+  return _gcry_cipher_eax_tag (c, outtag, taglen, 0);
+}
+
+gcry_err_code_t
+_gcry_cipher_eax_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
+                            size_t taglen)
+{
+  return _gcry_cipher_eax_tag (c, (unsigned char *) intag, taglen, 1);
+}
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index 8c897d7..a0ede5e 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -109,6 +109,25 @@ typedef union
 } cipher_context_alignment_t;
 
 
+/* Storage structure for CMAC, for CMAC and EAX modes. */
+typedef struct {
+  /* The initialization vector. Also contains tag after finalization. */
+  union {
+    cipher_context_alignment_t iv_align;
+    unsigned char iv[MAX_BLOCKSIZE];
+  } u_iv;
+
+  /* Subkeys for tag creation, not cleared by gcry_cipher_reset. */
+  unsigned char subkeys[2][MAX_BLOCKSIZE];
+
+  /* Space to save partial input lengths for MAC. */
+  unsigned char macbuf[MAX_BLOCKSIZE];
+
+  int mac_unused;  /* Number of unprocessed bytes in MACBUF. */
+  unsigned int tag:1; /* Set to 1 if tag has been finalized.  */
+} gcry_cmac_context_t;
+
+
 /* The handle structure.  */
 struct gcry_cipher_handle
 {
@@ -197,7 +216,7 @@ struct gcry_cipher_handle
 
       unsigned char s0[GCRY_CCM_BLOCK_LEN];
 
-      unsigned int nonce:1;/* Set to 1 if nonce has been set.  */
+      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.  */
     } ccm;
@@ -217,12 +236,16 @@ struct gcry_cipher_handle
     } poly1305;
 
     /* Mode specific storage for CMAC mode. */
+    gcry_cmac_context_t cmac;
+
+    /* Mode specific storage for EAX mode. */
     struct {
-      unsigned int tag:1; /* Set to 1 if tag has been finalized.  */
+      /* CMAC for header (AAD). */
+      gcry_cmac_context_t cmac_header;
 
-      /* Subkeys for tag creation, not cleared by gcry_cipher_reset. */
-      unsigned char subkeys[2][MAX_BLOCKSIZE];
-    } cmac;
+      /* CMAC for ciphertext. */
+      gcry_cmac_context_t cmac_ciphertext;
+    } eax;
 
     /* Mode specific storage for GCM mode. */
     struct {
@@ -236,7 +259,6 @@ struct gcry_cipher_handle
       unsigned char macbuf[GCRY_CCM_BLOCK_LEN];
       int mac_unused;  /* Number of unprocessed bytes in MACBUF. */
 
-
       /* byte counters for GCM */
       u32 aadlen[2];
       u32 datalen[2];
@@ -309,7 +331,6 @@ struct gcry_cipher_handle
          processed.  */
       unsigned int data_finalized:1;
       unsigned int aad_finalized:1;
-
     } ocb;
 
     /* Mode specific storage for XTS mode. */
@@ -406,6 +427,42 @@ gcry_err_code_t _gcry_cipher_ccm_check_tag
                  const unsigned char *intag, size_t taglen);
 
 
+/*-- cipher-cmac.c --*/
+gcry_err_code_t _gcry_cmac_generate_subkeys
+/*           */ (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx);
+gcry_err_code_t _gcry_cmac_write
+/*           */ (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx,
+		 const byte * inbuf, size_t inlen);
+gcry_err_code_t _gcry_cmac_final
+/*           */ (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx);
+void _gcry_cmac_reset (gcry_cmac_context_t *ctx);
+
+
+/*-- cipher-eax.c --*/
+gcry_err_code_t _gcry_cipher_eax_encrypt
+/*           */   (gcry_cipher_hd_t c,
+                   unsigned char *outbuf, size_t outbuflen,
+                   const unsigned char *inbuf, size_t inbuflen);
+gcry_err_code_t _gcry_cipher_eax_decrypt
+/*           */   (gcry_cipher_hd_t c,
+                   unsigned char *outbuf, size_t outbuflen,
+                   const unsigned char *inbuf, size_t inbuflen);
+gcry_err_code_t _gcry_cipher_eax_set_nonce
+/*           */   (gcry_cipher_hd_t c,
+                   const unsigned char *nonce, size_t noncelen);
+gcry_err_code_t _gcry_cipher_eax_authenticate
+/*           */   (gcry_cipher_hd_t c,
+                   const unsigned char *aadbuf, size_t aadbuflen);
+gcry_err_code_t _gcry_cipher_eax_get_tag
+/*           */   (gcry_cipher_hd_t c,
+                   unsigned char *outtag, size_t taglen);
+gcry_err_code_t _gcry_cipher_eax_check_tag
+/*           */   (gcry_cipher_hd_t c,
+                   const unsigned char *intag, size_t taglen);
+gcry_err_code_t _gcry_cipher_eax_setkey
+/*           */   (gcry_cipher_hd_t c);
+
+
 /*-- cipher-gcm.c --*/
 gcry_err_code_t _gcry_cipher_gcm_encrypt
 /*           */   (gcry_cipher_hd_t c,
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 18b2591..1bef766 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -420,6 +420,7 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
       case GCRY_CIPHER_MODE_CTR:
       case GCRY_CIPHER_MODE_AESWRAP:
       case GCRY_CIPHER_MODE_CMAC:
+      case GCRY_CIPHER_MODE_EAX:
       case GCRY_CIPHER_MODE_GCM:
 	if (!spec->encrypt || !spec->decrypt)
 	  err = GPG_ERR_INV_CIPHER_MODE;
@@ -688,7 +689,11 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
       switch (c->mode)
         {
         case GCRY_CIPHER_MODE_CMAC:
-          _gcry_cipher_cmac_set_subkeys (c);
+          rc = _gcry_cipher_cmac_set_subkeys (c);
+          break;
+
+        case GCRY_CIPHER_MODE_EAX:
+          rc = _gcry_cipher_eax_setkey (c);
           break;
 
         case GCRY_CIPHER_MODE_GCM:
@@ -782,8 +787,12 @@ cipher_reset (gcry_cipher_hd_t c)
   switch (c->mode)
     {
     case GCRY_CIPHER_MODE_CMAC:
-      /* Only clear 'tag' for cmac, keep subkeys. */
-      c->u_mode.cmac.tag = 0;
+      _gcry_cmac_reset(&c->u_mode.cmac);
+      break;
+
+    case GCRY_CIPHER_MODE_EAX:
+      _gcry_cmac_reset(&c->u_mode.eax.cmac_header);
+      _gcry_cmac_reset(&c->u_mode.eax.cmac_ciphertext);
       break;
 
     case GCRY_CIPHER_MODE_GCM:
@@ -929,6 +938,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
       rc = GPG_ERR_INV_CIPHER_MODE;
       break;
 
+    case GCRY_CIPHER_MODE_EAX:
+      rc = _gcry_cipher_eax_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+      break;
+
     case GCRY_CIPHER_MODE_GCM:
       rc = _gcry_cipher_gcm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
@@ -1060,6 +1073,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
       rc = GPG_ERR_INV_CIPHER_MODE;
       break;
 
+    case GCRY_CIPHER_MODE_EAX:
+      rc = _gcry_cipher_eax_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+      break;
+
     case GCRY_CIPHER_MODE_GCM:
       rc = _gcry_cipher_gcm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
@@ -1158,6 +1175,10 @@ _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen)
         rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen);
         break;
 
+      case GCRY_CIPHER_MODE_EAX:
+        rc =  _gcry_cipher_eax_set_nonce (hd, iv, ivlen);
+        break;
+
       case GCRY_CIPHER_MODE_GCM:
         rc =  _gcry_cipher_gcm_setiv (hd, iv, ivlen);
         break;
@@ -1226,6 +1247,10 @@ _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf,
       rc = _gcry_cipher_cmac_authenticate (hd, abuf, abuflen);
       break;
 
+    case GCRY_CIPHER_MODE_EAX:
+      rc = _gcry_cipher_eax_authenticate (hd, abuf, abuflen);
+      break;
+
     case GCRY_CIPHER_MODE_GCM:
       rc = _gcry_cipher_gcm_authenticate (hd, abuf, abuflen);
       break;
@@ -1263,6 +1288,10 @@ _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen)
       rc = _gcry_cipher_cmac_get_tag (hd, outtag, taglen);
       break;
 
+    case GCRY_CIPHER_MODE_EAX:
+      rc = _gcry_cipher_eax_get_tag (hd, outtag, taglen);
+      break;
+
     case GCRY_CIPHER_MODE_GCM:
       rc = _gcry_cipher_gcm_get_tag (hd, outtag, taglen);
       break;
@@ -1300,6 +1329,10 @@ _gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen)
       rc = _gcry_cipher_cmac_check_tag (hd, intag, taglen);
       break;
 
+    case GCRY_CIPHER_MODE_EAX:
+      rc = _gcry_cipher_eax_check_tag (hd, intag, taglen);
+      break;
+
     case GCRY_CIPHER_MODE_GCM:
       rc = _gcry_cipher_gcm_check_tag (hd, intag, taglen);
       break;
@@ -1501,6 +1534,10 @@ _gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes)
               *nbytes = h->u_mode.ccm.authlen;
               break;
 
+            case GCRY_CIPHER_MODE_EAX:
+              *nbytes = h->spec->blocksize;
+              break;
+
             case GCRY_CIPHER_MODE_GCM:
               *nbytes = GCRY_GCM_BLOCK_LEN;
               break;
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 7831505..ccb4b82 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -1722,6 +1722,12 @@ value is automatically incremented after each call of
 Auto-increment allows avoiding need of setting IV between processing
 of sequential data units.
 
+ at item  GCRY_CIPHER_MODE_EAX
+ at cindex EAX, EAX mode
+EAX is an Authenticated Encryption with Associated Data (AEAD) block cipher
+mode by Bellare, Rogaway, and Wagner (see
+ at uref{http://web.cs.ucdavis.edu/~rogaway/papers/eax.html}).
+
 @end table
 
 @node Working with cipher handles
@@ -1752,12 +1758,13 @@ with some algorithms - in particular, stream mode
 Poly1305 AEAD mode (@code{GCRY_CIPHER_MODE_POLY1305}) only works with
 ChaCha20 stream cipher. The block cipher modes
 (@code{GCRY_CIPHER_MODE_ECB}, @code{GCRY_CIPHER_MODE_CBC},
- at code{GCRY_CIPHER_MODE_CFB}, @code{GCRY_CIPHER_MODE_OFB} and
- at code{GCRY_CIPHER_MODE_CTR}) will work with any block cipher
-algorithm.  GCM mode (@code{GCRY_CIPHER_MODE_CCM}), CCM mode
-(@code{GCRY_CIPHER_MODE_GCM}), OCB mode (@code{GCRY_CIPHER_MODE_OCB}),
-and XTS mode (@code{GCRY_CIPHER_MODE_XTS}) will only work
-with block cipher algorithms which have the block size of 16 bytes.
+ at code{GCRY_CIPHER_MODE_CFB}, @code{GCRY_CIPHER_MODE_OFB},
+ at code{GCRY_CIPHER_MODE_CTR} and @code{GCRY_CIPHER_MODE_EAX}) will work
+with any block cipher algorithm.  GCM mode
+(@code{GCRY_CIPHER_MODE_CCM}), CCM mode (@code{GCRY_CIPHER_MODE_GCM}),
+OCB mode (@code{GCRY_CIPHER_MODE_OCB}), and XTS mode
+(@code{GCRY_CIPHER_MODE_XTS}) 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 1eb3d7c..83f94b6 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -971,7 +971,8 @@ enum gcry_cipher_modes
     GCRY_CIPHER_MODE_POLY1305 = 10,  /* Poly1305 based AEAD mode. */
     GCRY_CIPHER_MODE_OCB      = 11,  /* OCB3 mode.  */
     GCRY_CIPHER_MODE_CFB8     = 12,  /* Cipher feedback (8 bit mode). */
-    GCRY_CIPHER_MODE_XTS      = 13  /* XTS mode.  */
+    GCRY_CIPHER_MODE_XTS      = 13,  /* XTS mode.  */
+    GCRY_CIPHER_MODE_EAX      = 14   /* EAX mode.  */
   };
 
 /* Flags used with the open function. */
diff --git a/tests/basic.c b/tests/basic.c
index c2b4208..c883eb3 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -1347,7 +1347,7 @@ check_ofb_cipher (void)
 static void
 _check_gcm_cipher (unsigned int step)
 {
-  struct tv
+  static const struct tv
   {
     int algo;
     char key[MAX_DATA_LEN];
@@ -1891,9 +1891,542 @@ check_gcm_cipher (void)
 
 
 static void
+_check_eax_cipher (unsigned int step)
+{
+  static const struct tv
+  {
+    int algo;
+    char key[MAX_DATA_LEN];
+    char nonce[MAX_DATA_LEN];
+    int noncelen;
+    unsigned char header[MAX_DATA_LEN];
+    int headerlen;
+    unsigned char plaintext[MAX_DATA_LEN];
+    int inlen;
+    char out[MAX_DATA_LEN];
+    char tag[MAX_DATA_LEN];
+    int taglen;
+    int should_fail;
+  } tv[] =
+    {
+      /* Test vectors from http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf */
+      { GCRY_CIPHER_AES,
+        "\x23\x39\x52\xDE\xE4\xD5\xED\x5F\x9B\x9C\x6D\x6F\xF8\x0F\xF4\x78",
+        "\x62\xEC\x67\xF9\xC3\xA4\xA4\x07\xFC\xB2\xA8\xC4\x90\x31\xA8\xB3", 16,
+        "\x6B\xFB\x91\x4F\xD0\x7E\xAE\x6B", 8,
+        "",
+        0,
+        "",
+        "\xE0\x37\x83\x0E\x83\x89\xF2\x7B\x02\x5A\x2D\x65\x27\xE7\x9D\x01", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\x91\x94\x5D\x3F\x4D\xCB\xEE\x0B\xF4\x5E\xF5\x22\x55\xF0\x95\xA4",
+        "\xBE\xCA\xF0\x43\xB0\xA2\x3D\x84\x31\x94\xBA\x97\x2C\x66\xDE\xBD", 16,
+        "\xFA\x3B\xFD\x48\x06\xEB\x53\xFA", 8,
+        "\xF7\xFB",
+        2,
+        "\x19\xDD",
+        "\x5C\x4C\x93\x31\x04\x9D\x0B\xDA\xB0\x27\x74\x08\xF6\x79\x67\xE5", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\x01\xF7\x4A\xD6\x40\x77\xF2\xE7\x04\xC0\xF6\x0A\xDA\x3D\xD5\x23",
+        "\x70\xC3\xDB\x4F\x0D\x26\x36\x84\x00\xA1\x0E\xD0\x5D\x2B\xFF\x5E", 16,
+        "\x23\x4A\x34\x63\xC1\x26\x4A\xC6", 8,
+        "\x1A\x47\xCB\x49\x33",
+        5,
+        "\xD8\x51\xD5\xBA\xE0",
+        "\x3A\x59\xF2\x38\xA2\x3E\x39\x19\x9D\xC9\x26\x66\x26\xC4\x0F\x80", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\xD0\x7C\xF6\xCB\xB7\xF3\x13\xBD\xDE\x66\xB7\x27\xAF\xD3\xC5\xE8",
+        "\x84\x08\xDF\xFF\x3C\x1A\x2B\x12\x92\xDC\x19\x9E\x46\xB7\xD6\x17", 16,
+        "\x33\xCC\xE2\xEA\xBF\xF5\xA7\x9D", 8,
+        "\x48\x1C\x9E\x39\xB1",
+        5,
+        "\x63\x2A\x9D\x13\x1A",
+        "\xD4\xC1\x68\xA4\x22\x5D\x8E\x1F\xF7\x55\x93\x99\x74\xA7\xBE\xDE", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\x35\xB6\xD0\x58\x00\x05\xBB\xC1\x2B\x05\x87\x12\x45\x57\xD2\xC2",
+        "\xFD\xB6\xB0\x66\x76\xEE\xDC\x5C\x61\xD7\x42\x76\xE1\xF8\xE8\x16", 16,
+        "\xAE\xB9\x6E\xAE\xBE\x29\x70\xE9", 8,
+        "\x40\xD0\xC0\x7D\xA5\xE4",
+        6,
+        "\x07\x1D\xFE\x16\xC6\x75",
+        "\xCB\x06\x77\xE5\x36\xF7\x3A\xFE\x6A\x14\xB7\x4E\xE4\x98\x44\xDD", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\xBD\x8E\x6E\x11\x47\x5E\x60\xB2\x68\x78\x4C\x38\xC6\x2F\xEB\x22",
+        "\x6E\xAC\x5C\x93\x07\x2D\x8E\x85\x13\xF7\x50\x93\x5E\x46\xDA\x1B", 16,
+        "\xD4\x48\x2D\x1C\xA7\x8D\xCE\x0F", 8,
+        "\x4D\xE3\xB3\x5C\x3F\xC0\x39\x24\x5B\xD1\xFB\x7D",
+        12,
+        "\x83\x5B\xB4\xF1\x5D\x74\x3E\x35\x0E\x72\x84\x14",
+        "\xAB\xB8\x64\x4F\xD6\xCC\xB8\x69\x47\xC5\xE1\x05\x90\x21\x0A\x4F", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\x7C\x77\xD6\xE8\x13\xBE\xD5\xAC\x98\xBA\xA4\x17\x47\x7A\x2E\x7D",
+        "\x1A\x8C\x98\xDC\xD7\x3D\x38\x39\x3B\x2B\xF1\x56\x9D\xEE\xFC\x19", 16,
+        "\x65\xD2\x01\x79\x90\xD6\x25\x28", 8,
+        "\x8B\x0A\x79\x30\x6C\x9C\xE7\xED\x99\xDA\xE4\xF8\x7F\x8D\xD6\x16\x36",
+        17,
+        "\x02\x08\x3E\x39\x79\xDA\x01\x48\x12\xF5\x9F\x11\xD5\x26\x30\xDA\x30",
+        "\x13\x73\x27\xD1\x06\x49\xB0\xAA\x6E\x1C\x18\x1D\xB6\x17\xD7\xF2", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\x5F\xFF\x20\xCA\xFA\xB1\x19\xCA\x2F\xC7\x35\x49\xE2\x0F\x5B\x0D",
+        "\xDD\xE5\x9B\x97\xD7\x22\x15\x6D\x4D\x9A\xFF\x2B\xC7\x55\x98\x26", 16,
+        "\x54\xB9\xF0\x4E\x6A\x09\x18\x9A", 8,
+        "\x1B\xDA\x12\x2B\xCE\x8A\x8D\xBA\xF1\x87\x7D\x96\x2B\x85\x92\xDD"
+        "\x2D\x56",
+        18,
+        "\x2E\xC4\x7B\x2C\x49\x54\xA4\x89\xAF\xC7\xBA\x48\x97\xED\xCD\xAE"
+        "\x8C\xC3",
+        "\x3B\x60\x45\x05\x99\xBD\x02\xC9\x63\x82\x90\x2A\xEF\x7F\x83\x2A", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\xA4\xA4\x78\x2B\xCF\xFD\x3E\xC5\xE7\xEF\x6D\x8C\x34\xA5\x61\x23",
+        "\xB7\x81\xFC\xF2\xF7\x5F\xA5\xA8\xDE\x97\xA9\xCA\x48\xE5\x22\xEC", 16,
+        "\x89\x9A\x17\x58\x97\x56\x1D\x7E", 8,
+        "\x6C\xF3\x67\x20\x87\x2B\x85\x13\xF6\xEA\xB1\xA8\xA4\x44\x38\xD5"
+        "\xEF\x11",
+        18,
+        "\x0D\xE1\x8F\xD0\xFD\xD9\x1E\x7A\xF1\x9F\x1D\x8E\xE8\x73\x39\x38"
+        "\xB1\xE8",
+        "\xE7\xF6\xD2\x23\x16\x18\x10\x2F\xDB\x7F\xE5\x5F\xF1\x99\x17\x00", 16,
+        0
+      },
+      { GCRY_CIPHER_AES,
+        "\x83\x95\xFC\xF1\xE9\x5B\xEB\xD6\x97\xBD\x01\x0B\xC7\x66\xAA\xC3",
+        "\x22\xE7\xAD\xD9\x3C\xFC\x63\x93\xC5\x7E\xC0\xB3\xC1\x7D\x6B\x44", 16,
+        "\x12\x67\x35\xFC\xC3\x20\xD2\x5A", 8,
+        "\xCA\x40\xD7\x44\x6E\x54\x5F\xFA\xED\x3B\xD1\x2A\x74\x0A\x65\x9F"
+        "\xFB\xBB\x3C\xEA\xB7",
+        21,
+        "\xCB\x89\x20\xF8\x7A\x6C\x75\xCF\xF3\x96\x27\xB5\x6E\x3E\xD1\x97"
+        "\xC5\x52\xD2\x95\xA7",
+        "\xCF\xC4\x6A\xFC\x25\x3B\x46\x52\xB1\xAF\x37\x95\xB1\x24\xAB\x6E", 16,
+        0
+      },
+      /* Negative test for bad tag. */
+      { GCRY_CIPHER_AES,
+        "\x23\x39\x52\xDE\xE4\xD5\xED\x5F\x9B\x9C\x6D\x6F\xF8\x0F\xF4\x78",
+        "\x62\xEC\x67\xF9\xC3\xA4\xA4\x07\xFC\xB2\xA8\xC4\x90\x31\xA8\xB3", 16,
+        "\x6B\xFB\x91\x4F\xD0\x7E\xAE\x6B", 8,
+        "",
+        0,
+        "",
+        "\x00\x37\x83\x0E\x83\x89\xF2\x7B\x02\x5A\x2D\x65\x27\xE7\x9D\x01", 16,
+        1
+      },
+      /* Test vectors from libtomcrypt. */
+      {
+        GCRY_CIPHER_AES,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        "", 0,
+        "", 0,
+        "",
+        0,
+        "",
+        "\x9a\xd0\x7e\x7d\xbf\xf3\x01\xf5\x05\xde\x59\x6b\x96\x15\xdf\xff", 16,
+        0
+      },
+      {
+        GCRY_CIPHER_AES,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
+        "", 0,
+        "",
+        0,
+        "",
+        "\x1c\xe1\x0d\x3e\xff\xd4\xca\xdb\xe2\xe4\x4b\x58\xd6\x0a\xb9\xec", 16,
+        0
+      },
+      {
+        GCRY_CIPHER_AES,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        "", 0,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
+        "",
+        0,
+        "",
+        "\x3a\x69\x8f\x7a\x27\x0e\x51\xb0\xf6\x5b\x3d\x3e\x47\x19\x3c\xff", 16,
+        0
+      },
+      {
+        GCRY_CIPHER_AES,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+        "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+        32,
+        "\x29\xd8\x78\xd1\xa3\xbe\x85\x7b\x6f\xb8\xc8\xea\x59\x50\xa7\x78"
+        "\x33\x1f\xbf\x2c\xcf\x33\x98\x6f\x35\xe8\xcf\x12\x1d\xcb\x30\xbc",
+        "\x4f\xbe\x03\x38\xbe\x1c\x8c\x7e\x1d\x7a\xe7\xe4\x5b\x92\xc5\x87", 16,
+        0
+      },
+      {
+        GCRY_CIPHER_AES,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e", 15,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d", 14,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+        "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c",
+        29,
+        "\xdd\x25\xc7\x54\xc5\xb1\x7c\x59\x28\xb6\x9b\x73\x15\x5f\x7b\xb8"
+        "\x88\x8f\xaf\x37\x09\x1a\xd9\x2c\x8a\x24\xdb\x86\x8b",
+        "\x0d\x1a\x14\xe5\x22\x24\xff\xd2\x3a\x05\xfa\x02\xcd\xef\x52\xda", 16,
+        0
+      },
+    };
+
+  gcry_cipher_hd_t hde, hdd;
+  unsigned char out[MAX_DATA_LEN];
+  unsigned char tag[16];
+  int i, keylen;
+  gcry_error_t err = 0;
+  size_t pos, poslen, taglen2;
+  int byteNum;
+
+  if (verbose)
+    fprintf (stderr, "  Starting EAX checks.\n");
+
+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+    {
+      if (gcry_cipher_test_algo (tv[i].algo) && in_fips_mode)
+        {
+          if (verbose)
+            fprintf (stderr, "  algorithm %d not available in fips mode\n",
+		     tv[i].algo);
+          continue;
+        }
+
+      if (verbose)
+        fprintf (stderr, "    checking EAX 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_EAX, 0);
+      if (!err)
+        err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_EAX, 0);
+      if (err)
+        {
+          fail ("aes-eax, gcry_cipher_open failed: %s\n", gpg_strerror (err));
+          return;
+        }
+
+      keylen = gcry_cipher_get_algo_keylen(tv[i].algo);
+      if (!keylen)
+        {
+          fail ("aes-eax, 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 ("aes-eax, gcry_cipher_setkey failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          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 ("aes-eax, gcry_cipher_setiv failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      err = gcry_cipher_info (hde, GCRYCTL_GET_TAGLEN, NULL, &taglen2);
+      if (err)
+        {
+          fail ("cipher-eax, gcryctl_get_taglen failed (tv %d): %s\n",
+                i, gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+      if (taglen2 != 16)
+        {
+          fail ("cipher-eax, gcryctl_get_taglen returned bad length"
+                " (tv %d): got=%zu want=%d\n",
+                i, taglen2, 16);
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      for (pos = 0; pos < tv[i].headerlen; pos += step)
+        {
+          poslen = (pos + step < tv[i].headerlen) ?
+                    step : tv[i].headerlen - pos;
+
+          err = gcry_cipher_authenticate(hde, tv[i].header + pos, poslen);
+          if (err)
+            {
+              fail ("aes-eax, gcry_cipher_authenticate (%d) (%lu:%d) failed: "
+                    "%s\n", i, (unsigned long) pos, step, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+          err = gcry_cipher_authenticate(hdd, tv[i].header + pos, poslen);
+          if (err)
+            {
+              fail ("aes-eax, de gcry_cipher_authenticate (%d) (%lu:%d) failed: "
+	            "%s\n", i, (unsigned long) pos, step, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+        }
+
+      for (pos = 0; pos < tv[i].inlen; pos += step)
+        {
+          poslen = (pos + step < tv[i].inlen) ? step : tv[i].inlen - pos;
+
+          err = gcry_cipher_encrypt (hde, out + pos, poslen,
+                                     tv[i].plaintext + pos, poslen);
+          if (err)
+            {
+              fail ("aes-eax, gcry_cipher_encrypt (%d) (%lu:%d) failed: %s\n",
+                    i, (unsigned long) pos, step, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+        }
+
+      if (memcmp (tv[i].out, out, tv[i].inlen))
+        fail ("aes-eax, encrypt mismatch entry %d (step %d)\n", i, step);
+
+      for (pos = 0; pos < tv[i].inlen; pos += step)
+        {
+          poslen = (pos + step < tv[i].inlen) ? step : tv[i].inlen - pos;
+
+          err = gcry_cipher_decrypt (hdd, out + pos, poslen, NULL, 0);
+          if (err)
+            {
+              fail ("aes-eax, gcry_cipher_decrypt (%d) (%lu:%d) failed: %s\n",
+                    i, (unsigned long) pos, step, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+        }
+
+      if (memcmp (tv[i].plaintext, out, tv[i].inlen))
+        fail ("aes-eax, decrypt mismatch entry %d (step %d)\n", i, step);
+
+      taglen2 = tv[i].taglen ? tv[i].taglen : 16;
+
+      err = gcry_cipher_gettag (hde, out, taglen2);
+      if (err)
+        {
+          if (tv[i].should_fail)
+            goto next_tv;
+
+          fail ("aes-eax, gcry_cipher_gettag(%d) failed: %s\n",
+                i, gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      if ((memcmp (tv[i].tag, out, taglen2) != 0) ^ tv[i].should_fail)
+        fail ("aes-eax, encrypt tag mismatch entry %d\n", i);
+
+      err = gcry_cipher_checktag (hdd, tv[i].tag, taglen2);
+      if (err)
+        {
+          if (tv[i].should_fail)
+            goto next_tv;
+
+          fail ("aes-eax, gcry_cipher_checktag(%d) failed: %s\n",
+                i, gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      err = gcry_cipher_reset(hde);
+      if (!err)
+        err = gcry_cipher_reset(hdd);
+      if (err)
+        {
+          fail ("aes-eax, gcry_cipher_reset (%d) failed: %s\n",
+                i, gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      /* gcry_cipher_reset clears the IV */
+      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 ("aes-eax, gcry_cipher_setiv failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      /* this time we authenticate, encrypt and decrypt one byte at a time */
+      for (byteNum = 0; byteNum < tv[i].headerlen; ++byteNum)
+        {
+          err = gcry_cipher_authenticate(hde, tv[i].header + byteNum, 1);
+          if (err)
+            {
+              fail ("aes-eax, gcry_cipher_authenticate (%d) (byte-buf) failed: "
+                    "%s\n", i, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+          err = gcry_cipher_authenticate(hdd, tv[i].header + byteNum, 1);
+          if (err)
+            {
+              fail ("aes-eax, de gcry_cipher_authenticate (%d) (byte-buf) "
+	            "failed: %s\n", i, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+        }
+
+      for (byteNum = 0; byteNum < tv[i].inlen; ++byteNum)
+        {
+          err = gcry_cipher_encrypt (hde, out+byteNum, 1,
+                                     (tv[i].plaintext) + byteNum,
+                                     1);
+          if (err)
+            {
+              fail ("aes-eax, gcry_cipher_encrypt (%d) (byte-buf) failed: %s\n",
+                    i,  gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+        }
+
+      if (memcmp (tv[i].out, out, tv[i].inlen))
+        fail ("aes-eax, encrypt mismatch entry %d, (byte-buf)\n", i);
+
+      /* Test output to larger than 16-byte buffer. */
+      taglen2 = tv[i].taglen ? tv[i].taglen : 16 + 1;
+
+      err = gcry_cipher_gettag (hde, tag, taglen2);
+      if (err)
+        {
+          if (tv[i].should_fail)
+            goto next_tv;
+
+          fail ("aes-eax, gcry_cipher_gettag(%d, %lu) (byte-buf) failed: %s\n",
+                i, (unsigned long) taglen2, gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      taglen2 = tv[i].taglen ? tv[i].taglen : 16;
+
+      if ((memcmp (tv[i].tag, tag, taglen2) != 0) ^ tv[i].should_fail)
+        fail ("aes-eax, encrypt tag mismatch entry %d, (byte-buf)\n", i);
+
+      for (byteNum = 0; byteNum < tv[i].inlen; ++byteNum)
+        {
+          err = gcry_cipher_decrypt (hdd, out+byteNum, 1, NULL, 0);
+          if (err)
+            {
+              fail ("aes-eax, gcry_cipher_decrypt (%d) (byte-buf) failed: %s\n",
+                    i, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+        }
+
+      if (memcmp (tv[i].plaintext, out, tv[i].inlen))
+        fail ("aes-eax, decrypt mismatch entry %d\n", i);
+
+      err = gcry_cipher_checktag (hdd, tv[i].tag, taglen2);
+      if (err)
+        {
+          if (tv[i].should_fail)
+            goto next_tv;
+
+          fail ("aes-eax, gcry_cipher_checktag(%d) (byte-buf) failed: %s\n",
+                i, gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      err = gcry_cipher_checktag (hdd, tag, 17);
+      if (!err)
+        {
+          fail ("aes-eax, gcry_cipher_checktag(%d) did not fail for invalid "
+	        " tag length of '%d'\n", i, 17);
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      if (tv[i].should_fail)
+        {
+          fail ("aes-eax, negative test succeeded %d\n", i);
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+    next_tv:
+      gcry_cipher_close (hde);
+      gcry_cipher_close (hdd);
+    }
+  if (verbose)
+    fprintf (stderr, "  Completed EAX checks.\n");
+}
+
+
+static void
+check_eax_cipher (void)
+{
+  /* Large buffers, no splitting. */
+  _check_eax_cipher(0xffffffff);
+  /* Split input to one byte buffers. */
+  _check_eax_cipher(1);
+  /* Split input to 7 byte buffers. */
+  _check_eax_cipher(7);
+  /* Split input to 16 byte buffers. */
+  _check_eax_cipher(16);
+}
+
+
+static void
 _check_poly1305_cipher (unsigned int step)
 {
-  struct tv
+  static const struct tv
   {
     int algo;
     const char *key;
@@ -5813,6 +6346,7 @@ get_algo_mode_blklen (int algo, int mode)
     case GCRY_CIPHER_MODE_CTR:
     case GCRY_CIPHER_MODE_CCM:
     case GCRY_CIPHER_MODE_GCM:
+    case GCRY_CIPHER_MODE_EAX:
     case GCRY_CIPHER_MODE_POLY1305:
       return 1;
     }
@@ -5894,7 +6428,7 @@ check_one_cipher_core (int algo, int mode, int flags,
   if ((mode == GCRY_CIPHER_MODE_CBC && (flags & GCRY_CIPHER_CBC_CTS)) ||
       mode == GCRY_CIPHER_MODE_XTS)
     {
-      /* Input cannot be split in to multiple operations with CTS . */
+      /* Input cannot be split in to multiple operations with CTS. */
       blklen = nplain;
     }
 
@@ -6281,6 +6815,7 @@ check_ciphers (void)
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CBC, 0);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CTR, 0);
+      check_one_cipher (algos[i], GCRY_CIPHER_MODE_EAX, 0);
       if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_CCM_BLOCK_LEN)
         check_one_cipher (algos[i], GCRY_CIPHER_MODE_CCM, 0);
       if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_GCM_BLOCK_LEN)
@@ -6333,6 +6868,7 @@ check_cipher_modes(void)
   check_poly1305_cipher ();
   check_ocb_cipher ();
   check_xts_cipher ();
+  check_eax_cipher ();
   check_gost28147_cipher ();
   check_stream_cipher ();
   check_stream_cipher_large_block ();
diff --git a/tests/bench-slope.c b/tests/bench-slope.c
index 75e6e43..e34104f 100644
--- a/tests/bench-slope.c
+++ b/tests/bench-slope.c
@@ -1231,6 +1231,53 @@ static struct bench_ops ocb_authenticate_ops = {
   &bench_ocb_authenticate_do_bench
 };
 
+static void
+bench_eax_encrypt_do_bench (struct bench_obj *obj, void *buf,
+			    size_t buflen)
+{
+  char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
+                     0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
+                     0x00, 0x00, 0x01, 0x00 };
+  bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
+}
+
+static void
+bench_eax_decrypt_do_bench (struct bench_obj *obj, void *buf,
+			    size_t buflen)
+{
+  char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
+                     0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
+                     0x00, 0x00, 0x01, 0x00 };
+  bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
+}
+
+static void
+bench_eax_authenticate_do_bench (struct bench_obj *obj, void *buf,
+				 size_t buflen)
+{
+  char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
+                     0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
+                     0x00, 0x00, 0x01, 0x00 };
+  bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
+}
+
+static struct bench_ops eax_encrypt_ops = {
+  &bench_encrypt_init,
+  &bench_encrypt_free,
+  &bench_eax_encrypt_do_bench
+};
+
+static struct bench_ops eax_decrypt_ops = {
+  &bench_encrypt_init,
+  &bench_encrypt_free,
+  &bench_eax_decrypt_do_bench
+};
+
+static struct bench_ops eax_authenticate_ops = {
+  &bench_encrypt_init,
+  &bench_encrypt_free,
+  &bench_eax_authenticate_do_bench
+};
 
 static void
 bench_poly1305_encrypt_do_bench (struct bench_obj *obj, void *buf,
@@ -1291,6 +1338,9 @@ static struct bench_cipher_mode cipher_modes[] = {
   {GCRY_CIPHER_MODE_CCM, "CCM enc", &ccm_encrypt_ops},
   {GCRY_CIPHER_MODE_CCM, "CCM dec", &ccm_decrypt_ops},
   {GCRY_CIPHER_MODE_CCM, "CCM auth", &ccm_authenticate_ops},
+  {GCRY_CIPHER_MODE_EAX, "EAX enc",  &eax_encrypt_ops},
+  {GCRY_CIPHER_MODE_EAX, "EAX dec",  &eax_decrypt_ops},
+  {GCRY_CIPHER_MODE_EAX, "EAX auth", &eax_authenticate_ops},
   {GCRY_CIPHER_MODE_GCM, "GCM enc", &gcm_encrypt_ops},
   {GCRY_CIPHER_MODE_GCM, "GCM dec", &gcm_decrypt_ops},
   {GCRY_CIPHER_MODE_GCM, "GCM auth", &gcm_authenticate_ops},
diff --git a/tests/benchmark.c b/tests/benchmark.c
index 44a8711..59ea32c 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -779,6 +779,8 @@ cipher_bench ( const char *algoname )
       NULL, GCRY_GCM_BLOCK_LEN, GCRY_GCM_BLOCK_LEN },
     { GCRY_CIPHER_MODE_OCB, "      OCB", 1,
       NULL, 16, 16, 15 },
+    { GCRY_CIPHER_MODE_EAX, "      EAX", 0,
+      NULL, 0, 8, 8 },
     { GCRY_CIPHER_MODE_STREAM, "", 0 },
     {0}
   };

commit cd7ed2e3546b12dd98df4211949f1cdbf5827013
Author: Jussi Kivilinna <jussi.kivilinna at iki.fi>
Date:   Sun Jan 7 22:19:13 2018 +0200

    cipher: constify spec arrays
    
    * cipher/cipher.c (cipher_list): Constify array.
    * cipher/mac.c (mac_list): Constify array.
    * cipher/md.c (digest_list): Constify array.
    * cipher/pubkey.c (pubkey_list): Constify array.
    --
    
    Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>

diff --git a/cipher/cipher.c b/cipher/cipher.c
index 063c13d..18b2591 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -33,7 +33,7 @@
 
 /* This is the list of the default ciphers, which are included in
    libgcrypt.  */
-static gcry_cipher_spec_t *cipher_list[] =
+static gcry_cipher_spec_t * const cipher_list[] =
   {
 #if USE_BLOWFISH
      &_gcry_cipher_spec_blowfish,
diff --git a/cipher/mac.c b/cipher/mac.c
index 46be7b7..4a7a47d 100644
--- a/cipher/mac.c
+++ b/cipher/mac.c
@@ -29,7 +29,7 @@
 
 /* This is the list of the digest implementations included in
    libgcrypt.  */
-static gcry_mac_spec_t *mac_list[] = {
+static gcry_mac_spec_t * const mac_list[] = {
 #if USE_SHA1
   &_gcry_mac_type_spec_hmac_sha1,
 #endif
diff --git a/cipher/md.c b/cipher/md.c
index 94f1b5d..efbffe1 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -31,7 +31,7 @@
 
 /* This is the list of the digest implementations included in
    libgcrypt.  */
-static gcry_md_spec_t *digest_list[] =
+static gcry_md_spec_t * const digest_list[] =
   {
 #if USE_CRC
      &_gcry_digest_spec_crc32,
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 8ec15fd..4c07e33 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -34,7 +34,7 @@
 
 /* This is the list of the public-key algorithms included in
    Libgcrypt.  */
-static gcry_pk_spec_t *pubkey_list[] =
+static gcry_pk_spec_t * const pubkey_list[] =
   {
 #if USE_ECC
     &_gcry_pubkey_spec_ecc,

-----------------------------------------------------------------------

Summary of changes:
 cipher/Makefile.am            |   2 +-
 cipher/chacha20-amd64-ssse3.S |   4 +-
 cipher/cipher-cmac.c          | 137 ++++++-----
 cipher/cipher-eax.c           | 248 +++++++++++++++++++
 cipher/cipher-internal.h      |  71 +++++-
 cipher/cipher.c               |  45 +++-
 cipher/mac.c                  |   2 +-
 cipher/md.c                   |   2 +-
 cipher/pubkey.c               |   2 +-
 doc/gcrypt.texi               |  31 ++-
 src/gcrypt.h.in               |   3 +-
 tests/basic.c                 | 542 +++++++++++++++++++++++++++++++++++++++++-
 tests/bench-slope.c           |  50 ++++
 tests/benchmark.c             |   2 +
 14 files changed, 1053 insertions(+), 88 deletions(-)
 create mode 100644 cipher/cipher-eax.c


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org


_______________________________________________
Gnupg-commits mailing list
Gnupg-commits at gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits




More information about the Gcrypt-devel mailing list