diff --git a/lib/modules/Crypto.pmod/GCM.pmod b/lib/modules/Crypto.pmod/GCM.pmod
deleted file mode 100644
index c8cf7f23677f1f57a8a30b9ffe999d3919494a5b..0000000000000000000000000000000000000000
--- a/lib/modules/Crypto.pmod/GCM.pmod
+++ /dev/null
@@ -1,24 +0,0 @@
-#pike __REAL_VERSION__
-#pragma strict_types
-#require constant(Nettle.GCM)
-
-//! Implementation of the Galois Counter Mode (GCM). Works as
-//! a wrapper for the cipher algorithm put in create.
-//!
-//! This is a so-called authenticated encryption with associated data
-//! (AEAD) algorithm, and in addition to encryption also provides
-//! message digests.
-//!
-//! The operation of GCM is specified in
-//! NIST Special Publication 800-38D.
-//!
-//! @note
-//!   Wrapped ciphers MUST have a block size of @expr{16@}.
-//!
-//! @note
-//!   Note that this class is not available in all versions of Nettle.
-//!
-//! @seealso
-//!   @[CBC]
-
-inherit Nettle.GCM;
diff --git a/lib/modules/SSL.pmod/Cipher.pmod b/lib/modules/SSL.pmod/Cipher.pmod
index ca3b785a561ec80e6ef3a06e9f4a60bb724f429a..92b63feccd6ee34cf77f90949bae0e308ffa48ef 100644
--- a/lib/modules/SSL.pmod/Cipher.pmod
+++ b/lib/modules/SSL.pmod/Cipher.pmod
@@ -1335,24 +1335,6 @@ class Camellia
 }
 #endif
 
-#if constant(Crypto.GCM)
-//!
-class AES_GCM
-{
-  inherit Crypto.GCM.State;
-  protected void create() { ::create(Crypto.AES()); }
-}
-
-#if constant(Crypto.Camellia)
-//!
-class Camellia_GCM
-{
-  inherit Crypto.GCM.State;
-  protected void create() { ::create(Crypto.Camellia()); }
-}
-#endif
-#endif
-
 //! Signing using RSA.
 ADT.struct rsa_sign(object session, string cookie, ADT.struct struct)
 {
@@ -1825,13 +1807,13 @@ array lookup(int suite, ProtocolVersion|int version,
       res->mac_algorithm = 0;		// MACs are not used with AEAD.
 
       break;
-#if constant(Crypto.GCM)
+#if constant(Crypto.AES.GCM)
     case MODE_gcm:
       if (res->bulk_cipher_algorithm == AES) {
-	res->bulk_cipher_algorithm = AES_GCM;
-#if constant(Crypto.Camellia)
+	res->bulk_cipher_algorithm = Crypto.AES.GCM.State;
+#if constant(Crypto.Camellia.GCM)
       } else if (res->bulk_cipher_algorithm == Camellia) {
-	res->bulk_cipher_algorithm = Camellia_GCM;
+	res->bulk_cipher_algorithm = Crypto.Camellia.GCM.State;
 #endif
       } else {
 	// Unsupported.
diff --git a/lib/modules/SSL.pmod/Constants.pmod b/lib/modules/SSL.pmod/Constants.pmod
index 3e138fb76ecfb1b8d765851e56c1bb70f89b63db..1556f407eeac5c01c9d4b69e603bd333b9f82488 100644
--- a/lib/modules/SSL.pmod/Constants.pmod
+++ b/lib/modules/SSL.pmod/Constants.pmod
@@ -902,7 +902,7 @@ constant CIPHER_SUITES =
    TLS_ecdhe_rsa_with_camellia_256_cbc_sha384: ({ KE_ecdhe_rsa, CIPHER_camellia256, HASH_sha384 }),
 #endif /* Crypto.Camellia */
 
-#if constant(Crypto.GCM)
+#if constant(Crypto.AES.GCM)
    // GCM Suites:
    TLS_rsa_with_aes_128_gcm_sha256:	({ KE_rsa, CIPHER_aes, HASH_sha256, MODE_gcm }),
    TLS_dhe_rsa_with_aes_128_gcm_sha256:	({ KE_dhe_rsa, CIPHER_aes, HASH_sha256, MODE_gcm }),
@@ -955,7 +955,7 @@ constant CIPHER_SUITES =
    TLS_ecdh_rsa_with_camellia_128_gcm_sha256: ({ KE_ecdh_rsa, CIPHER_camellia128, HASH_sha256, MODE_gcm }),
    TLS_ecdh_rsa_with_camellia_256_gcm_sha384: ({ KE_ecdh_rsa, CIPHER_camellia256, HASH_sha384, MODE_gcm }),
 #endif /* Crypto.Camellia */
-#endif /* Crypto.GCM */
+#endif /* Crypto.AES.GCM */
 ]);
 
 constant HANDSHAKE_hello_request	= 0;  // RFC 5246
diff --git a/lib/modules/__builtin.pmod/Nettle.pmod/AEAD.pike b/lib/modules/__builtin.pmod/Nettle.pmod/AEAD.pike
index f90de461ac2660be8d40aeebf709e7d9e3807a89..50fb03fdf837c07f935a2d99f8f58504387c7d1b 100644
--- a/lib/modules/__builtin.pmod/Nettle.pmod/AEAD.pike
+++ b/lib/modules/__builtin.pmod/Nettle.pmod/AEAD.pike
@@ -24,17 +24,14 @@ class State
   inherit Cipher::State;
   inherit __Hash::State;
 
-  protected void create(__builtin.Nettle.Cipher|
-			program(__builtin.Nettle.Cipher)|function c,
-			mixed ... args)
+  protected void create()
   {
     /* Needed to block the default implementation in __Hash.State. */
   }
 }
 
 //! Calling `() will return a @[State] object.
-State `()(__builtin.Nettle.Cipher|program(__builtin.Nettle.Cipher)|function c,
-	  mixed ... args) {
-  return State(c, @args);
+State `()() {
+  return State();
 }
 
diff --git a/src/post_modules/Nettle/Makefile.in b/src/post_modules/Nettle/Makefile.in
index 3cadf2ff6500279b3f7d2f4d348fffa9051920b8..79d57554d94f87fba9bb08777bf6ee951f6eb788 100644
--- a/src/post_modules/Nettle/Makefile.in
+++ b/src/post_modules/Nettle/Makefile.in
@@ -17,7 +17,7 @@ mac.o: $(SRCDIR)/mac.c
 nt.o: $(SRCDIR)/nt.c
 
 $(SRCDIR)/aead.c: aead.H
-$(SRCDIR)/cipher.c: cipher.H
+$(SRCDIR)/cipher.c: cipher.H cipher16.H
 $(SRCDIR)/hash.c: hash.H
 $(SRCDIR)/mac.c: mac.H
 
diff --git a/src/post_modules/Nettle/cipher.cmod b/src/post_modules/Nettle/cipher.cmod
index ca14e4397ae1c0bc1154abdcebd78cd90d40ba8a..f4107a07a5fd5b631b7e1a5f0b8497904d4a574a 100644
--- a/src/post_modules/Nettle/cipher.cmod
+++ b/src/post_modules/Nettle/cipher.cmod
@@ -71,6 +71,25 @@ werror(const char *format, ...)
 /*! @module Nettle
  */
 
+/* Generic callback function for Nettle in case the crypt()
+ * function in the object isn't a Nettle function.
+ */
+static void pike_crypt_func(void *object, pike_nettle_size_t length,
+			    uint8_t *dst, const uint8_t *src)
+{
+  int args;
+  struct pike_string *str;
+  push_string(make_shared_binary_string((const char *)src, length));
+  args = safe_apply(object, "crypt", 1);
+  get_all_args("crypt", args, "%n", &str);
+  if (str->len != (ptrdiff_t)length) {
+    Pike_error("Bad string length %ld returned from crypt()\n",
+	       DO_NOT_WARN((long)str->len));
+  }
+  MEMCPY(dst, str->str, length);
+  pop_n_elems(args);
+}
+
 /* Calls Pike_error on errors */ 
 typedef void (*pike_nettle_set_key_func)(void *ctx,
 					 ptrdiff_t length, const char *key,
@@ -405,11 +424,519 @@ PIKECLASS Cipher
     }
   }
   /*! @endclass State */
-
 }
+
 /*! @endclass Cipher
  */
 
+/*! @class Cipher16
+ *!
+ *! This is the @[Cipher] class extended with algorithms
+ *! that require a block size of @expr{16@} bytes.
+ *!
+ *! @seealso
+ *!   @[Cipher], @[GCM]
+ */
+PIKECLASS Cipher16
+{
+  /* NOTE: MUST be first in the class to simplify access to symbols
+   *       in Cipher!
+   */
+  /*! @inherit Cipher
+   */
+  INHERIT Nettle_Cipher;
+
+#ifdef HAVE_NETTLE_GCM_H
+#include <nettle/gcm.h>
+
+  /*! @module GCM
+   *! Implementation of the Galois Counter Mode (GCM).
+   *!
+   *! Works as a wrapper for the cipher implemented by overloading
+   *! the parent class (@[Cipher16]).
+   *!
+   *! This is a so-called authenticated encryption with associated data
+   *! (AEAD) algorithm, which in addition to encryption also provides
+   *! message digests.
+   *!
+   *! The operation of GCM is specified in
+   *! NIST Special Publication 800-38D.
+   *!
+   *! Typically accessed as @expr{Crypto.AES.GCM@} or
+   *! @expr{Crypto.Camellia.GCM@}
+   *!
+   *! @note
+   *!   Note that this module is not available in all versions of Nettle.
+   *!
+   *! @seealso
+   *!   @[CBC]
+   */
+
+  PIKEVAR object(Nettle_Cipher) GCM;
+
+  PIKECLASS _GCM
+    program_flags PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT;
+    flags ID_PROTECTED;
+  {
+    /*! @decl inherit __builtin.Nettle.AEAD
+     */
+    INHERIT "__builtin.Nettle.AEAD";
+
+    /*! @decl string(0..255) name()
+     *! Returns the name of the base cipher with @expr{".GCM"@} appended.
+     */
+    PIKEFUN string(0..255) name()
+      optflags OPT_TRY_OPTIMIZE;
+    {
+      apply_external(1, f_Nettle_Cipher_name_fun_num, args);
+      push_constant_text(".GCM");
+    }
+
+    /*! @decl int(16..16) block_size()
+     *! Returns the block size of the encapsulated cipher,
+     *! which is always @expr{16@} for GCM.
+     */
+    PIKEFUN int(16..16) block_size()
+      optflags OPT_TRY_OPTIMIZE;
+    {
+      RETURN GCM_BLOCK_SIZE;
+    }
+
+    /*! @decl int(16..16) digest_size()
+     *! Returns the size of the generated digest,
+     *! which is always @expr{16@} for GCM.
+     */
+    PIKEFUN int(16..16) digest_size()
+      optflags OPT_TRY_OPTIMIZE;
+    {
+      RETURN GCM_BLOCK_SIZE;
+    }
+
+    /*! @decl int(12..12) iv_size()
+     *! Returns the recommended size for the initialization vector
+     *! (ie @expr{12@}).
+     *!
+     *! Other sizes are allowed, but will be compressed or expanded
+     *! to this size using the encapsulated cipher.
+     */
+    PIKEFUN int(12..12) iv_size()
+      optflags OPT_TRY_OPTIMIZE;
+    {
+      RETURN GCM_IV_SIZE;
+    }
+
+    /*! @class State
+     *!
+     *! The state for a GCM instance.
+     */
+    PIKECLASS State
+      program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT;
+    {
+      DOCSTART() @decl inherit AEAD::State
+	DOCEND()
+
+      EXTRA
+      {
+	/* Perform an inherit of the State class (if any) that our parent
+	 * may contain via its inherit of __builtin.Nettle.AEAD.
+	 */
+	struct program *parent_prog = Pike_compiler->previous->new_program;
+	struct object *parent_obj = Pike_compiler->previous->fake_object;
+	int parent_State_fun_num =
+	  really_low_find_shared_string_identifier(MK_STRING("State"),
+						   parent_prog,
+						   SEE_PROTECTED|SEE_PRIVATE);
+	if (parent_State_fun_num >= 0) {
+	  struct program *parent_State_prog =
+	    low_program_from_function(parent_obj, parent_State_fun_num);
+	  if (parent_State_prog) {
+	    low_inherit(parent_State_prog, 0,
+			parent_State_fun_num +
+			parent_prog->inherits[1].identifier_level,
+			1 + 42, 0, NULL);
+	  }
+	}
+      }
+
+      PIKEVAR object object
+	flags ID_PRIVATE|ID_PROTECTED|ID_HIDDEN;
+      CVAR struct Nettle_Cipher_State_struct *crypt_state;
+      CVAR INT32 mode;
+      CVAR INT32 dmode;
+      CVAR struct gcm_key gcm_key;
+      CVAR struct gcm_ctx gcm_ctx;
+
+      /* dmode flags */
+#define NO_ADATA	1	/* Disallow associated data. */
+#define NO_CDATA	2	/* Disallow crypted data. */
+
+      INIT
+      {
+	THIS->mode = -1;
+      }
+
+      EXIT
+	gc_trivial;
+      {
+	if (THIS->object) {
+	  free_object(THIS->object);
+	  THIS->object = NULL;
+	}
+      }
+
+      /*! @decl void create()
+       *!
+       *! Initialize the GCM state.
+       */
+      PIKEFUN void create()
+	flags ID_PROTECTED;
+      {
+	struct object *o;
+	struct inherit *inh;
+	int f;
+
+	apply_external(2, Nettle_Cipher_State_program_fun_num, 0);
+	if (TYPEOF(Pike_sp[-1]) != T_OBJECT) {
+	  Pike_error("Unsupported return value from Cipher::State().\n");
+	}
+	o = Pike_sp[-1].u.object;
+	if (!o->prog) {
+	  Pike_error("Cipher::State() returned destructed object.\n");
+	}
+
+	f = find_identifier("crypt", o->prog);
+	if (f < 0) {
+	  Pike_error("State object has no crypt() function.\n");
+	}
+
+	safe_apply(o, "block_size", 0);
+
+	if (TYPEOF(Pike_sp[-1]) != T_INT)
+	  Pike_error("block_size() didn't return an int.\n");
+
+	if (Pike_sp[-1].u.integer != GCM_BLOCK_SIZE)
+	  Pike_error("cipher has an invalid block size for GCM.\n");
+
+	if (THIS->object) free_object(THIS->object);
+	add_ref(THIS->object = o);
+
+	inh = INHERIT_FROM_INT(o->prog, f);
+	if (inh->prog == Nettle_Cipher_State_program) {
+	  /* crypt() is from Nettle.Cipher.State.
+	   */
+	  THIS->crypt_state = (struct Nettle_Cipher_State_struct *)
+	    get_inherit_storage(o, inh - o->prog->inherits);
+	}
+
+	pop_n_elems(2);
+
+	THIS->mode = -1;
+      }
+
+      /*! @decl string(0..255) name()
+       *! Returns the string @expr{"x.GCM"@} where x is the
+       *! encapsulated algorithm.
+       */
+      PIKEFUN string(0..255) name()
+	optflags OPT_TRY_OPTIMIZE;
+      {
+	safe_apply(THIS->object, "name", 0);
+	push_constant_text(".GCM");
+	f_add(2);
+      }
+
+      /*! @decl int(16..16) block_size()
+       *! Returns the block size of the encapsulated cipher,
+       *! which is always @expr{16@} for GCM.
+       */
+      PIKEFUN int(16..16) block_size()
+	optflags OPT_TRY_OPTIMIZE;
+      {
+	RETURN GCM_BLOCK_SIZE;
+      }
+
+      /*! @decl int(16..16) digest_size()
+       *! Returns the size of the generated digest,
+       *! which is always @expr{16@} for GCM.
+       */
+      PIKEFUN int(16..16) digest_size()
+	optflags OPT_TRY_OPTIMIZE;
+      {
+	RETURN GCM_BLOCK_SIZE;
+      }
+
+      /*! @decl int(12..12) iv_size()
+       *! Returns the recommended size for the initialization vector
+       *! (ie @expr{12@}).
+       *!
+       *! Other sizes are allowed, but will be compressed or expanded
+       *! to this size using the encapsulated cipher.
+       */
+      PIKEFUN int(12..12) iv_size()
+	optflags OPT_TRY_OPTIMIZE;
+      {
+	RETURN GCM_IV_SIZE;
+      }
+
+      /*! @decl int(0..) key_size()
+       *! Returns the key size of the encapsulated cipher.
+       */
+      PIKEFUN int(0..) key_size()
+	optflags OPT_EXTERNAL_DEPEND;
+      {
+	safe_apply(THIS->object, "key_size", args);
+      }
+
+      /*! @decl this_program set_encrypt_key(string(0..255) key, int|void flags)
+       *!
+       *! Prepare the cipher and the wrapper for encrypting with the given
+       *! @[key]. The @[key] memory will be cleared before released.
+       *!
+       *! @note
+       *!   Note that this operation does not by itself reset the
+       *!   context sufficiently to start a new message; @[set_iv()]
+       *!   needs to be called too.
+       *!
+       *! @seealso
+       *!   @[set_decrypt_key()], @[set_iv()]
+       */
+      PIKEFUN object set_encrypt_key(string(0..255) key, int|void flags)
+	optflags OPT_SIDE_EFFECT;
+      {
+	crypt_func func = pike_crypt_func;
+	void *ctx = THIS->object;
+	key->flags |= STRING_CLEAR_ON_EXIT;
+	safe_apply(THIS->object, "set_encrypt_key", args);
+	pop_stack();
+
+	if (THIS->crypt_state && THIS->crypt_state->crypt) {
+	  func = THIS->crypt_state->crypt;
+	  ctx = THIS->crypt_state->ctx;
+	}
+	gcm_set_key(&THIS->gcm_key, ctx, func);
+	THIS->mode = 0;
+
+	push_object(this_object());
+      }
+
+      /*! @decl this_program set_decrypt_key(string(0..255) key, int|void flags)
+       *!
+       *! Prepare the cipher and the wrapper for decrypting with the given
+       *! @[key]. The @[key] memory will be cleared before released.
+       *!
+       *! @note
+       *!   Note that this operation does not by itself reset the
+       *!   context sufficiently to start a new message; @[set_iv()]
+       *!   needs to be called too.
+       *!
+       *! @seealso
+       *!   @[set_encrypt_key()], @[set_iv()]
+       */
+      PIKEFUN object set_decrypt_key(string(0..255) key, int|void flags)
+	optflags OPT_SIDE_EFFECT;
+      {
+	crypt_func func = pike_crypt_func;
+	void *ctx = THIS->object;
+	key->flags |= STRING_CLEAR_ON_EXIT;
+	/* NOTE: GCM always uses the encryption function
+	 *       of the underlying cipher!
+	 */
+	safe_apply(THIS->object, "set_encrypt_key", args);
+	pop_stack();
+
+	if (THIS->crypt_state && THIS->crypt_state->crypt) {
+	  func = THIS->crypt_state->crypt;
+	  ctx = THIS->crypt_state->ctx;
+	}
+	gcm_set_key(&THIS->gcm_key, ctx, func);
+	THIS->mode = 1;
+
+	push_object(this_object());
+      }
+
+      /*! @decl this_program set_iv(string(0..255) iv)
+       *!
+       *! Set the initialization vector to @[iv]. The @[iv] memory will be
+       *! cleared before released.
+       *!
+       *! Also resets all state needed to start a new message.
+       *!
+       *! @note
+       *!   For @[iv]s of length other than @expr{12@}, an encryption or
+       *!   decryption key must have been set first.
+       *!
+       *! @seealso
+       *!   @[set_encrypt_key()], @[set_decrypt_key()].
+       */
+      PIKEFUN object set_iv(string(0..255) iv)
+	optflags OPT_SIDE_EFFECT;
+      {
+	iv->flags |= STRING_CLEAR_ON_EXIT;
+	NO_WIDE_STRING(iv);
+	if ((THIS->mode < 0) && (iv->len != GCM_IV_SIZE))
+	  Pike_error("The key must be set to use an iv of length other than %d.\n",
+		     GCM_IV_SIZE);
+	gcm_set_iv(&THIS->gcm_ctx, &THIS->gcm_key, iv->len, STR0(iv));
+	THIS->dmode = 0;
+	RETURN this_object();
+      }
+
+      /*! @decl void update(string(0..255) public_data)
+       *!
+       *! Add @[public_data] to be authenticated.
+       *!
+       *! The length of @[public_data] MUST be a multiple of the
+       *! block size (ie @expr{16@}) for all calls except the last.
+       *!
+       *! All calls of @[update()] need to be performed before
+       *! any calls of @[crypt()].
+       */
+      PIKEFUN void update(string(0..255) data)
+      {
+	NO_WIDE_STRING(data);
+
+	if (!THIS->object || !THIS->object->prog) {
+	  Pike_error("Lookup in destructed object.\n");
+	}
+
+	if (THIS->mode < 0)
+	  Pike_error("Key schedule not initialized.\n");
+
+	if (THIS->dmode & NO_ADATA)
+	  Pike_error("Public data not allowed now.\n");
+
+	gcm_update(&THIS->gcm_ctx, &THIS->gcm_key, data->len, STR0(data));
+
+	if (data->len & (GCM_BLOCK_SIZE - 1))
+	  THIS->dmode |= NO_ADATA;
+
+	pop_n_elems(args);
+      }
+
+      /*! @decl string(0..255) crypt(string(0..255) data)
+       *!
+       *! Encrypt/decrypt @[data] and return the result. @[data] must
+       *! be an integral number of blocks.
+       *!
+       *! The length of @[data] MUST be a multiple of the block size
+       *! (ie @expr{16@}) for all calls except the last.
+       *!
+       *! Neither the input or output data is not automatically memory
+       *! scrubbed, unless @[String.secure] has been called on the data.
+       *!
+       *! @seealso
+       *!   @[update()], @[digest()]
+       */
+      PIKEFUN string(0..255) crypt(string(0..255) data)
+      {
+	struct pike_string *result;
+	ONERROR uwp;
+	crypt_func func = pike_crypt_func;
+	void *ctx = THIS->object;
+
+	NO_WIDE_STRING(data);
+
+	if (!THIS->object || !THIS->object->prog) {
+	  Pike_error("Lookup in destructed object.\n");
+	}
+
+	if (THIS->mode < 0)
+	  Pike_error("Key schedule not initialized.\n");
+
+	if (THIS->dmode & NO_CDATA)
+	  Pike_error("More data not allowed before the iv is reset.\n");
+
+	result = begin_shared_string(data->len);
+	SET_ONERROR (uwp, do_free_string, result);
+
+	if (THIS->crypt_state && THIS->crypt_state->crypt) {
+	  func = THIS->crypt_state->crypt;
+	  ctx = THIS->crypt_state->ctx;
+	}
+
+	if (!THIS->mode) {
+	  gcm_encrypt(&THIS->gcm_ctx, &THIS->gcm_key, ctx, func,
+		      data->len, STR0(result), STR0(data));
+	} else {
+	  gcm_decrypt(&THIS->gcm_ctx, &THIS->gcm_key, ctx, func,
+		      data->len, STR0(result), STR0(data));
+	}
+
+	THIS->dmode |= NO_ADATA;
+
+	if (data->len & (GCM_BLOCK_SIZE - 1))
+	  THIS->dmode |= NO_CDATA;
+
+	pop_n_elems(args);
+	push_string(end_shared_string(result));
+	UNSET_ONERROR(uwp);
+      }
+
+      /*! @decl string(0..255) digest()
+       *!
+       *! Generate a message digest for the data accumulated so far.
+       *!
+       *! @note
+       *!   @[set_iv()] needs to be called to start the next message.
+       *!
+       *! @seealso
+       *!   @[update()], @[digest()]
+       */
+      PIKEFUN string(0..255) digest()
+      {
+	struct pike_string *result;
+	ONERROR uwp;
+	crypt_func func = pike_crypt_func;
+	void *ctx = THIS->object;
+
+	if (!THIS->object || !THIS->object->prog) {
+	  Pike_error("Lookup in destructed object.\n");
+	}
+
+	if (THIS->mode < 0)
+	  Pike_error("Key schedule not initialized.\n");
+
+	result = begin_shared_string(GCM_BLOCK_SIZE);
+	SET_ONERROR (uwp, do_free_string, result);
+
+	if (THIS->crypt_state && THIS->crypt_state->crypt) {
+	  func = THIS->crypt_state->crypt;
+	  ctx = THIS->crypt_state->ctx;
+	}
+
+	gcm_digest(&THIS->gcm_ctx, &THIS->gcm_key, ctx, func,
+		   GCM_BLOCK_SIZE, STR0(result));
+
+	THIS->dmode |= NO_ADATA | NO_CDATA;
+
+	pop_n_elems(args);
+	push_string(end_shared_string(result));
+	UNSET_ONERROR(uwp);
+      }
+    }
+    /*! @endclass
+     */
+  }
+
+  /*! @endmodule
+   */
+
+#endif /* HAVE_NETTLE_GCM_H */
+
+  INIT
+  {
+#ifdef HAVE_NETTLE_GCM_H
+    apply_current(Nettle_Cipher16_cq__GCM_program_fun_num, 0);
+    if (TYPEOF(Pike_sp[-1]) == T_OBJECT) {
+      add_ref(THIS_NETTLE_CIPHER16->GCM = Pike_sp[-1].u.object);
+    }
+    pop_stack();
+#endif
+  }
+}
+/*! @endclass Cipher16
+ */
+
 static void
 pike_aes_set_encrypt_key(void *ctx,
 			 ptrdiff_t length, const char *key,
@@ -434,7 +961,7 @@ pike_aes_set_decrypt_key(void *ctx,
 
 #cmod_define PIKE_NAME AES
 #cmod_define NETTLE_NAME aes
-#cmod_include "cipher.H"
+#cmod_include "cipher16.H"
 #cmod_undef PIKE_NAME
 #cmod_undef NETTLE_NAME
 
@@ -772,7 +1299,7 @@ pike_camellia_set_decrypt_key(void *ctx,
 
 #cmod_define PIKE_NAME CAMELLIA
 #cmod_define NETTLE_NAME camellia
-#cmod_include "cipher.H"
+#cmod_include "cipher16.H"
 #cmod_undef PIKE_NAME
 #cmod_undef NETTLE_NAME
 
@@ -1549,7 +2076,7 @@ pike_serpent_set_key(void *ctx,
 
 #cmod_define PIKE_NAME SERPENT
 #cmod_define NETTLE_NAME serpent
-#cmod_include "cipher.H"
+#cmod_include "cipher16.H"
 #cmod_undef PIKE_NAME
 #cmod_undef NETTLE_NAME
 
@@ -1573,7 +2100,7 @@ pike_twofish_set_key(void *ctx,
 
 #cmod_define PIKE_NAME Twofish
 #cmod_define NETTLE_NAME twofish
-#cmod_include "cipher.H"
+#cmod_include "cipher16.H"
 #cmod_undef PIKE_NAME
 #cmod_undef NETTLE_NAME
 
@@ -1689,25 +2216,6 @@ static struct object *make_cipher_object(INT32 args) {
 }
 
 
-/* Generic callback function for Nettle in case the crypt()
- * function in the object isn't a Nettle function.
- */
-static void pike_crypt_func(void *object, unsigned length, uint8_t *dst,
-			    const uint8_t *src)
-{
-  int args;
-  struct pike_string *str;
-  push_string(make_shared_binary_string((const char *)src, length));
-  args = safe_apply(object, "crypt", 1);
-  get_all_args("crypt", args, "%n", &str);
-  if (str->len != (ptrdiff_t)length) {
-    Pike_error("Bad string length %ld returned from crypt()\n",
-	       DO_NOT_WARN((long)str->len));
-  }
-  MEMCPY(dst, str->str, length);
-  pop_n_elems(args);
-}
-
 /*! @class CBC
  *! Implementation of the cipher block chaining mode (CBC). Works as
  *! a wrapper for the cipher algorithm put in create.
@@ -2264,476 +2772,6 @@ PIKECLASS CTR
 
 #endif /* HAVE_NETTLE_CTR_H */
 
-#ifdef HAVE_NETTLE_GCM_H
-#include <nettle/gcm.h>
-
-/*! @class GCM
- *! Implementation of the Galois Counter Mode (GCM). Works as
- *! a wrapper for the cipher algorithm put in create.
- *!
- *! This is a so-called authenticated encryption with associated data
- *! (AEAD) algorithm, and in addition to encryption also provides
- *! message digests.
- *!
- *! The operation of GCM is specified in
- *! NIST Special Publication 800-38D.
- *!
- *! @note
- *!   Wrapped ciphers MUST have a block size of @expr{16@}.
- *!
- *! @note
- *!   Use @[Crypto.GCM] instead.
- *!
- *! @note
- *!   Note that this class is not available in all versions of Nettle.
- *!
- *! @seealso
- *!   @[Crypto.GCM], @[CBC]
- */
-PIKECLASS GCM
-{
-  /*! @decl inherit __builtin.Nettle.AEAD
-   */
-  INHERIT "__builtin.Nettle.AEAD";
-
-  /*! @decl string(0..255) name()
-   *! Returns the string @expr{"GCM"@}.
-   */
-  PIKEFUN string(0..255) name()
-    optflags OPT_TRY_OPTIMIZE;
-  {
-    push_constant_text("GCM");
-  }
-
-  /*! @decl int(16..16) block_size()
-   *! Returns the block size of the encapsulated cipher,
-   *! which is always @expr{16@} for GCM.
-   */
-  PIKEFUN int(16..16) block_size()
-    optflags OPT_TRY_OPTIMIZE;
-  {
-    RETURN GCM_BLOCK_SIZE;
-  }
-
-  /*! @decl int(16..16) digest_size()
-   *! Returns the size of the generated digest,
-   *! which is always @expr{16@} for GCM.
-   */
-  PIKEFUN int(16..16) digest_size()
-    optflags OPT_TRY_OPTIMIZE;
-  {
-    RETURN GCM_BLOCK_SIZE;
-  }
-
-  /*! @decl int(12..12) iv_size()
-   *! Returns the recommended size for the initialization vector
-   *! (ie @expr{12@}).
-   *!
-   *! Other sizes are allowed, but will be compressed or expanded
-   *! to this size using the encapsulated cipher.
-   */
-  PIKEFUN int(12..12) iv_size()
-    optflags OPT_TRY_OPTIMIZE;
-  {
-    RETURN GCM_IV_SIZE;
-  }
-
-  /*! @class State
-   *!
-   *! The state for a GCM instance.
-   */
-  PIKECLASS State
-    program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT;
-  {
-    DOCSTART() @decl inherit AEAD::State
-    DOCEND()
-
-    EXTRA
-    {
-      /* Perform an inherit of the State class (if any) that our parent
-       * may contain via its inherit of __builtin.Nettle.AEAD.
-       */
-      struct program *parent_prog = Pike_compiler->previous->new_program;
-      struct object *parent_obj = Pike_compiler->previous->fake_object;
-      int parent_State_fun_num =
-	really_low_find_shared_string_identifier(MK_STRING("State"),
-						 parent_prog,
-						 SEE_PROTECTED|SEE_PRIVATE);
-      if (parent_State_fun_num >= 0) {
-	struct program *parent_State_prog =
-	  low_program_from_function(parent_obj, parent_State_fun_num);
-	if (parent_State_prog) {
-	  low_inherit(parent_State_prog, 0,
-		      parent_State_fun_num +
-		      parent_prog->inherits[1].identifier_level,
-		      1 + 42, 0, NULL);
-	}
-      }
-    }
-
-    PIKEVAR object object
-      flags ID_PRIVATE|ID_PROTECTED|ID_HIDDEN;
-    CVAR struct Nettle_Cipher_State_struct *crypt_state;
-    CVAR INT32 mode;
-    CVAR INT32 dmode;
-    CVAR struct gcm_key gcm_key;
-    CVAR struct gcm_ctx gcm_ctx;
-
-    /* dmode flags */
-#define NO_ADATA	1	/* Disallow associated data. */
-#define NO_CDATA	2	/* Disallow crypted data. */
-
-    INIT
-    {
-      THIS->mode = -1;
-    }
-
-    EXIT
-      gc_trivial;
-    {
-      if (THIS->object) {
-	free_object(THIS->object);
-	THIS->object = NULL;
-      }
-    }
-
-    /*! @decl void create(program|object|function cipher, mixed ... args)
-     *!
-     *! Initialize the GCM wrapper with a cipher algorithm. If it is a
-     *! program, an object will be instantiated with @[args] as
-     *! arguments. If it is an object that doesn't conform to the cipher
-     *! API, but has an @[LFUN::`()], that LFUN will be called. If it is
-     *! a function, that function will be called with @[args] as
-     *! arguments.
-     *!
-     *! @note
-     *!   For correct key setup, @[set_encrypt_key()] or @[set_decrypt_key()]
-     *!   MUST be used.
-     */
-    PIKEFUN void create(program|object|function cipher, mixed ... more)
-      flags ID_PROTECTED;
-    {
-      struct object *o = make_cipher_object(args);
-      struct inherit *inh;
-      int f;
-
-      if (THIS->object) free_object(THIS->object);
-      THIS->object = o;
-
-      f = find_identifier("crypt", o->prog);
-      inh = INHERIT_FROM_INT(o->prog, f);
-      if (inh->prog == Nettle_Cipher_State_program) {
-	/* crypt() is from Nettle.Cipher.State.
-	 * Check if the context and crypt function are valid.
-	 */
-	THIS->crypt_state = (struct Nettle_Cipher_State_struct *)
-	  get_inherit_storage(o, inh - o->prog->inherits);
-      }
-
-      safe_apply(THIS->object, "block_size", 0);
-
-      if (TYPEOF(Pike_sp[-1]) != T_INT)
-	Pike_error("block_size() didn't return an int.\n");
-
-      if (Pike_sp[-1].u.integer != GCM_BLOCK_SIZE)
-	Pike_error("cipher has an invalid block size for GCM.\n");
-
-      pop_stack();
-
-      THIS->mode = -1;
-    }
-
-    /*! @decl string(0..255) name()
-     *! Returns the string @expr{"GCM(x)"@} where x is the
-     *! encapsulated algorithm.
-     */
-    PIKEFUN string(0..255) name()
-      optflags OPT_TRY_OPTIMIZE;
-    {
-      push_constant_text("GCM(");
-      safe_apply(THIS->object, "name", 0);
-      push_constant_text(")");
-      f_add(3);
-    }
-
-    /*! @decl int(16..16) block_size()
-     *! Returns the block size of the encapsulated cipher,
-     *! which is always @expr{16@} for GCM.
-     */
-    PIKEFUN int(16..16) block_size()
-      optflags OPT_TRY_OPTIMIZE;
-    {
-      RETURN GCM_BLOCK_SIZE;
-    }
-
-    /*! @decl int(16..16) digest_size()
-     *! Returns the size of the generated digest,
-     *! which is always @expr{16@} for GCM.
-     */
-    PIKEFUN int(16..16) digest_size()
-      optflags OPT_TRY_OPTIMIZE;
-    {
-      RETURN GCM_BLOCK_SIZE;
-    }
-
-    /*! @decl int(12..12) iv_size()
-     *! Returns the recommended size for the initialization vector
-     *! (ie @expr{12@}).
-     *!
-     *! Other sizes are allowed, but will be compressed or expanded
-     *! to this size using the encapsulated cipher.
-     */
-    PIKEFUN int(12..12) iv_size()
-      optflags OPT_TRY_OPTIMIZE;
-    {
-      RETURN GCM_IV_SIZE;
-    }
-
-    /*! @decl int(0..) key_size()
-     *! Returns the key size of the encapsulated cipher.
-     */
-    PIKEFUN int(0..) key_size()
-      optflags OPT_EXTERNAL_DEPEND;
-    {
-      safe_apply(THIS->object, "key_size", args);
-    }
-
-    /*! @decl this_program set_encrypt_key(string(0..255) key, int|void flags)
-     *!
-     *! Prepare the cipher and the wrapper for encrypting with the given
-     *! @[key]. The @[key] memory will be cleared before released.
-     *!
-     *! @note
-     *!   Note that this operation does not by itself reset the
-     *!   context sufficiently to start a new message; @[set_iv()]
-     *!   needs to be called too.
-     *!
-     *! @seealso
-     *!   @[set_decrypt_key()], @[set_iv()]
-     */
-    PIKEFUN object set_encrypt_key(string(0..255) key, int|void flags)
-      optflags OPT_SIDE_EFFECT;
-    {
-      crypt_func func = pike_crypt_func;
-      void *ctx = THIS->object;
-      key->flags |= STRING_CLEAR_ON_EXIT;
-      safe_apply(THIS->object, "set_encrypt_key", args);
-      pop_stack();
-
-      if (THIS->crypt_state && THIS->crypt_state->crypt) {
-	func = THIS->crypt_state->crypt;
-	ctx = THIS->crypt_state->ctx;
-      }
-      gcm_set_key(&THIS->gcm_key, ctx, func);
-      THIS->mode = 0;
-
-      push_object(this_object());
-    }
-
-    /*! @decl this_program set_decrypt_key(string(0..255) key, int|void flags)
-     *!
-     *! Prepare the cipher and the wrapper for decrypting with the given
-     *! @[key]. The @[key] memory will be cleared before released.
-     *!
-     *! @note
-     *!   Note that this operation does not by itself reset the
-     *!   context sufficiently to start a new message; @[set_iv()]
-     *!   needs to be called too.
-     *!
-     *! @seealso
-     *!   @[set_encrypt_key()], @[set_iv()]
-     */
-    PIKEFUN object set_decrypt_key(string(0..255) key, int|void flags)
-      optflags OPT_SIDE_EFFECT;
-    {
-      crypt_func func = pike_crypt_func;
-      void *ctx = THIS->object;
-      key->flags |= STRING_CLEAR_ON_EXIT;
-      /* NOTE: GCM always uses the encryption function
-       *       of the underlying cipher!
-       */
-      safe_apply(THIS->object, "set_encrypt_key", args);
-      pop_stack();
-
-      if (THIS->crypt_state && THIS->crypt_state->crypt) {
-	func = THIS->crypt_state->crypt;
-	ctx = THIS->crypt_state->ctx;
-      }
-      gcm_set_key(&THIS->gcm_key, ctx, func);
-      THIS->mode = 1;
-
-      push_object(this_object());
-    }
-
-    /*! @decl this_program set_iv(string(0..255) iv)
-     *!
-     *! Set the initialization vector to @[iv]. The @[iv] memory will be
-     *! cleared before released.
-     *!
-     *! Also resets all state needed to start a new message.
-     *!
-     *! @note
-     *!   For @[iv]s of length other than @expr{12@}, an encryption or
-     *!   decryption key must have been set first.
-     *!
-     *! @seealso
-     *!   @[set_encrypt_key()], @[set_decrypt_key()].
-     */
-    PIKEFUN object set_iv(string(0..255) iv)
-      optflags OPT_SIDE_EFFECT;
-    {
-      iv->flags |= STRING_CLEAR_ON_EXIT;
-      NO_WIDE_STRING(iv);
-      if ((THIS->mode < 0) && (iv->len != GCM_IV_SIZE))
-	Pike_error("The key must be set to use an iv of length other than %d.\n",
-		   GCM_IV_SIZE);
-      gcm_set_iv(&THIS->gcm_ctx, &THIS->gcm_key, iv->len, STR0(iv));
-      THIS->dmode = 0;
-      RETURN this_object();
-    }
-
-    /*! @decl void update(string(0..255) public_data)
-     *!
-     *! Add @[public_data] to be authenticated.
-     *!
-     *! The length of @[public_data] MUST be a multiple of the
-     *! block size (ie @expr{16@}) for all calls except the last.
-     *!
-     *! All calls of @[update()] need to be performed before
-     *! any calls of @[crypt()].
-     */
-    PIKEFUN void update(string(0..255) data)
-    {
-      NO_WIDE_STRING(data);
-
-      if (!THIS->object || !THIS->object->prog) {
-	Pike_error("Lookup in destructed object.\n");
-      }
-
-      if (THIS->mode < 0)
-	Pike_error("Key schedule not initialized.\n");
-
-      if (THIS->dmode & NO_ADATA)
-	Pike_error("Public data not allowed now.\n");
-
-      gcm_update(&THIS->gcm_ctx, &THIS->gcm_key, data->len, STR0(data));
-
-      if (data->len & (GCM_BLOCK_SIZE - 1))
-	THIS->dmode |= NO_ADATA;
-
-      pop_n_elems(args);
-    }
-
-    /*! @decl string(0..255) crypt(string(0..255) data)
-     *!
-     *! Encrypt/decrypt @[data] and return the result. @[data] must
-     *! be an integral number of blocks.
-     *!
-     *! The length of @[data] MUST be a multiple of the block size
-     *! (ie @expr{16@}) for all calls except the last.
-     *!
-     *! Neither the input or output data is not automatically memory
-     *! scrubbed, unless @[String.secure] has been called on the data.
-     *!
-     *! @seealso
-     *!   @[update()], @[digest()]
-     */
-    PIKEFUN string(0..255) crypt(string(0..255) data)
-    {
-      struct pike_string *result;
-      ONERROR uwp;
-      crypt_func func = pike_crypt_func;
-      void *ctx = THIS->object;
-
-      NO_WIDE_STRING(data);
-
-      if (!THIS->object || !THIS->object->prog) {
-	Pike_error("Lookup in destructed object.\n");
-      }
-
-      if (THIS->mode < 0)
-	Pike_error("Key schedule not initialized.\n");
-
-      if (THIS->dmode & NO_CDATA)
-	Pike_error("More data not allowed before the iv is reset.\n");
-
-      result = begin_shared_string(data->len);
-      SET_ONERROR (uwp, do_free_string, result);
-
-      if (THIS->crypt_state && THIS->crypt_state->crypt) {
-	func = THIS->crypt_state->crypt;
-	ctx = THIS->crypt_state->ctx;
-      }
-
-      if (!THIS->mode) {
-	gcm_encrypt(&THIS->gcm_ctx, &THIS->gcm_key, ctx, func,
-		    data->len, STR0(result), STR0(data));
-      } else {
-	gcm_decrypt(&THIS->gcm_ctx, &THIS->gcm_key, ctx, func,
-		    data->len, STR0(result), STR0(data));
-      }
-
-      THIS->dmode |= NO_ADATA;
-
-      if (data->len & (GCM_BLOCK_SIZE - 1))
-	THIS->dmode |= NO_CDATA;
-
-      pop_n_elems(args);
-      push_string(end_shared_string(result));
-      UNSET_ONERROR(uwp);
-    }
-
-    /*! @decl string(0..255) digest()
-     *!
-     *! Generate a message digest for the data accumulated so far.
-     *!
-     *! @note
-     *!   @[set_iv()] needs to be called to start the next message.
-     *!
-     *! @seealso
-     *!   @[update()], @[digest()]
-     */
-    PIKEFUN string(0..255) digest()
-    {
-      struct pike_string *result;
-      ONERROR uwp;
-      crypt_func func = pike_crypt_func;
-      void *ctx = THIS->object;
-
-      if (!THIS->object || !THIS->object->prog) {
-	Pike_error("Lookup in destructed object.\n");
-      }
-
-      if (THIS->mode < 0)
-	Pike_error("Key schedule not initialized.\n");
-
-      result = begin_shared_string(GCM_BLOCK_SIZE);
-      SET_ONERROR (uwp, do_free_string, result);
-
-      if (THIS->crypt_state && THIS->crypt_state->crypt) {
-	func = THIS->crypt_state->crypt;
-	ctx = THIS->crypt_state->ctx;
-      }
-
-      gcm_digest(&THIS->gcm_ctx, &THIS->gcm_key, ctx, func,
-		 GCM_BLOCK_SIZE, STR0(result));
-
-      THIS->dmode |= NO_ADATA | NO_CDATA;
-
-      pop_n_elems(args);
-      push_string(end_shared_string(result));
-      UNSET_ONERROR(uwp);
-    }
-  }
-  /*! @endclass
-   */
-}
-
-/*! @endclass
- */
-
-#endif /* HAVE_NETTLE_GCM_H */
-
 #define PAD_SSL        0
 #define PAD_ISO_10126  1
 #define PAD_ANSI_X923  2
diff --git a/src/post_modules/Nettle/cipher16.H b/src/post_modules/Nettle/cipher16.H
new file mode 100644
index 0000000000000000000000000000000000000000..229b99e92194c1ebe7c7d3560f67b2dbd4b226b1
--- /dev/null
+++ b/src/post_modules/Nettle/cipher16.H
@@ -0,0 +1,82 @@
+/* -*- C -*-
+ *
+ * Cmod header-file acting as a template for the cipher classes
+ * that have a 16-byte block size.
+ */
+
+DOCSTART() @class PIKE_NAME
+ *!
+ *! Implementation of the PIKE_NAME cipher.
+ *!
+DOCEND()
+PIKECLASS PIKE_NAME
+{
+  DOCSTART() @decl inherit Cipher16
+  DOCEND()
+  INHERIT Nettle_Cipher16;
+
+  static const struct pike_cipher cmod_CONCAT_EVAL(pike_, NETTLE_NAME) =
+    _PIKE_CIPHER(NETTLE_NAME, PIKE_NAME);
+
+  INIT
+    {
+      struct Nettle_Cipher_struct *cipher;
+      ASSIGN_CURRENT_STORAGE(cipher, struct Nettle_Cipher_struct, 2,
+			     Nettle_Cipher_program);
+      cipher->meta = &cmod_CONCAT_EVAL(pike_, NETTLE_NAME);
+    }
+
+  DOCSTART() @class State
+    *!
+    *! State for PIKE_NAME encyption.
+    *!
+  DOCEND()
+  PIKECLASS State
+    program_flags PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT;
+  {
+    DOCSTART() @decl inherit Cipher::State
+    DOCEND()
+
+    EXTRA
+    {
+      /* Perform an inherit of the Cipher.State class that our parent
+       * contains via its inherit of Cipher16.
+       */
+      struct program *parent_prog = Pike_compiler->previous->new_program;
+      struct object *parent_obj = Pike_compiler->previous->fake_object;
+      int parent_State_fun_num =
+	really_low_find_shared_string_identifier(MK_STRING("State"),
+						 parent_prog,
+						 SEE_PROTECTED|SEE_PRIVATE);
+      if (parent_State_fun_num >= 0) {
+	struct program *parent_State_prog =
+	  low_program_from_function(parent_obj, parent_State_fun_num);
+	if (parent_State_prog) {
+	  low_inherit(parent_State_prog, 0,
+		      parent_State_fun_num +
+		      parent_prog->inherits[1].identifier_level,
+		      1 + 42, 0, NULL);
+	}
+      }
+    }
+
+    CVAR struct cmod_CONCAT_EVAL(NETTLE_NAME, _ctx) NETTLE_NAME;
+
+    INIT
+    {
+      struct Nettle_Cipher_State_struct *state;
+      ASSIGN_CURRENT_STORAGE(state, struct Nettle_Cipher_State_struct, 1,
+			     Nettle_Cipher_State_program);
+
+      fprintf(stderr, "%s: Setting state->ctx (%p) to %p\n",
+	      TOSTR(PIKE_NAME), state, &THIS->NETTLE_NAME);
+      state->ctx = &THIS->NETTLE_NAME;
+    }
+  }
+  DOCSTART() @endclass State
+  DOCEND()
+
+}
+
+DOCSTART() @endclass PIKE_NAME
+DOCEND()