diff --git a/ChangeLog b/ChangeLog
index 3d12926c2035d1e10efc8b37efdb2657b92ec8d9..23d976f3fd0d228537f9787a2010f85063feb09b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2015-03-14  Niels Möller  <nisse@diamant.hack.org>
+
+	* ccm.c (memeql_sec): New function, more side-channel silent than
+	memcmp.
+	(ccm_decrypt_message): Use it.
+
 2015-03-12  Niels Möller  <nisse@diamant.hack.org>
 
 	* base64.h (struct base64_encode_ctx): Micro optimization of
diff --git a/ccm.c b/ccm.c
index c5ff790873883eec6eeb2bcbbe82b035821a286c..b98bc9cfc43438b4a8edcf6090f09c723a7bdc4c 100644
--- a/ccm.c
+++ b/ccm.c
@@ -246,6 +246,19 @@ ccm_encrypt_message(const void *cipher, nettle_cipher_func *f,
   ccm_digest(&ctx, cipher, f, tlength, tag);
 }
 
+/* FIXME: Should be made public, under some suitable name. */
+static int
+memeql_sec (const void *a, const void *b, size_t n)
+{
+  volatile const unsigned char *ap = (const unsigned char *) a;
+  volatile const unsigned char *bp = (const unsigned char *) b;
+  volatile unsigned char d;
+  size_t i;
+  for (d = i = 0; i < n; i++)
+    d |= (ap[i] ^ bp[i]);
+  return d == 0;
+}
+
 int
 ccm_decrypt_message(const void *cipher, nettle_cipher_func *f,
 		    size_t nlength, const uint8_t *nonce,
@@ -258,5 +271,5 @@ ccm_decrypt_message(const void *cipher, nettle_cipher_func *f,
   ccm_update(&ctx, cipher, f, alength, adata);
   ccm_decrypt(&ctx, cipher, f, mlength, dst, src);
   ccm_digest(&ctx, cipher, f, tlength, tag);
-  return (memcmp(tag, src + mlength, tlength) == 0);
+  return memeql_sec(tag, src + mlength, tlength);
 }