diff --git a/ChangeLog b/ChangeLog
index fd75fe8caa5e738676d6e97885a280682de13b87..3be3a9ed194ad2eb791e89a24f01641b22add224 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2014-02-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* aead.h: New file.
+	* aead-encrypt.c: New file.
+	* aead-decrypt.c: New file.
+	* aead-encrypt-msg.c: New file.
+	* aead-decrypt-msg.c: New file.
+	* Makefile.in (nettle_SOURCES): Added new source files.
+	(HEADERS): Added aead.h.
+
 2014-02-13  Niels Möller  <nisse@lysator.liu.se>
 
 	* Makefile.in (nettle_SOURCES): Added eax-aes128.c
diff --git a/Makefile.in b/Makefile.in
index 180900539afac296656a9d7c3af8e07ee00668e6..10ae274b8494157a635aa01d7cdc8a4147b74403 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -62,7 +62,9 @@ dvi installcheck uninstallcheck:
 
 all-here: $(TARGETS) $(DOCTARGETS)
 
-nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
+nettle_SOURCES = aead-decrypt.c aead-decrypt-msg.c \
+		 aead-encrypt.c aead-encrypt-msg.c \
+		 aes-decrypt-internal.c aes-decrypt.c \
 		 aes-encrypt-internal.c aes-encrypt.c aes-encrypt-table.c \
 		 aes-invert-internal.c aes-set-key-internal.c \
 		 aes-set-encrypt-key.c aes-set-decrypt-key.c \
@@ -164,7 +166,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  ecc-ecdsa-sign.c ecdsa-sign.c \
 		  ecc-ecdsa-verify.c ecdsa-verify.c ecdsa-keygen.c
 
-HEADERS = aes.h arcfour.h arctwo.h asn1.h bignum.h blowfish.h \
+HEADERS = aead.h aes.h arcfour.h arctwo.h asn1.h bignum.h blowfish.h \
 	  base16.h base64.h buffer.h camellia.h cast128.h \
 	  cbc.h chacha.h chacha-poly1305.h ctr.h \
 	  des.h des-compat.h dsa.h eax.h ecc-curve.h ecc.h ecdsa.h \
diff --git a/aead-decrypt-msg.c b/aead-decrypt-msg.c
new file mode 100644
index 0000000000000000000000000000000000000000..026aaeffc1451308a40cb1c43c0d2c9782ace307
--- /dev/null
+++ b/aead-decrypt-msg.c
@@ -0,0 +1,73 @@
+/* aead-decrypt-msg.c
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2014 Niels Möller
+ *
+ * The nettle library 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.
+ *
+ * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "aead.h"
+
+#include "nettle-internal.h"
+#include "nettle-meta.h"
+
+size_t
+aead_decrypt_msg_size(const struct nettle_aead *aead, size_t size)
+{
+  if (size < aead->digest_size)
+    /* Invalid message */
+    return 0;
+  else
+    return size - aead->digest_size;
+}
+
+int
+aead_decrypt_msg (const struct nettle_aead *aead,
+		  void *ctx, const uint8_t *nonce,
+		  size_t ad_size, const uint8_t *ad,
+		  size_t gibberish_size,
+		  uint8_t *plaintext, const uint8_t *gibberish)
+{
+  TMP_DECL (digest, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE);
+  size_t plaintext_size;
+
+  TMP_ALLOC (digest, aead->digest_size);
+  plaintext_size = gibberish_size - aead->digest_size;
+
+  /* Allow NULL nonce, for the case that the caller already has done
+     that. E.g., if the application uses a nonce size different from
+     aead->nonce_size. */
+  if (nonce)
+    aead->set_nonce (ctx, nonce);
+  
+  if (gibberish_size < aead->digest_size)
+    /* Invalid message */
+    return 0;
+
+  aead->update (ctx, ad_size, ad);
+  aead->decrypt (ctx, plaintext_size, plaintext, gibberish);
+  aead->digest (ctx, aead->digest_size, digest);
+  return memcmp (gibberish + plaintext_size,
+		 digest, aead->digest_size) == 0;
+}
diff --git a/aead-decrypt.c b/aead-decrypt.c
new file mode 100644
index 0000000000000000000000000000000000000000..a024d7c2a60a861d295c3bfc5370f62ed70d6c26
--- /dev/null
+++ b/aead-decrypt.c
@@ -0,0 +1,180 @@
+/* aead-decrypt.c
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2014 Niels Möller
+ *
+ * The nettle library 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.
+ *
+ * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "aead.h"
+
+#include "buffer.h"
+#include "nettle-internal.h"
+#include "nettle-meta.h"
+
+#define GET_BUF(aead, ctx) \
+  ((uint8_t *)((char *) (ctx) + (aead)->context_size))
+
+/* Needs a buffer of digest_size + block_size - 1 bytes. Let this be
+   followed by an uint8_t buffer index; using a small type avoids
+   alignment issues. */
+
+size_t
+aead_decrypt_ctx_size (const struct nettle_aead *aead)
+{
+  return aead->context_size + aead->block_size + aead->digest_size;
+}
+
+void
+aead_decrypt_init (const struct nettle_aead *aead,
+		   void *ctx, const uint8_t *nonce)
+{
+  /* The case of unbuffered underlying method not supported. Niether
+     is block sizes larger than 256 bytes. */
+  assert (aead->block_size > 0);
+  assert (aead->block_size <= 256);
+
+  /* Allow NULL nonce, for the case that the caller already has done
+     that. E.g., if the application uses a nonce size different from
+     aead->nonce_size. */
+  if (nonce)
+    aead->set_nonce (ctx, nonce);
+
+  /* Initialize buffer index. */
+  GET_BUF (aead, ctx)[aead->block_size + aead->digest_size - 1] = 0;
+}
+
+size_t
+aead_decrypt (const struct nettle_aead *aead,
+	      void *ctx, struct nettle_buffer *buffer,
+	      size_t size, const uint8_t *gibberish)
+{
+  uint8_t *buf;
+  uint8_t *dst;
+  uint8_t left_over;
+  size_t done;
+  
+  buf = GET_BUF (aead, ctx);
+  left_over = buf[aead->block_size + aead->digest_size-1];
+  assert (left_over < aead->block_size + aead->digest_size);
+
+  done = 0;
+  /* First try to process buffered data, one block at a time. */
+  while (left_over > 0
+	 && left_over + size >= aead->block_size + aead->digest_size)
+    {
+      dst = nettle_buffer_space (buffer, aead->block_size);
+      if (!dst)
+	return done;
+
+      if (left_over < aead->block_size)
+	{
+	  unsigned part = aead->block_size - left_over;
+
+	  memcpy (buf + left_over, gibberish, part);
+	  aead->decrypt (ctx, aead->block_size, dst, buf);
+	  done += part;
+	  size -= part;
+	  
+	  left_over = 0;
+	}
+      else
+	{
+	  aead->decrypt (ctx, aead->block_size, dst, buf);
+	  left_over -= aead->block_size;
+	  memmove (buf, buf + aead->block_size, left_over);
+	}
+    }
+      
+  if (left_over + size < aead->block_size + aead->digest_size)
+    {
+      /* Buffer new data */
+      assert (left_over + size < aead->block_size + aead->digest_size);
+      memcpy (buf + left_over, gibberish, size);
+      buf[aead->block_size + aead->digest_size-1] = left_over + size;
+      return done + size;
+    }
+  assert (left_over == 0);
+  assert (size >= aead->digest_size);
+
+  size -= aead->digest_size;
+  left_over = size % aead->block_size;
+  size -= left_over;
+
+  dst = nettle_buffer_space (buffer, size);
+  if (!dst)
+    {
+      /* Process as many blocks as possible, without growing the
+	 buffer. */
+      size_t avail = (buffer->alloc - buffer->size);
+      avail -= (avail % aead->block_size);
+      assert (avail < size);
+      size = avail;
+      left_over = 0;
+      dst = nettle_buffer_space (buffer, size);
+      assert (dst != NULL);
+    }
+  aead->encrypt (ctx, size, dst, gibberish);
+  done += size;
+
+  /* Buffer left over + potential digest */
+  left_over += aead->digest_size;
+  memcpy (buf, gibberish + size, left_over);
+  buf[aead->block_size + aead->digest_size - 1] = left_over;
+
+  done += left_over;
+  return done;
+}
+
+size_t
+aead_decrypt_final_size (const struct nettle_aead *aead)
+{
+  return aead->block_size - 1;
+}
+
+int
+aead_decrypt_final (const struct nettle_aead *aead,
+		    void *ctx, struct nettle_buffer *buffer)
+{
+  TMP_DECL (digest, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE);
+  const uint8_t *buf = GET_BUF (aead, ctx);
+  uint8_t *dst;
+  unsigned left_over = buf[aead->block_size - 1];
+  assert (left_over < aead->block_size + aead->digest_size);
+  
+  if (left_over < aead->digest_size)
+    /* Too short */
+    return 0;
+  left_over -= aead->digest_size;
+  dst = nettle_buffer_space (buffer, left_over);
+  if (!dst)
+    return 0;
+
+  aead->encrypt (ctx, left_over, dst, buf);
+
+  TMP_ALLOC (digest, aead->digest_size);  
+  aead->digest (ctx, aead->digest_size, digest);
+  return memcmp (buf + left_over, digest, aead->digest_size) == 0;
+}
diff --git a/aead-encrypt-msg.c b/aead-encrypt-msg.c
new file mode 100644
index 0000000000000000000000000000000000000000..450548f42e10868fe96dde163c79a54603ec6888
--- /dev/null
+++ b/aead-encrypt-msg.c
@@ -0,0 +1,53 @@
+/* aead-encrypt-msg.c
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2014 Niels Möller
+ *
+ * The nettle library 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.
+ *
+ * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "aead.h"
+
+#include "nettle-meta.h"
+
+size_t
+aead_encrypt_msg_size(const struct nettle_aead *aead, size_t size)
+{
+  return size + aead->digest_size;
+}
+
+void
+aead_encrypt_msg (const struct nettle_aead *aead,
+		  void *ctx, const uint8_t *nonce,
+		  size_t ad_size, const uint8_t *ad,
+		  size_t plaintext_size,
+		  uint8_t *gibberish, const uint8_t *plaintext)
+{
+  /* Allow NULL nonce, for the case that the caller already has done
+     that. E.g., if the application uses a nonce size different from
+     aead->nonce_size. */
+  if (nonce)
+    aead->set_nonce (ctx, nonce);
+  aead->update (ctx, ad_size, ad);
+  aead->encrypt (ctx, plaintext_size, gibberish, plaintext);
+  aead->digest (ctx, aead->digest_size, gibberish + plaintext_size);
+}
diff --git a/aead-encrypt.c b/aead-encrypt.c
new file mode 100644
index 0000000000000000000000000000000000000000..1eaaa98ebf5c45a7472e0ec8c40375bf35c4ecb6
--- /dev/null
+++ b/aead-encrypt.c
@@ -0,0 +1,167 @@
+/* aead-encrypt.c
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2014 Niels Möller
+ *
+ * The nettle library 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.
+ *
+ * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "aead.h"
+
+#include "nettle-meta.h"
+#include "buffer.h"
+
+/* Needs a buffer of block_size - 1 bytes. Let this be followed by an
+   uint8_t buffer index; using a small type avoids alignment
+   issues. */
+#define GET_BUF(aead, ctx) \
+  ((uint8_t *)((char *) (ctx) + (aead)->context_size))
+
+size_t
+aead_encrypt_ctx_size (const struct nettle_aead *aead)
+{
+  return aead->context_size + aead->block_size;
+}
+
+void
+aead_encrypt_init (const struct nettle_aead *aead,
+		   void *ctx, const uint8_t *nonce)
+{
+  /* The case of unbuffered underlying method not supported. Niether
+     is block sizes larger than 256 bytes. */
+  assert (aead->block_size > 0);
+  assert (aead->block_size <= 256);
+
+  /* Allow NULL nonce, for the case that the caller already has done
+     that. E.g., if the application uses a nonce size different from
+     aead->nonce_size. */
+  if (nonce)
+    aead->set_nonce (ctx, nonce);
+
+  /* Initialize buffer index. */
+  GET_BUF (aead, ctx)[aead->block_size-1] = 0;
+}
+
+size_t
+aead_encrypt (const struct nettle_aead *aead,
+	      void *ctx, struct nettle_buffer *buffer,
+	      size_t size, const uint8_t *plaintext)
+{
+  uint8_t *buf;
+  uint8_t *dst;
+  uint8_t left_over;
+  size_t done;
+  
+  buf = GET_BUF (aead, ctx);
+  left_over = buf[aead->block_size-1];
+  assert (left_over < aead->block_size);
+
+  if (left_over > 0)
+    {
+      /* Try to fill buffer */
+      if (size >= aead->block_size - left_over)
+	{
+	  dst = nettle_buffer_space (buffer, aead->block_size);
+	  if (!dst)
+	    /* Would could copy some more data into our buffer, but we
+	       really can't make any progress until the caller
+	       provides a larger output buffer. */
+	    return 0;
+
+	  done = aead->block_size - left_over;
+	  memcpy (buf + left_over, plaintext, done);
+	  aead->encrypt (ctx, aead->block_size, dst, buf);
+	  size -= done;
+	  plaintext += done;
+	}
+      else
+	{
+	  memcpy (buf + left_over, plaintext, size);
+	  left_over += size;
+	  assert (left_over < aead->block_size);
+	  buf[aead->block_size-1] = left_over;
+	  return size;
+	}
+    }
+  else
+    done = 0;
+
+  left_over = size % aead->block_size;
+
+  dst = nettle_buffer_space (buffer, size - left_over);
+  if (dst)
+    {
+      /* Buffer rest of input. */
+      size -= left_over;
+      memcpy (buf, plaintext + size, left_over);
+      done += left_over;
+    }
+  else
+    {
+      /* Process as many blocks as possible, without growing the buffer. */
+      size_t avail = (buffer->alloc - buffer->size);
+      avail -= (avail % aead->block_size);
+      assert (avail < size);
+      size = avail;
+      left_over = 0;
+      dst = nettle_buffer_space (buffer, size);
+      assert (dst != NULL);
+    }
+  aead->encrypt (ctx, size, dst, plaintext);
+  done += size;
+
+  buf[aead->block_size-1] = left_over;
+
+  return done;
+}
+
+size_t
+aead_encrypt_final_size (const struct nettle_aead *aead)
+{
+  return aead->digest_size + aead->block_size - 1;
+}
+
+int
+aead_encrypt_final (const struct nettle_aead *aead,
+		    void *ctx, struct nettle_buffer *buffer)
+{
+  uint8_t *buf = GET_BUF (aead, ctx);
+  uint8_t *dst;
+  uint8_t left_over = buf[aead->block_size - 1];
+  assert (left_over < aead->block_size);
+  if (left_over)
+    {
+      dst = nettle_buffer_space (buffer, left_over);
+      if (!dst)
+	return 0;
+      aead->encrypt (ctx, left_over, dst, buf);
+      buf[aead->block_size - 1] = 0;
+    }
+  dst = nettle_buffer_space (buffer, aead->digest_size);
+  if (!dst)
+    return 0;
+  aead->digest (ctx, aead->digest_size, dst);
+  return 1;
+}