Convert bulk CTR and CBC selftest functions in Camellia to generic selftest helper...
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Wed, 22 May 2013 11:10:59 +0000 (14:10 +0300)
committerWerner Koch <wk@gnupg.org>
Wed, 22 May 2013 15:42:20 +0000 (17:42 +0200)
* cipher/Makefile.am (libcipher_la_SOURCES): Add cipher-selftest files.
* cipher/camellia-glue.c (selftest_ctr_128, selftest_cbc_128): Change
to use the new selftest helper functions.
* cipher/cipher-selftest.c: New.
* cipher/cipher-selftest.h: New.
--

Convert selftest functions into generic helper functions for code sharing.

[v2]: use syslog for more detailed selftest error messages

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
cipher/Makefile.am
cipher/camellia-glue.c
cipher/cipher-selftest.c [new file with mode: 0644]
cipher/cipher-selftest.h [new file with mode: 0644]

index 00e4429..0808bd2 100644 (file)
@@ -40,6 +40,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES)
 libcipher_la_SOURCES = \
 cipher.c cipher-internal.h \
 cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \
+cipher-selftest.c cipher-selftest.h \
 pubkey.c pubkey-internal.h \
 md.c \
 kdf.c kdf-internal.h \
index e9e2bf2..4c724a9 100644 (file)
@@ -63,6 +63,7 @@
 #include "cipher.h"
 #include "camellia.h"
 #include "bufhelp.h"
+#include "cipher-selftest.h"
 
 /* Helper macro to force alignment to 16 bytes.  */
 #ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
@@ -313,93 +314,12 @@ static const char*
 selftest_ctr_128 (void)
 {
   const int nblocks = 16+1;
-  CAMELLIA_context ctx ATTR_ALIGNED_16;
-  unsigned char plaintext[nblocks*16] ATTR_ALIGNED_16;
-  unsigned char ciphertext[nblocks*16] ATTR_ALIGNED_16;
-  unsigned char plaintext2[nblocks*16] ATTR_ALIGNED_16;
-  unsigned char iv[16] ATTR_ALIGNED_16;
-  unsigned char iv2[16] ATTR_ALIGNED_16;
-  int i, j, diff;
-
-  static const unsigned char key[16] ATTR_ALIGNED_16 = {
-      0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
-      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
-    };
-  static char error_str[128];
-
-  camellia_setkey (&ctx, key, sizeof (key));
-
-  /* Test single block code path */
-  memset(iv, 0xff, sizeof(iv));
-  for (i = 0; i < 16; i++)
-    plaintext[i] = i;
-
-  /* CTR manually.  */
-  camellia_encrypt (&ctx, ciphertext, iv);
-  for (i = 0; i < 16; i++)
-    ciphertext[i] ^= plaintext[i];
-  for (i = 16; i > 0; i--)
-    {
-      iv[i-1]++;
-      if (iv[i-1])
-        break;
-    }
-
-  memset(iv2, 0xff, sizeof(iv2));
-  _gcry_camellia_ctr_enc (&ctx, iv2, plaintext2, ciphertext, 1);
-
-  if (memcmp(plaintext2, plaintext, 16))
-    return "CAMELLIA-128-CTR test failed (plaintext mismatch)";
-
-  if (memcmp(iv2, iv, 16))
-    return "CAMELLIA-128-CTR test failed (IV mismatch)";
-
-  /* Test parallelized code paths */
-  for (diff = 0; diff < nblocks; diff++) {
-    memset(iv, 0xff, sizeof(iv));
-    iv[15] -= diff;
-
-    for (i = 0; i < sizeof(plaintext); i++)
-      plaintext[i] = i;
-
-    /* Create CTR ciphertext manually.  */
-    for (i = 0; i < sizeof(plaintext); i+=16)
-      {
-        camellia_encrypt (&ctx, &ciphertext[i], iv);
-        for (j = 0; j < 16; j++)
-          ciphertext[i+j] ^= plaintext[i+j];
-        for (j = 16; j > 0; j--)
-          {
-            iv[j-1]++;
-            if (iv[j-1])
-              break;
-          }
-      }
-
-    /* Decrypt using bulk CTR and compare result.  */
-    memset(iv2, 0xff, sizeof(iv2));
-    iv2[15] -= diff;
-
-    _gcry_camellia_ctr_enc (&ctx, iv2, plaintext2, ciphertext,
-                            sizeof(ciphertext) / CAMELLIA_BLOCK_SIZE);
-
-    if (memcmp(plaintext2, plaintext, sizeof(plaintext)))
-      {
-        snprintf(error_str, sizeof(error_str),
-                 "CAMELLIA-128-CTR test failed (plaintext mismatch, diff: %d)",
-                 diff);
-        return error_str;
-      }
-    if (memcmp(iv2, iv, sizeof(iv)))
-      {
-        snprintf(error_str, sizeof(error_str),
-                 "CAMELLIA-128-CTR test failed (IV mismatch, diff: %d)",
-                 diff);
-        return error_str;
-      }
-  }
+  const int blocksize = CAMELLIA_BLOCK_SIZE;
+  const int context_size = sizeof(CAMELLIA_context);
 
-  return NULL;
+  return _gcry_selftest_helper_ctr_128("CAMELLIA", &camellia_setkey,
+           &camellia_encrypt, &_gcry_camellia_ctr_enc, nblocks, blocksize,
+          context_size);
 }
 
 /* Run the self-tests for CAMELLIA-CBC-128, tests bulk CBC decryption.
@@ -408,78 +328,12 @@ static const char*
 selftest_cbc_128 (void)
 {
   const int nblocks = 16+2;
-  CAMELLIA_context ctx ATTR_ALIGNED_16;
-  unsigned char plaintext[nblocks*16] ATTR_ALIGNED_16;
-  unsigned char ciphertext[nblocks*16] ATTR_ALIGNED_16;
-  unsigned char plaintext2[nblocks*16] ATTR_ALIGNED_16;
-  unsigned char iv[16] ATTR_ALIGNED_16;
-  unsigned char iv2[16] ATTR_ALIGNED_16;
-  int i, j;
-
-  static const unsigned char key[16] ATTR_ALIGNED_16 = {
-      0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
-      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22
-    };
-  static char error_str[128];
-
-  camellia_setkey (&ctx, key, sizeof (key));
-
-  /* Test single block code path */
-  memset(iv, 0x4e, sizeof(iv));
-  memset(iv2, 0x4e, sizeof(iv2));
-  for (i = 0; i < 16; i++)
-    plaintext[i] = i;
-
-  /* CBC manually.  */
-  for (i = 0; i < 16; i++)
-    ciphertext[i] = iv[i] ^ plaintext[i];
-  camellia_encrypt (&ctx, ciphertext, ciphertext);
-  memcpy(iv, ciphertext, sizeof(iv));
-
-  /* CBC decrypt.  */
-  _gcry_camellia_cbc_dec (&ctx, iv2, plaintext2, ciphertext, 1);
-
-  if (memcmp(plaintext2, plaintext, 16))
-    return "CAMELLIA-128-CBC test failed (plaintext mismatch)";
+  const int blocksize = CAMELLIA_BLOCK_SIZE;
+  const int context_size = sizeof(CAMELLIA_context);
 
-  if (memcmp(iv2, iv, 16))
-    return "CAMELLIA-128-CBC test failed (IV mismatch)";
-
-  /* Test parallelized code paths */
-  memset(iv, 0x5f, sizeof(iv));
-  memset(iv2, 0x5f, sizeof(iv2));
-
-  for (i = 0; i < sizeof(plaintext); i++)
-    plaintext[i] = i;
-
-  /* Create CBC ciphertext manually.  */
-  for (i = 0; i < sizeof(plaintext); i+=16)
-    {
-      for (j = 0; j < 16; j++)
-        ciphertext[i+j] = iv[j] ^ plaintext[i+j];
-      camellia_encrypt (&ctx, &ciphertext[i], &ciphertext[i]);
-      memcpy(iv, &ciphertext[i], sizeof(iv));
-    }
-
-  /* Decrypt using bulk CBC and compare result.  */
-  _gcry_camellia_cbc_dec (&ctx, iv2, plaintext2, ciphertext,
-                          sizeof(ciphertext) / CAMELLIA_BLOCK_SIZE);
-
-  if (memcmp(plaintext2, plaintext, sizeof(plaintext)))
-    {
-      snprintf(error_str, sizeof(error_str),
-               "CAMELLIA-128-CBC test failed (plaintext mismatch, "
-              "parallel path)");
-      return error_str;
-    }
-  if (memcmp(iv2, iv, sizeof(iv)))
-    {
-      snprintf(error_str, sizeof(error_str),
-               "CAMELLIA-128-CBC test failed (IV mismatch, parallel path)");
-      return error_str;
-    }
-
-  return NULL;
+  return _gcry_selftest_helper_cbc_128("CAMELLIA", &camellia_setkey,
+           &camellia_encrypt, &_gcry_camellia_cbc_dec, nblocks, blocksize,
+          context_size);
 }
 
 static const char *
diff --git a/cipher/cipher-selftest.c b/cipher/cipher-selftest.c
new file mode 100644 (file)
index 0000000..50c7752
--- /dev/null
@@ -0,0 +1,291 @@
+/* cipher-selftest.c - Helper functions for bulk encryption selftests.
+ *     Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@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>
+#ifdef HAVE_SYSLOG
+# include <syslog.h>
+#endif /*HAVE_SYSLOG*/
+
+#include "types.h"
+#include "g10lib.h"
+#include "cipher.h"
+#include "bufhelp.h"
+#include "cipher-selftest.h"
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h> /* uintptr_t */
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#else
+/* In this case, uintptr_t is provided by config.h. */
+#endif
+
+/* Helper macro to force alignment to 16 bytes.  */
+#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED
+# define ATTR_ALIGNED_16  __attribute__ ((aligned (16)))
+#else
+# define ATTR_ALIGNED_16
+#endif
+
+
+/* Run the self-tests for <block cipher>-CBC-128, tests bulk CBC
+   decryption.  Returns NULL on success. */
+const char *
+_gcry_selftest_helper_cbc_128 (const char *cipher, gcry_cipher_setkey_t setkey,
+                              gcry_cipher_encrypt_t encrypt_one,
+                              gcry_cipher_bulk_cbc_dec_t bulk_cbc_dec,
+                              const int nblocks, const int blocksize,
+                              const int context_size)
+{
+  int i, offs;
+  unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
+  unsigned int ctx_aligned_size, memsize;
+
+  static const unsigned char key[16] ATTR_ALIGNED_16 = {
+      0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22
+    };
+
+  /* Allocate buffers, align elements to 16 bytes.  */
+  ctx_aligned_size = context_size + 15;
+  ctx_aligned_size -= ctx_aligned_size & 0xf;
+
+  memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
+
+  mem = gcry_calloc (1, memsize);
+  if (!mem)
+    return "failed to allocate memory";
+
+  offs = (16 - ((uintptr_t)mem & 15)) & 15;
+  ctx = (void*)(mem + offs);
+  iv = ctx + ctx_aligned_size;
+  iv2 = iv + blocksize;
+  plaintext = iv2 + blocksize;
+  plaintext2 = plaintext + nblocks * blocksize;
+  ciphertext = plaintext2 + nblocks * blocksize;
+
+  /* Initialize ctx */
+  setkey (ctx, key, sizeof(key));
+
+  /* Test single block code path */
+  memset (iv, 0x4e, blocksize);
+  memset (iv2, 0x4e, blocksize);
+  for (i = 0; i < blocksize; i++)
+    plaintext[i] = i;
+
+  /* CBC manually.  */
+  buf_xor (ciphertext, iv, plaintext, blocksize);
+  encrypt_one (ctx, ciphertext, ciphertext);
+  memcpy (iv, ciphertext, blocksize);
+
+  /* CBC decrypt.  */
+  bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, 1);
+  if (memcmp (plaintext2, plaintext, 16))
+    {
+      gcry_free (mem);
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "%s-128-CBC test failed (plaintext mismatch)", cipher);
+#endif
+      return "selftest for 128 bit CBC failed - see syslog for details";
+    }
+
+  if (memcmp (iv2, iv, 16))
+    {
+      gcry_free (mem);
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "%s-128-CBC test failed (IV mismatch)", cipher);
+#endif
+      return "selftest for 128 bit CBC failed - see syslog for details";
+    }
+
+  /* Test parallelized code paths */
+  memset (iv, 0x5f, blocksize);
+  memset (iv2, 0x5f, blocksize);
+
+  for (i = 0; i < nblocks * blocksize; i++)
+    plaintext[i] = i;
+
+  /* Create CBC ciphertext manually.  */
+  for (i = 0; i < nblocks * blocksize; i+=blocksize)
+    {
+      buf_xor (&ciphertext[i], iv, &plaintext[i], blocksize);
+      encrypt_one (ctx, &ciphertext[i], &ciphertext[i]);
+      memcpy (iv, &ciphertext[i], blocksize);
+    }
+
+  /* Decrypt using bulk CBC and compare result.  */
+  bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
+
+  if (memcmp (plaintext2, plaintext, nblocks * blocksize))
+    {
+      gcry_free (mem);
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "%s-128-CBC test failed (plaintext mismatch, parallel path)",
+             cipher);
+#endif
+      return "selftest for 128 bit CBC failed - see syslog for details";
+    }
+  if (memcmp (iv2, iv, blocksize))
+    {
+      gcry_free (mem);
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "%s-128-CBC test failed (IV mismatch, parallel path)",
+             cipher);
+#endif
+      return "selftest for 128 bit CBC failed - see syslog for details";
+    }
+
+  gcry_free (mem);
+  return NULL;
+}
+
+/* Run the self-tests for <block cipher>-CTR-128, tests IV increment of bulk CTR
+   encryption.  Returns NULL on success. */
+const char *
+_gcry_selftest_helper_ctr_128 (const char *cipher, gcry_cipher_setkey_t setkey,
+                              gcry_cipher_encrypt_t encrypt_one,
+                              gcry_cipher_bulk_ctr_enc_t bulk_ctr_enc,
+                              const int nblocks, const int blocksize,
+                              const int context_size)
+{
+  int i, j, offs, diff;
+  unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
+  unsigned int ctx_aligned_size, memsize;
+
+  static const unsigned char key[16] ATTR_ALIGNED_16 = {
+      0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
+    };
+
+  /* Allocate buffers, align elements to 16 bytes.  */
+  ctx_aligned_size = context_size + 15;
+  ctx_aligned_size -= ctx_aligned_size & 0xf;
+
+  memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
+
+  mem = gcry_calloc (1, memsize);
+  if (!mem)
+    return "failed to allocate memory";
+
+  offs = (16 - ((uintptr_t)mem & 15)) & 15;
+  ctx = (void*)(mem + offs);
+  iv = ctx + ctx_aligned_size;
+  iv2 = iv + blocksize;
+  plaintext = iv2 + blocksize;
+  plaintext2 = plaintext + nblocks * blocksize;
+  ciphertext = plaintext2 + nblocks * blocksize;
+
+  /* Initialize ctx */
+  setkey (ctx, key, sizeof(key));
+
+  /* Test single block code path */
+  memset (iv, 0xff, blocksize);
+  for (i = 0; i < blocksize; i++)
+    plaintext[i] = i;
+
+  /* CTR manually.  */
+  encrypt_one (ctx, ciphertext, iv);
+  for (i = 0; i < blocksize; i++)
+    ciphertext[i] ^= plaintext[i];
+  for (i = blocksize; i > 0; i--)
+    {
+      iv[i-1]++;
+      if (iv[i-1])
+        break;
+    }
+
+  memset (iv2, 0xff, blocksize);
+  bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, 1);
+
+  if (memcmp (plaintext2, plaintext, blocksize))
+    {
+      gcry_free (mem);
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "%s-128-CTR test failed (plaintext mismatch)", cipher);
+#endif
+      return "selftest for 128 bit CTR failed - see syslog for details";
+    }
+
+  if (memcmp (iv2, iv, blocksize))
+    {
+      gcry_free (mem);
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "%s-128-CTR test failed (IV mismatch)", cipher);
+#endif
+      return "selftest for 128 bit CTR failed - see syslog for details";
+    }
+
+  /* Test parallelized code paths */
+  for (diff = 0; diff < nblocks; diff++) {
+    memset(iv, 0xff, blocksize);
+    iv[blocksize-1] -= diff;
+
+    for (i = 0; i < blocksize * nblocks; i++)
+      plaintext[i] = i;
+
+    /* Create CTR ciphertext manually.  */
+    for (i = 0; i < blocksize * nblocks; i+=blocksize)
+      {
+        encrypt_one (ctx, &ciphertext[i], iv);
+        for (j = 0; j < blocksize; j++)
+          ciphertext[i+j] ^= plaintext[i+j];
+        for (j = blocksize; j > 0; j--)
+          {
+            iv[j-1]++;
+            if (iv[j-1])
+              break;
+          }
+      }
+
+    /* Decrypt using bulk CTR and compare result.  */
+    memset(iv2, 0xff, blocksize);
+    iv2[blocksize-1] -= diff;
+
+    bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, nblocks);
+
+    if (memcmp (plaintext2, plaintext, blocksize * nblocks))
+      {
+        gcry_free (mem);
+#ifdef HAVE_SYSLOG
+        syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+                "%s-128-CTR test failed (plaintext mismatch, diff: %d)", cipher,
+               diff);
+#endif
+        return "selftest for 128 bit CTR failed - see syslog for details";
+      }
+    if (memcmp(iv2, iv, blocksize))
+      {
+        gcry_free (mem);
+#ifdef HAVE_SYSLOG
+        syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+                "%s-128-CTR test failed (IV mismatch, diff: %d)", cipher, diff);
+#endif
+        return "selftest for 128 bit CTR failed - see syslog for details";
+      }
+  }
+
+  gcry_free (mem);
+  return NULL;
+}
diff --git a/cipher/cipher-selftest.h b/cipher/cipher-selftest.h
new file mode 100644 (file)
index 0000000..89d79c2
--- /dev/null
@@ -0,0 +1,54 @@
+/* cipher-selftest.h - Helper functions for bulk encryption selftests.
+ *     Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@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/>.
+ */
+
+#ifndef G10_SELFTEST_HELP_H
+#define G10_SELFTEST_HELP_H
+
+#include <config.h>
+#include "types.h"
+#include "g10lib.h"
+#include "cipher.h"
+
+typedef void (*gcry_cipher_bulk_cbc_dec_t)(void *context, unsigned char *iv,
+                                          void *outbuf_arg,
+                                          const void *inbuf_arg,
+                                          unsigned int nblocks);
+
+typedef void (*gcry_cipher_bulk_ctr_enc_t)(void *context, unsigned char *iv,
+                                          void *outbuf_arg,
+                                          const void *inbuf_arg,
+                                          unsigned int nblocks);
+
+/* Helper function for bulk CBC decryption selftest */
+const char *
+_gcry_selftest_helper_cbc_128 (const char *cipher, gcry_cipher_setkey_t setkey,
+                              gcry_cipher_encrypt_t encrypt_one,
+                              gcry_cipher_bulk_cbc_dec_t bulk_cbc_dec,
+                              const int nblocks, const int blocksize,
+                              const int context_size);
+
+/* Helper function for bulk CTR encryption selftest */
+const char *
+_gcry_selftest_helper_ctr_128 (const char *cipher, gcry_cipher_setkey_t setkey,
+                              gcry_cipher_encrypt_t encrypt_one,
+                              gcry_cipher_bulk_ctr_enc_t bulk_ctr_enc,
+                              const int nblocks, const int blocksize,
+                              const int context_size);
+
+#endif /*G10_SELFTEST_HELP_H*/