[PATCH 2/2] cipher: move CBC/CFB/CTR self-tests to tests/basic

Jussi Kivilinna jussi.kivilinna at iki.fi
Mon May 9 19:33:36 CEST 2022


* cipher/Makefile.am: Remove 'cipher-selftest.c' and 'cipher-selftest.h'.
* cipher/cipher-selftest.c: Remove (refactor these tests to
tests/basic.c).
* cipher/cipher-selftest.h: Remove.
* cipher/blowfish.c (selftest_ctr, selftest_cbc, selftest_cfb): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/camellia-glue.c (selftest_ctr_128, selftest_cbc_128)
(selftest_cfb_128): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/cast5.c (selftest_ctr, selftest_cbc, selftest_cfb): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/des.c (bulk_selftest_setkey, selftest_ctr, selftest_cbc)
(selftest_cfb): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/rijndael.c (selftest_basic_128, selftest_basic_192)
(selftest_basic_256): Allocate context from stack instead of heap and
handle alignment manually.
(selftest_ctr_128, selftest_cbc_128, selftest_cfb_128): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/serpent.c (selftest_ctr_128, selftest_cbc_128)
(selftest_cfb_128): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/sm4.c (selftest_ctr_128, selftest_cbc_128)
(selftest_cfb_128): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/twofish.c (selftest_ctr, selftest_cbc, selftest_cfb): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* tests/basic.c (buf_xor, cipher_cbc_bulk_test, buf_xor_2dst)
(cipher_cfb_bulk_test, cipher_ctr_bulk_test): New.
(check_ciphers): Run cipher_cbc_bulk_test(), cipher_cfb_bulk_test() and
cipher_ctr_bulk_test() for block ciphers.
---

CBC/CFB/CTR bulk self-tests are quite computationally heavy and
slow down use cases where application opens cipher context once,
does processing and exits. Better place for these tests is in
`tests/basic`.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 cipher/Makefile.am            |   1 -
 cipher/blowfish.c             |  53 ---
 cipher/camellia-glue.c        |  49 ---
 cipher/cast5.c                |  53 ---
 cipher/cipher-selftest.c      | 512 ----------------------
 cipher/cipher-selftest.h      |  69 ---
 cipher/des.c                  |  72 ----
 cipher/rijndael-aesni.c       |   1 -
 cipher/rijndael-armv8-ce.c    |   1 -
 cipher/rijndael-padlock.c     |   1 -
 cipher/rijndael-ssse3-amd64.c |   1 -
 cipher/rijndael-vaes.c        |   1 -
 cipher/rijndael.c             |  92 +---
 cipher/serpent.c              |  53 ---
 cipher/sm4.c                  |  50 ---
 cipher/twofish.c              |  49 ---
 tests/basic.c                 | 772 ++++++++++++++++++++++++++++++++++
 17 files changed, 780 insertions(+), 1050 deletions(-)
 delete mode 100644 cipher/cipher-selftest.c
 delete mode 100644 cipher/cipher-selftest.h

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index a6171bf5..250b229e 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -55,7 +55,6 @@ libcipher_la_SOURCES = \
 	cipher-eax.c \
 	cipher-siv.c \
 	cipher-gcm-siv.c \
-	cipher-selftest.c cipher-selftest.h \
 	pubkey.c pubkey-internal.h pubkey-util.c \
 	md.c \
 	mac.c mac-internal.h \
diff --git a/cipher/blowfish.c b/cipher/blowfish.c
index 7b001306..1b11d718 100644
--- a/cipher/blowfish.c
+++ b/cipher/blowfish.c
@@ -38,7 +38,6 @@
 #include "cipher.h"
 #include "bufhelp.h"
 #include "cipher-internal.h"
-#include "cipher-selftest.h"
 
 #define BLOWFISH_BLOCKSIZE 8
 #define BLOWFISH_KEY_MIN_BITS 8
@@ -856,48 +855,6 @@ _gcry_blowfish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
 }
 
 
-/* Run the self-tests for BLOWFISH-CTR, tests IV increment of bulk CTR
-   encryption.  Returns NULL on success. */
-static const char *
-selftest_ctr (void)
-{
-  const int nblocks = 4+1;
-  const int blocksize = BLOWFISH_BLOCKSIZE;
-  const int context_size = sizeof(BLOWFISH_context);
-
-  return _gcry_selftest_helper_ctr("BLOWFISH", &bf_setkey,
-           &encrypt_block, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for BLOWFISH-CBC, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char *
-selftest_cbc (void)
-{
-  const int nblocks = 4+2;
-  const int blocksize = BLOWFISH_BLOCKSIZE;
-  const int context_size = sizeof(BLOWFISH_context);
-
-  return _gcry_selftest_helper_cbc("BLOWFISH", &bf_setkey,
-           &encrypt_block, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for BLOWFISH-CFB, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char *
-selftest_cfb (void)
-{
-  const int nblocks = 4+2;
-  const int blocksize = BLOWFISH_BLOCKSIZE;
-  const int context_size = sizeof(BLOWFISH_context);
-
-  return _gcry_selftest_helper_cfb("BLOWFISH", &bf_setkey,
-           &encrypt_block, nblocks, blocksize, context_size);
-}
-
-
 static const char*
 selftest(void)
 {
@@ -911,7 +868,6 @@ selftest(void)
     { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 };
   static const byte cipher3[] =
     { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 };
-  const char *r;
 
   bf_setkey( (void *) &c,
              (const unsigned char*)"abcdefghijklmnopqrstuvwxyz", 26,
@@ -931,15 +887,6 @@ selftest(void)
   if( memcmp( buffer, plain3, 8 ) )
     return "Blowfish selftest failed (4).";
 
-  if ( (r = selftest_cbc ()) )
-    return r;
-
-  if ( (r = selftest_cfb ()) )
-    return r;
-
-  if ( (r = selftest_ctr ()) )
-    return r;
-
   return NULL;
 }
 
diff --git a/cipher/camellia-glue.c b/cipher/camellia-glue.c
index a854b82d..c938be71 100644
--- a/cipher/camellia-glue.c
+++ b/cipher/camellia-glue.c
@@ -64,7 +64,6 @@
 #include "camellia.h"
 #include "bufhelp.h"
 #include "cipher-internal.h"
-#include "cipher-selftest.h"
 #include "bulkhelp.h"
 
 /* Helper macro to force alignment to 16 bytes.  */
@@ -1454,44 +1453,6 @@ _gcry_camellia_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
   return nblocks;
 }
 
-/* Run the self-tests for CAMELLIA-CTR-128, tests IV increment of bulk CTR
-   encryption.  Returns NULL on success. */
-static const char*
-selftest_ctr_128 (void)
-{
-  const int nblocks = 64+32+16+1;
-  const int blocksize = CAMELLIA_BLOCK_SIZE;
-  const int context_size = sizeof(CAMELLIA_context);
-
-  return _gcry_selftest_helper_ctr("CAMELLIA", &camellia_setkey,
-           &camellia_encrypt, nblocks, blocksize, context_size);
-}
-
-/* Run the self-tests for CAMELLIA-CBC-128, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char*
-selftest_cbc_128 (void)
-{
-  const int nblocks = 64+32+16+2;
-  const int blocksize = CAMELLIA_BLOCK_SIZE;
-  const int context_size = sizeof(CAMELLIA_context);
-
-  return _gcry_selftest_helper_cbc("CAMELLIA", &camellia_setkey,
-           &camellia_encrypt, nblocks, blocksize, context_size);
-}
-
-/* Run the self-tests for CAMELLIA-CFB-128, tests bulk CFB decryption.
-   Returns NULL on success. */
-static const char*
-selftest_cfb_128 (void)
-{
-  const int nblocks = 64+32+16+2;
-  const int blocksize = CAMELLIA_BLOCK_SIZE;
-  const int context_size = sizeof(CAMELLIA_context);
-
-  return _gcry_selftest_helper_cfb("CAMELLIA", &camellia_setkey,
-           &camellia_encrypt, nblocks, blocksize, context_size);
-}
 
 static const char *
 selftest(void)
@@ -1499,7 +1460,6 @@ selftest(void)
   CAMELLIA_context ctx;
   byte scratch[16];
   cipher_bulk_ops_t bulk_ops;
-  const char *r;
 
   /* These test vectors are from RFC-3713 */
   static const byte plaintext[]=
@@ -1563,15 +1523,6 @@ selftest(void)
   if(memcmp(scratch,plaintext,sizeof(plaintext))!=0)
     return "CAMELLIA-256 test decryption failed.";
 
-  if ( (r = selftest_ctr_128 ()) )
-    return r;
-
-  if ( (r = selftest_cbc_128 ()) )
-    return r;
-
-  if ( (r = selftest_cfb_128 ()) )
-    return r;
-
   return NULL;
 }
 
diff --git a/cipher/cast5.c b/cipher/cast5.c
index 837ea0fe..20bf7479 100644
--- a/cipher/cast5.c
+++ b/cipher/cast5.c
@@ -45,7 +45,6 @@
 #include "bithelp.h"
 #include "bufhelp.h"
 #include "cipher-internal.h"
-#include "cipher-selftest.h"
 
 /* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
 #undef USE_AMD64_ASM
@@ -991,48 +990,6 @@ _gcry_cast5_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
 }
 
 
-/* Run the self-tests for CAST5-CTR, tests IV increment of bulk CTR
-   encryption.  Returns NULL on success. */
-static const char *
-selftest_ctr (void)
-{
-  const int nblocks = 4+1;
-  const int blocksize = CAST5_BLOCKSIZE;
-  const int context_size = sizeof(CAST5_context);
-
-  return _gcry_selftest_helper_ctr("CAST5", &cast_setkey,
-           &encrypt_block, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for CAST5-CBC, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char *
-selftest_cbc (void)
-{
-  const int nblocks = 4+2;
-  const int blocksize = CAST5_BLOCKSIZE;
-  const int context_size = sizeof(CAST5_context);
-
-  return _gcry_selftest_helper_cbc("CAST5", &cast_setkey,
-           &encrypt_block, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for CAST5-CFB, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char *
-selftest_cfb (void)
-{
-  const int nblocks = 4+2;
-  const int blocksize = CAST5_BLOCKSIZE;
-  const int context_size = sizeof(CAST5_context);
-
-  return _gcry_selftest_helper_cfb("CAST5", &cast_setkey,
-           &encrypt_block, nblocks, blocksize, context_size);
-}
-
-
 static const char*
 selftest(void)
 {
@@ -1046,7 +1003,6 @@ selftest(void)
     static const byte cipher[8] =
                     { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 };
     byte buffer[8];
-    const char *r;
 
     cast_setkey( &c, key, 16, &bulk_ops );
     encrypt_block( &c, buffer, plain );
@@ -1082,15 +1038,6 @@ selftest(void)
     }
 #endif
 
-    if ( (r = selftest_cbc ()) )
-      return r;
-
-    if ( (r = selftest_cfb ()) )
-      return r;
-
-    if ( (r = selftest_ctr ()) )
-      return r;
-
     return NULL;
 }
 
diff --git a/cipher/cipher-selftest.c b/cipher/cipher-selftest.c
deleted file mode 100644
index d7f38a42..00000000
--- a/cipher/cipher-selftest.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/* cipher-selftest.c - Helper functions for bulk encryption selftests.
- * Copyright (C) 2013,2020 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>
-#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"
-#include "cipher-internal.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
-
-
-/* Return an allocated buffers of size CONTEXT_SIZE with an alignment
-   of 16.  The caller must free that buffer using the address returned
-   at R_MEM.  Returns NULL and sets ERRNO on failure.  */
-void *
-_gcry_cipher_selftest_alloc_ctx (const int context_size, unsigned char **r_mem)
-{
-  int offs;
-  unsigned int ctx_aligned_size, memsize;
-
-  ctx_aligned_size = context_size + 15;
-  ctx_aligned_size -= ctx_aligned_size & 0xf;
-
-  memsize = ctx_aligned_size + 16;
-
-  *r_mem = xtrycalloc (1, memsize);
-  if (!*r_mem)
-    return NULL;
-
-  offs = (16 - ((uintptr_t)*r_mem & 15)) & 15;
-  return (void*)(*r_mem + offs);
-}
-
-
-/* Run the self-tests for <block cipher>-CBC-<block size>, tests bulk CBC
-   decryption.  Returns NULL on success. */
-const char *
-_gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey_func,
-			   gcry_cipher_encrypt_t encrypt_one,
-			   const int nblocks, const int blocksize,
-			   const int context_size)
-{
-  cipher_bulk_ops_t bulk_ops = { 0, };
-  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 first two elements to 16 bytes and latter to
-     block size.  */
-  ctx_aligned_size = context_size + 15;
-  ctx_aligned_size -= ctx_aligned_size & 0xf;
-
-  memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
-
-  mem = xtrycalloc (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 */
-  if (setkey_func (ctx, key, sizeof(key), &bulk_ops) != GPG_ERR_NO_ERROR)
-   {
-     xfree(mem);
-     return "setkey failed";
-   }
-
-  /* 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_ops.cbc_dec (ctx, iv2, plaintext2, ciphertext, 1);
-  if (memcmp (plaintext2, plaintext, blocksize))
-    {
-      xfree (mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CBC-%d test failed (plaintext mismatch)", cipher,
-	      blocksize * 8);
-#else
-      (void)cipher; /* Not used.  */
-#endif
-      return "selftest for CBC failed - see syslog for details";
-    }
-
-  if (memcmp (iv2, iv, blocksize))
-    {
-      xfree (mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8);
-#endif
-      return "selftest for 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_ops.cbc_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
-
-  if (memcmp (plaintext2, plaintext, nblocks * blocksize))
-    {
-      xfree (mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CBC-%d test failed (plaintext mismatch, parallel path)",
-	      cipher, blocksize * 8);
-#endif
-      return "selftest for CBC failed - see syslog for details";
-    }
-  if (memcmp (iv2, iv, blocksize))
-    {
-      xfree (mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CBC-%d test failed (IV mismatch, parallel path)",
-	      cipher, blocksize * 8);
-#endif
-      return "selftest for CBC failed - see syslog for details";
-    }
-
-  xfree (mem);
-  return NULL;
-}
-
-/* Run the self-tests for <block cipher>-CFB-<block size>, tests bulk CFB
-   decryption.  Returns NULL on success. */
-const char *
-_gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey_func,
-			   gcry_cipher_encrypt_t encrypt_one,
-			   const int nblocks, const int blocksize,
-			   const int context_size)
-{
-  cipher_bulk_ops_t bulk_ops = { 0, };
-  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 = {
-      0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
-      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33
-    };
-
-  /* Allocate buffers, align first two elements to 16 bytes and latter to
-     block size.  */
-  ctx_aligned_size = context_size + 15;
-  ctx_aligned_size -= ctx_aligned_size & 0xf;
-
-  memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
-
-  mem = xtrycalloc (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 */
-  if (setkey_func (ctx, key, sizeof(key), &bulk_ops) != GPG_ERR_NO_ERROR)
-   {
-     xfree(mem);
-     return "setkey failed";
-   }
-
-  /* Test single block code path */
-  memset(iv, 0xd3, blocksize);
-  memset(iv2, 0xd3, blocksize);
-  for (i = 0; i < blocksize; i++)
-    plaintext[i] = i;
-
-  /* CFB manually.  */
-  encrypt_one (ctx, ciphertext, iv);
-  buf_xor_2dst (iv, ciphertext, plaintext, blocksize);
-
-  /* CFB decrypt.  */
-  bulk_ops.cfb_dec (ctx, iv2, plaintext2, ciphertext, 1);
-  if (memcmp(plaintext2, plaintext, blocksize))
-    {
-      xfree(mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CFB-%d test failed (plaintext mismatch)", cipher,
-	      blocksize * 8);
-#else
-      (void)cipher; /* Not used.  */
-#endif
-      return "selftest for CFB failed - see syslog for details";
-    }
-
-  if (memcmp(iv2, iv, blocksize))
-    {
-      xfree(mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CFB-%d test failed (IV mismatch)", cipher, blocksize * 8);
-#endif
-      return "selftest for CFB failed - see syslog for details";
-    }
-
-  /* Test parallelized code paths */
-  memset(iv, 0xe6, blocksize);
-  memset(iv2, 0xe6, blocksize);
-
-  for (i = 0; i < nblocks * blocksize; i++)
-    plaintext[i] = i;
-
-  /* Create CFB ciphertext manually.  */
-  for (i = 0; i < nblocks * blocksize; i+=blocksize)
-    {
-      encrypt_one (ctx, &ciphertext[i], iv);
-      buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize);
-    }
-
-  /* Decrypt using bulk CBC and compare result.  */
-  bulk_ops.cfb_dec (ctx, iv2, plaintext2, ciphertext, nblocks);
-
-  if (memcmp(plaintext2, plaintext, nblocks * blocksize))
-    {
-      xfree(mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CFB-%d test failed (plaintext mismatch, parallel path)",
-              cipher, blocksize * 8);
-#endif
-      return "selftest for CFB failed - see syslog for details";
-    }
-  if (memcmp(iv2, iv, blocksize))
-    {
-      xfree(mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CFB-%d test failed (IV mismatch, parallel path)", cipher,
-	      blocksize * 8);
-#endif
-      return "selftest for CFB failed - see syslog for details";
-    }
-
-  xfree(mem);
-  return NULL;
-}
-
-/* Run the self-tests for <block cipher>-CTR-<block size>, tests IV increment
-   of bulk CTR encryption.  Returns NULL on success. */
-const char *
-_gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
-			   gcry_cipher_encrypt_t encrypt_one,
-			   const int nblocks, const int blocksize,
-			   const int context_size)
-{
-  cipher_bulk_ops_t bulk_ops = { 0, };
-  int i, j, offs, diff;
-  unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *ciphertext2,
-                *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 first two elements to 16 bytes and latter to
-     block size.  */
-  ctx_aligned_size = context_size + 15;
-  ctx_aligned_size -= ctx_aligned_size & 0xf;
-
-  memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 4) + 16;
-
-  mem = xtrycalloc (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;
-  ciphertext2 = ciphertext + nblocks * blocksize;
-
-  /* Initialize ctx */
-  if (setkey_func (ctx, key, sizeof(key), &bulk_ops) != GPG_ERR_NO_ERROR)
-   {
-     xfree(mem);
-     return "setkey failed";
-   }
-
-  /* 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_ops.ctr_enc (ctx, iv2, plaintext2, ciphertext, 1);
-
-  if (memcmp (plaintext2, plaintext, blocksize))
-    {
-      xfree (mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CTR-%d test failed (plaintext mismatch)", cipher,
-	      blocksize * 8);
-#else
-      (void)cipher; /* Not used.  */
-#endif
-      return "selftest for CTR failed - see syslog for details";
-    }
-
-  if (memcmp (iv2, iv, blocksize))
-    {
-      xfree (mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CTR-%d test failed (IV mismatch)", cipher,
-	      blocksize * 8);
-#endif
-      return "selftest for CTR failed - see syslog for details";
-    }
-
-  /* Test bulk encryption with typical IV. */
-  memset(iv, 0x57, blocksize-4);
-  iv[blocksize-1] = 1;
-  iv[blocksize-2] = 0;
-  iv[blocksize-3] = 0;
-  iv[blocksize-4] = 0;
-  memset(iv2, 0x57, blocksize-4);
-  iv2[blocksize-1] = 1;
-  iv2[blocksize-2] = 0;
-  iv2[blocksize-3] = 0;
-  iv2[blocksize-4] = 0;
-
-  for (i = 0; i < blocksize * nblocks; i++)
-    plaintext2[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;
-        }
-    }
-
-  bulk_ops.ctr_enc (ctx, iv2, ciphertext2, plaintext2, nblocks);
-
-  if (memcmp (ciphertext2, ciphertext, blocksize * nblocks))
-    {
-      xfree (mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CTR-%d test failed (ciphertext mismatch, bulk)", cipher,
-              blocksize * 8);
-#endif
-      return "selftest for CTR failed - see syslog for details";
-    }
-  if (memcmp(iv2, iv, blocksize))
-    {
-      xfree (mem);
-#ifdef HAVE_SYSLOG
-      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-              "%s-CTR-%d test failed (IV mismatch, bulk)", cipher,
-              blocksize * 8);
-#endif
-      return "selftest for CTR failed - see syslog for details";
-    }
-
-  /* Test parallelized code paths (check counter overflow handling) */
-  for (diff = 0; diff < nblocks; diff++) {
-    memset(iv, 0xff, blocksize);
-    iv[blocksize-1] -= diff;
-    iv[0] = iv[1] = 0;
-    iv[2] = 0x07;
-
-    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;
-    iv2[0] = iv2[1] = 0;
-    iv2[2] = 0x07;
-
-    bulk_ops.ctr_enc (ctx, iv2, plaintext2, ciphertext, nblocks);
-
-    if (memcmp (plaintext2, plaintext, blocksize * nblocks))
-      {
-        xfree (mem);
-#ifdef HAVE_SYSLOG
-        syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-                "%s-CTR-%d test failed (plaintext mismatch, diff: %d)", cipher,
-		blocksize * 8, diff);
-#endif
-        return "selftest for CTR failed - see syslog for details";
-      }
-    if (memcmp(iv2, iv, blocksize))
-      {
-        xfree (mem);
-#ifdef HAVE_SYSLOG
-        syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
-                "%s-CTR-%d test failed (IV mismatch, diff: %d)", cipher,
-		blocksize * 8, diff);
-#endif
-        return "selftest for CTR failed - see syslog for details";
-      }
-  }
-
-  xfree (mem);
-  return NULL;
-}
diff --git a/cipher/cipher-selftest.h b/cipher/cipher-selftest.h
deleted file mode 100644
index c3090ad1..00000000
--- a/cipher/cipher-selftest.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* cipher-selftest.h - Helper functions for bulk encryption selftests.
- * Copyright (C) 2013,2020 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/>.
- */
-
-#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,
-					   size_t nblocks);
-
-typedef void (*gcry_cipher_bulk_cfb_dec_t)(void *context, unsigned char *iv,
-					   void *outbuf_arg,
-					   const void *inbuf_arg,
-					   size_t nblocks);
-
-typedef void (*gcry_cipher_bulk_ctr_enc_t)(void *context, unsigned char *iv,
-					   void *outbuf_arg,
-					   const void *inbuf_arg,
-					   size_t nblocks);
-
-/* Helper function to allocate an aligned context for selftests.  */
-void *_gcry_cipher_selftest_alloc_ctx (const int context_size,
-                                       unsigned char **r_mem);
-
-
-/* Helper function for bulk CBC decryption selftest */
-const char *
-_gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey,
-			   gcry_cipher_encrypt_t encrypt_one,
-			   const int nblocks, const int blocksize,
-			   const int context_size);
-
-/* Helper function for bulk CFB decryption selftest */
-const char *
-_gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey,
-			   gcry_cipher_encrypt_t encrypt_one,
-			   const int nblocks, const int blocksize,
-			   const int context_size);
-
-/* Helper function for bulk CTR encryption selftest */
-const char *
-_gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey,
-			   gcry_cipher_encrypt_t encrypt_one,
-			   const int nblocks, const int blocksize,
-			   const int context_size);
-
-#endif /*G10_SELFTEST_HELP_H*/
diff --git a/cipher/des.c b/cipher/des.c
index 51116fcf..7a81697a 100644
--- a/cipher/des.c
+++ b/cipher/des.c
@@ -120,7 +120,6 @@
 #include "cipher.h"
 #include "bufhelp.h"
 #include "cipher-internal.h"
-#include "cipher-selftest.h"
 
 
 #define DES_BLOCKSIZE 8
@@ -1047,66 +1046,6 @@ is_weak_key ( const byte *key )
 }
 
 
-/* Alternative setkey for selftests; need larger key than default. */
-static gcry_err_code_t
-bulk_selftest_setkey (void *context, const byte *__key, unsigned __keylen,
-                      cipher_bulk_ops_t *bulk_ops)
-{
-  static const unsigned char key[24] ATTR_ALIGNED_16 = {
-      0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
-      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22,
-      0x18,0x2A,0x39,0x47,0x5E,0x6F,0x75,0x82
-    };
-
-  (void)__key;
-  (void)__keylen;
-
-  return do_tripledes_setkey(context, key, sizeof(key), bulk_ops);
-}
-
-
-/* Run the self-tests for DES-CTR, tests IV increment of bulk CTR
-   encryption.  Returns NULL on success. */
-static const char *
-selftest_ctr (void)
-{
-  const int nblocks = 3+1;
-  const int blocksize = DES_BLOCKSIZE;
-  const int context_size = sizeof(struct _tripledes_ctx);
-
-  return _gcry_selftest_helper_ctr("3DES", &bulk_selftest_setkey,
-           &do_tripledes_encrypt, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for DES-CBC, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char *
-selftest_cbc (void)
-{
-  const int nblocks = 3+2;
-  const int blocksize = DES_BLOCKSIZE;
-  const int context_size = sizeof(struct _tripledes_ctx);
-
-  return _gcry_selftest_helper_cbc("3DES", &bulk_selftest_setkey,
-           &do_tripledes_encrypt, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for DES-CFB, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char *
-selftest_cfb (void)
-{
-  const int nblocks = 3+2;
-  const int blocksize = DES_BLOCKSIZE;
-  const int context_size = sizeof(struct _tripledes_ctx);
-
-  return _gcry_selftest_helper_cfb("3DES", &bulk_selftest_setkey,
-           &do_tripledes_encrypt, nblocks, blocksize, context_size);
-}
-
-
 /*
  * Performs a selftest of this DES/Triple-DES implementation.
  * Returns an string with the error text on failure.
@@ -1115,8 +1054,6 @@ selftest_cfb (void)
 static const char *
 selftest (void)
 {
-  const char *r;
-
   /*
    * Check if 'u32' is really 32 bits wide. This DES / 3DES implementation
    * need this.
@@ -1296,15 +1233,6 @@ selftest (void)
         return "DES weak key detection failed";
   }
 
-  if ( (r = selftest_cbc ()) )
-    return r;
-
-  if ( (r = selftest_cfb ()) )
-    return r;
-
-  if ( (r = selftest_ctr ()) )
-    return r;
-
   return 0;
 }
 
diff --git a/cipher/rijndael-aesni.c b/cipher/rijndael-aesni.c
index ff6b0b26..156af015 100644
--- a/cipher/rijndael-aesni.c
+++ b/cipher/rijndael-aesni.c
@@ -27,7 +27,6 @@
 #include "g10lib.h"
 #include "cipher.h"
 #include "bufhelp.h"
-#include "cipher-selftest.h"
 #include "rijndael-internal.h"
 #include "./cipher-internal.h"
 
diff --git a/cipher/rijndael-armv8-ce.c b/cipher/rijndael-armv8-ce.c
index b24ae3e9..e53c940e 100644
--- a/cipher/rijndael-armv8-ce.c
+++ b/cipher/rijndael-armv8-ce.c
@@ -27,7 +27,6 @@
 #include "g10lib.h"
 #include "cipher.h"
 #include "bufhelp.h"
-#include "cipher-selftest.h"
 #include "rijndael-internal.h"
 #include "./cipher-internal.h"
 
diff --git a/cipher/rijndael-padlock.c b/cipher/rijndael-padlock.c
index 3af214d7..2583b834 100644
--- a/cipher/rijndael-padlock.c
+++ b/cipher/rijndael-padlock.c
@@ -27,7 +27,6 @@
 #include "g10lib.h"
 #include "cipher.h"
 #include "bufhelp.h"
-#include "cipher-selftest.h"
 #include "rijndael-internal.h"
 
 #ifdef USE_PADLOCK
diff --git a/cipher/rijndael-ssse3-amd64.c b/cipher/rijndael-ssse3-amd64.c
index b0723853..0f0abf62 100644
--- a/cipher/rijndael-ssse3-amd64.c
+++ b/cipher/rijndael-ssse3-amd64.c
@@ -43,7 +43,6 @@
 #include "g10lib.h"
 #include "cipher.h"
 #include "bufhelp.h"
-#include "cipher-selftest.h"
 #include "rijndael-internal.h"
 #include "./cipher-internal.h"
 
diff --git a/cipher/rijndael-vaes.c b/cipher/rijndael-vaes.c
index 0d7d1367..dbcf9afa 100644
--- a/cipher/rijndael-vaes.c
+++ b/cipher/rijndael-vaes.c
@@ -26,7 +26,6 @@
 #include "g10lib.h"
 #include "cipher.h"
 #include "bufhelp.h"
-#include "cipher-selftest.h"
 #include "rijndael-internal.h"
 #include "./cipher-internal.h"
 
diff --git a/cipher/rijndael.c b/cipher/rijndael.c
index 9b96b616..dddcbc54 100644
--- a/cipher/rijndael.c
+++ b/cipher/rijndael.c
@@ -46,7 +46,6 @@
 #include "g10lib.h"
 #include "cipher.h"
 #include "bufhelp.h"
-#include "cipher-selftest.h"
 #include "rijndael-internal.h"
 #include "./cipher-internal.h"
 
@@ -1535,7 +1534,7 @@ static const char*
 selftest_basic_128 (void)
 {
   RIJNDAEL_context *ctx;
-  unsigned char *ctxmem;
+  unsigned char ctxmem[sizeof(*ctx) + 16];
   unsigned char scratch[16];
   cipher_bulk_ops_t bulk_ops;
 
@@ -1579,21 +1578,15 @@ selftest_basic_128 (void)
     };
 #endif
 
-  /* Because gcc/ld can only align the CTX struct on 8 bytes on the
-     stack, we need to allocate that context on the heap.  */
-  ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem);
-  if (!ctx)
-    return "failed to allocate memory";
+  ctx = (void *)(ctxmem + ((16 - ((uintptr_t)ctxmem & 15)) & 15));
 
   rijndael_setkey (ctx, key_128, sizeof (key_128), &bulk_ops);
   rijndael_encrypt (ctx, scratch, plaintext_128);
   if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128)))
     {
-      xfree (ctxmem);
       return "AES-128 test encryption failed.";
     }
   rijndael_decrypt (ctx, scratch, scratch);
-  xfree (ctxmem);
   if (memcmp (scratch, plaintext_128, sizeof (plaintext_128)))
     return "AES-128 test decryption failed.";
 
@@ -1605,7 +1598,7 @@ static const char*
 selftest_basic_192 (void)
 {
   RIJNDAEL_context *ctx;
-  unsigned char *ctxmem;
+  unsigned char ctxmem[sizeof(*ctx) + 16];
   unsigned char scratch[16];
   cipher_bulk_ops_t bulk_ops;
 
@@ -1626,18 +1619,15 @@ selftest_basic_192 (void)
       0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA
     };
 
-  ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem);
-  if (!ctx)
-    return "failed to allocate memory";
+  ctx = (void *)(ctxmem + ((16 - ((uintptr_t)ctxmem & 15)) & 15));
+
   rijndael_setkey (ctx, key_192, sizeof(key_192), &bulk_ops);
   rijndael_encrypt (ctx, scratch, plaintext_192);
   if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192)))
     {
-      xfree (ctxmem);
       return "AES-192 test encryption failed.";
     }
   rijndael_decrypt (ctx, scratch, scratch);
-  xfree (ctxmem);
   if (memcmp (scratch, plaintext_192, sizeof (plaintext_192)))
     return "AES-192 test decryption failed.";
 
@@ -1650,7 +1640,7 @@ static const char*
 selftest_basic_256 (void)
 {
   RIJNDAEL_context *ctx;
-  unsigned char *ctxmem;
+  unsigned char ctxmem[sizeof(*ctx) + 16];
   unsigned char scratch[16];
   cipher_bulk_ops_t bulk_ops;
 
@@ -1672,18 +1662,15 @@ selftest_basic_256 (void)
       0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3
     };
 
-  ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem);
-  if (!ctx)
-    return "failed to allocate memory";
+  ctx = (void *)(ctxmem + ((16 - ((uintptr_t)ctxmem & 15)) & 15));
+
   rijndael_setkey (ctx, key_256, sizeof(key_256), &bulk_ops);
   rijndael_encrypt (ctx, scratch, plaintext_256);
   if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256)))
     {
-      xfree (ctxmem);
       return "AES-256 test encryption failed.";
     }
   rijndael_decrypt (ctx, scratch, scratch);
-  xfree (ctxmem);
   if (memcmp (scratch, plaintext_256, sizeof (plaintext_256)))
     return "AES-256 test decryption failed.";
 
@@ -1691,60 +1678,6 @@ selftest_basic_256 (void)
 }
 
 
-/* Run the self-tests for AES-CTR-128, tests IV increment of bulk CTR
-   encryption.  Returns NULL on success. */
-static const char*
-selftest_ctr_128 (void)
-{
-#ifdef USE_VAES
-  const int nblocks = 16+1;
-#else
-  const int nblocks = 8+1;
-#endif
-  const int blocksize = BLOCKSIZE;
-  const int context_size = sizeof(RIJNDAEL_context);
-
-  return _gcry_selftest_helper_ctr("AES", &rijndael_setkey,
-           &rijndael_encrypt, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for AES-CBC-128, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char*
-selftest_cbc_128 (void)
-{
-#ifdef USE_VAES
-  const int nblocks = 16+2;
-#else
-  const int nblocks = 8+2;
-#endif
-  const int blocksize = BLOCKSIZE;
-  const int context_size = sizeof(RIJNDAEL_context);
-
-  return _gcry_selftest_helper_cbc("AES", &rijndael_setkey,
-           &rijndael_encrypt, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for AES-CFB-128, tests bulk CFB decryption.
-   Returns NULL on success. */
-static const char*
-selftest_cfb_128 (void)
-{
-#ifdef USE_VAES
-  const int nblocks = 16+2;
-#else
-  const int nblocks = 8+2;
-#endif
-  const int blocksize = BLOCKSIZE;
-  const int context_size = sizeof(RIJNDAEL_context);
-
-  return _gcry_selftest_helper_cfb("AES", &rijndael_setkey,
-           &rijndael_encrypt, nblocks, blocksize, context_size);
-}
-
-
 /* Run all the self-tests and return NULL on success.  This function
    is used for the on-the-fly self-tests. */
 static const char *
@@ -1757,15 +1690,6 @@ selftest (void)
        || (r = selftest_basic_256 ()) )
     return r;
 
-  if ( (r = selftest_ctr_128 ()) )
-    return r;
-
-  if ( (r = selftest_cbc_128 ()) )
-    return r;
-
-  if ( (r = selftest_cfb_128 ()) )
-    return r;
-
   return r;
 }
 
diff --git a/cipher/serpent.c b/cipher/serpent.c
index dfe5cc28..11eeb079 100644
--- a/cipher/serpent.c
+++ b/cipher/serpent.c
@@ -30,7 +30,6 @@
 #include "bithelp.h"
 #include "bufhelp.h"
 #include "cipher-internal.h"
-#include "cipher-selftest.h"
 #include "bulkhelp.h"
 
 
@@ -1540,48 +1539,6 @@ _gcry_serpent_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
 
 
 
-/* Run the self-tests for SERPENT-CTR-128, tests IV increment of bulk CTR
-   encryption.  Returns NULL on success. */
-static const char*
-selftest_ctr_128 (void)
-{
-  const int nblocks = 16+8+1;
-  const int blocksize = sizeof(serpent_block_t);
-  const int context_size = sizeof(serpent_context_t);
-
-  return _gcry_selftest_helper_ctr("SERPENT", &serpent_setkey,
-           &serpent_encrypt, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for SERPENT-CBC-128, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char*
-selftest_cbc_128 (void)
-{
-  const int nblocks = 16+8+2;
-  const int blocksize = sizeof(serpent_block_t);
-  const int context_size = sizeof(serpent_context_t);
-
-  return _gcry_selftest_helper_cbc("SERPENT", &serpent_setkey,
-           &serpent_encrypt, nblocks, blocksize, context_size);
-}
-
-
-/* Run the self-tests for SERPENT-CBC-128, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char*
-selftest_cfb_128 (void)
-{
-  const int nblocks = 16+8+2;
-  const int blocksize = sizeof(serpent_block_t);
-  const int context_size = sizeof(serpent_context_t);
-
-  return _gcry_selftest_helper_cfb("SERPENT", &serpent_setkey,
-           &serpent_encrypt, nblocks, blocksize, context_size);
-}
-
-
 /* Serpent test.  */
 
 static const char *
@@ -1590,7 +1547,6 @@ serpent_test (void)
   serpent_context_t context;
   unsigned char scratch[16];
   unsigned int i;
-  const char *r;
 
   static struct test
   {
@@ -1662,15 +1618,6 @@ serpent_test (void)
 	}
     }
 
-  if ( (r = selftest_ctr_128 ()) )
-    return r;
-
-  if ( (r = selftest_cbc_128 ()) )
-    return r;
-
-  if ( (r = selftest_cfb_128 ()) )
-    return r;
-
   return NULL;
 }
 
diff --git a/cipher/sm4.c b/cipher/sm4.c
index 7c7bc1ff..5f8bf224 100644
--- a/cipher/sm4.c
+++ b/cipher/sm4.c
@@ -29,7 +29,6 @@
 #include "cipher.h"
 #include "bufhelp.h"
 #include "cipher-internal.h"
-#include "cipher-selftest.h"
 #include "bulkhelp.h"
 
 /* Helper macro to force alignment to 64 bytes.  */
@@ -1429,51 +1428,11 @@ _gcry_sm4_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, size_t nblocks)
   return 0;
 }
 
-/* Run the self-tests for SM4-CTR, tests IV increment of bulk CTR
-   encryption.  Returns NULL on success. */
-static const char*
-selftest_ctr_128 (void)
-{
-  const int nblocks = 16 - 1;
-  const int blocksize = 16;
-  const int context_size = sizeof(SM4_context);
-
-  return _gcry_selftest_helper_ctr("SM4", &sm4_setkey,
-           &sm4_encrypt, nblocks, blocksize, context_size);
-}
-
-/* Run the self-tests for SM4-CBC, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char*
-selftest_cbc_128 (void)
-{
-  const int nblocks = 16 - 1;
-  const int blocksize = 16;
-  const int context_size = sizeof(SM4_context);
-
-  return _gcry_selftest_helper_cbc("SM4", &sm4_setkey,
-           &sm4_encrypt, nblocks, blocksize, context_size);
-}
-
-/* Run the self-tests for SM4-CFB, tests bulk CFB decryption.
-   Returns NULL on success. */
-static const char*
-selftest_cfb_128 (void)
-{
-  const int nblocks = 16 - 1;
-  const int blocksize = 16;
-  const int context_size = sizeof(SM4_context);
-
-  return _gcry_selftest_helper_cfb("SM4", &sm4_setkey,
-           &sm4_encrypt, nblocks, blocksize, context_size);
-}
-
 static const char *
 sm4_selftest (void)
 {
   SM4_context ctx;
   byte scratch[16];
-  const char *r;
 
   static const byte plaintext[16] = {
     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
@@ -1498,15 +1457,6 @@ sm4_selftest (void)
   if (memcmp (scratch, plaintext, sizeof (plaintext)))
     return "SM4 test decryption failed.";
 
-  if ( (r = selftest_ctr_128 ()) )
-    return r;
-
-  if ( (r = selftest_cbc_128 ()) )
-    return r;
-
-  if ( (r = selftest_cfb_128 ()) )
-    return r;
-
   return NULL;
 }
 
diff --git a/cipher/twofish.c b/cipher/twofish.c
index 4ae5d5a6..b300715b 100644
--- a/cipher/twofish.c
+++ b/cipher/twofish.c
@@ -46,7 +46,6 @@
 #include "cipher.h"
 #include "bufhelp.h"
 #include "cipher-internal.h"
-#include "cipher-selftest.h"
 #include "bulkhelp.h"
 
 
@@ -1527,46 +1526,6 @@ _gcry_twofish_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
   return nblocks;
 }
 
-
-
-/* Run the self-tests for TWOFISH-CTR, tests IV increment of bulk CTR
-   encryption.  Returns NULL on success. */
-static const char *
-selftest_ctr (void)
-{
-  const int nblocks = 16+1;
-  const int blocksize = TWOFISH_BLOCKSIZE;
-  const int context_size = sizeof(TWOFISH_context);
-
-  return _gcry_selftest_helper_ctr("TWOFISH", &twofish_setkey,
-           &twofish_encrypt, nblocks, blocksize, context_size);
-}
-
-/* Run the self-tests for TWOFISH-CBC, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char *
-selftest_cbc (void)
-{
-  const int nblocks = 16+2;
-  const int blocksize = TWOFISH_BLOCKSIZE;
-  const int context_size = sizeof(TWOFISH_context);
-
-  return _gcry_selftest_helper_cbc("TWOFISH", &twofish_setkey,
-           &twofish_encrypt, nblocks, blocksize, context_size);
-}
-
-/* Run the self-tests for TWOFISH-CFB, tests bulk CBC decryption.
-   Returns NULL on success. */
-static const char *
-selftest_cfb (void)
-{
-  const int nblocks = 16+2;
-  const int blocksize = TWOFISH_BLOCKSIZE;
-  const int context_size = sizeof(TWOFISH_context);
-
-  return _gcry_selftest_helper_cfb("TWOFISH", &twofish_setkey,
-           &twofish_encrypt, nblocks, blocksize, context_size);
-}
 
 
 /* Test a single encryption and decryption with each key size. */
@@ -1577,7 +1536,6 @@ selftest (void)
   TWOFISH_context ctx; /* Expanded key. */
   byte scratch[16];    /* Encryption/decryption result buffer. */
   cipher_bulk_ops_t bulk_ops;
-  const char *r;
 
   /* Test vectors for single encryption/decryption.  Note that I am using
    * the vectors from the Twofish paper's "known answer test", I=3 for
@@ -1627,13 +1585,6 @@ selftest (void)
   if (memcmp (scratch, plaintext_256, sizeof (plaintext_256)))
     return "Twofish-256 test decryption failed.";
 
-  if ((r = selftest_ctr()) != NULL)
-    return r;
-  if ((r = selftest_cbc()) != NULL)
-    return r;
-  if ((r = selftest_cfb()) != NULL)
-    return r;
-
   return NULL;
 }
 
diff --git a/tests/basic.c b/tests/basic.c
index 40a0a474..f5513740 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -27,6 +27,13 @@
 #include <string.h>
 #include <stdarg.h>
 #include <assert.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
 
 #include "../src/gcrypt-int.h"
 
@@ -11672,6 +11679,764 @@ out:
 
 
 
+static void buf_xor(void *vdst, const void *vsrc1, const void *vsrc2, size_t len)
+{
+  char *dst = vdst;
+  const char *src1 = vsrc1;
+  const char *src2 = vsrc2;
+
+  while (len)
+    {
+      *(char *)dst = *(char *)src1 ^ *(char *)src2;
+      dst++;
+      src1++;
+      src2++;
+      len--;
+    }
+}
+
+/* Run the tests for <block cipher>-CBC-<block size>, tests bulk CBC
+   decryption.  Returns NULL on success. */
+static int
+cipher_cbc_bulk_test (int cipher_algo)
+{
+  const int nblocks = 128 - 1;
+  int i, offs;
+  int blocksize;
+  const char *cipher;
+  gcry_cipher_hd_t hd_one;
+  gcry_cipher_hd_t hd_cbc;
+  gcry_error_t err = 0;
+  unsigned char *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
+  unsigned int memsize;
+  unsigned int keylen;
+
+  static const unsigned char key[32] = {
+      0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22,
+      0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22
+    };
+
+  if (gcry_cipher_test_algo (cipher_algo))
+    return -1;
+  blocksize = gcry_cipher_get_algo_blklen(cipher_algo);
+  if (blocksize < 8)
+    return -1;
+  cipher = gcry_cipher_algo_name (cipher_algo);
+  keylen = gcry_cipher_get_algo_keylen (cipher_algo);
+  if (keylen > sizeof(key))
+    {
+      fail ("%s-CBC-%d test failed (key too short)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  memsize = (blocksize * 2) + (blocksize * nblocks * 3) + 16;
+
+  mem = xcalloc (1, memsize);
+  if (!mem)
+    return -1;
+
+  offs = (16 - ((uintptr_t)mem & 15)) & 15;
+  iv = (void*)(mem + offs);
+  iv2 = iv + blocksize;
+  plaintext = iv2 + blocksize;
+  plaintext2 = plaintext + nblocks * blocksize;
+  ciphertext = plaintext2 + nblocks * blocksize;
+
+  err = gcry_cipher_open (&hd_one, cipher_algo, GCRY_CIPHER_MODE_ECB, 0);
+  if (err)
+    {
+      xfree(mem);
+      fail ("%s-CBC-%d test failed (cipher open fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_open (&hd_cbc, cipher_algo, GCRY_CIPHER_MODE_CBC, 0);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      xfree(mem);
+      fail ("%s-CBC-%d test failed (cipher open fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  /* Initialize ctx */
+  if (gcry_cipher_setkey (hd_one, key, keylen) ||
+      gcry_cipher_setkey (hd_cbc, key, keylen))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree(mem);
+      fail ("%s-CBC-%d test failed (setkey fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  /* 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);
+  err = gcry_cipher_encrypt (hd_one, ciphertext, blocksize,
+                             ciphertext, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree(mem);
+      fail ("%s-CBC-%d test failed (ECB encrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  memcpy (iv, ciphertext, blocksize);
+
+  /* CBC decrypt.  */
+  err = gcry_cipher_setiv (hd_cbc, iv2, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree(mem);
+      fail ("%s-CBC-%d test failed (setiv fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_decrypt (hd_cbc, plaintext2, blocksize * 1,
+                             ciphertext, blocksize * 1);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree(mem);
+      fail ("%s-CBC-%d test failed (CBC decrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  if (memcmp (plaintext2, plaintext, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree (mem);
+      fail ("%s-CBC-%d test failed (plaintext mismatch)", cipher, blocksize * 8);
+      return -1;
+    }
+
+#if 0 /* missing interface for reading IV */
+  if (memcmp (iv2, iv, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree (mem);
+      fail ("%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8);
+      return -1;
+    }
+#endif
+
+  /* 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);
+      err = gcry_cipher_encrypt (hd_one, &ciphertext[i], blocksize,
+                                 &ciphertext[i], blocksize);
+      if (err)
+        {
+          gcry_cipher_close (hd_one);
+          gcry_cipher_close (hd_cbc);
+          xfree(mem);
+          fail ("%s-CBC-%d test failed (ECB encrypt fail)", cipher, blocksize * 8);
+          return -1;
+        }
+      memcpy (iv, &ciphertext[i], blocksize);
+    }
+
+  /* Decrypt using bulk CBC and compare result.  */
+  err = gcry_cipher_setiv (hd_cbc, iv2, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree(mem);
+      fail ("%s-CBC-%d test failed (setiv fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_decrypt (hd_cbc, plaintext2, blocksize * nblocks,
+                             ciphertext, blocksize * nblocks);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree(mem);
+      fail ("%s-CBC-%d test failed (CBC decrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  if (memcmp (plaintext2, plaintext, nblocks * blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree (mem);
+      fail ("%s-CBC-%d test failed (plaintext mismatch, parallel path)",
+            cipher, blocksize * 8);
+      return -1;
+    }
+#if 0 /* missing interface for reading IV */
+  if (memcmp (iv2, iv, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cbc);
+      xfree (mem);
+      fail ("%s-CBC-%d test failed (IV mismatch, parallel path)",
+            cipher, blocksize * 8);
+      return -1;
+    }
+#endif
+
+  gcry_cipher_close (hd_one);
+  gcry_cipher_close (hd_cbc);
+  xfree (mem);
+  return -1;
+}
+
+
+static void
+buf_xor_2dst(void *vdst1, void *vdst2, const void *vsrc, size_t len)
+{
+  byte *dst1 = vdst1;
+  byte *dst2 = vdst2;
+  const byte *src = vsrc;
+
+  for (; len; len--)
+    *dst1++ = (*dst2++ ^= *src++);
+}
+
+/* Run the tests for <block cipher>-CFB-<block size>, tests bulk CFB
+   decryption.  Returns NULL on success. */
+static int
+cipher_cfb_bulk_test (int cipher_algo)
+{
+  const int nblocks = 128 - 1;
+  int blocksize;
+  const char *cipher;
+  gcry_cipher_hd_t hd_one;
+  gcry_cipher_hd_t hd_cfb;
+  gcry_error_t err = 0;
+  int i, offs;
+  unsigned char *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
+  unsigned int memsize;
+  unsigned int keylen;
+
+  static const unsigned char key[32] = {
+      0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33,
+      0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33
+    };
+
+  if (gcry_cipher_test_algo (cipher_algo))
+    return -1;
+  blocksize = gcry_cipher_get_algo_blklen(cipher_algo);
+  if (blocksize < 8)
+    return -1;
+  cipher = gcry_cipher_algo_name (cipher_algo);
+  keylen = gcry_cipher_get_algo_keylen (cipher_algo);
+  if (keylen > sizeof(key))
+    {
+      fail ("%s-CFB-%d test failed (key too short)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  memsize = (blocksize * 2) + (blocksize * nblocks * 3) + 16;
+
+  mem = xcalloc (1, memsize);
+  if (!mem)
+    return -1;
+
+  offs = (16 - ((uintptr_t)mem & 15)) & 15;
+  iv = (void*)(mem + offs);
+  iv2 = iv + blocksize;
+  plaintext = iv2 + blocksize;
+  plaintext2 = plaintext + nblocks * blocksize;
+  ciphertext = plaintext2 + nblocks * blocksize;
+
+  err = gcry_cipher_open (&hd_one, cipher_algo, GCRY_CIPHER_MODE_ECB, 0);
+  if (err)
+    {
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (cipher open fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_open (&hd_cfb, cipher_algo, GCRY_CIPHER_MODE_CFB, 0);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (cipher open fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  /* Initialize ctx */
+  if (gcry_cipher_setkey (hd_one, key, keylen) ||
+      gcry_cipher_setkey (hd_cfb, key, keylen))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (setkey fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  /* Test single block code path */
+  memset(iv, 0xd3, blocksize);
+  memset(iv2, 0xd3, blocksize);
+  for (i = 0; i < blocksize; i++)
+    plaintext[i] = i;
+
+  /* CFB manually.  */
+  err = gcry_cipher_encrypt (hd_one, ciphertext, blocksize, iv, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (ECB encrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  buf_xor_2dst (iv, ciphertext, plaintext, blocksize);
+
+  /* CFB decrypt.  */
+  err = gcry_cipher_setiv (hd_cfb, iv2, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (setiv fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_decrypt (hd_cfb, plaintext2, blocksize * 1,
+                             ciphertext, blocksize * 1);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (CFB decrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  if (memcmp(plaintext2, plaintext, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (plaintext mismatch)",
+            cipher, blocksize * 8);
+      return -1;
+    }
+
+#if 0
+  if (memcmp(iv2, iv, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (IV mismatch)",
+            cipher, blocksize * 8);
+      return -1;
+    }
+#endif
+
+  /* Test parallelized code paths */
+  memset(iv, 0xe6, blocksize);
+  memset(iv2, 0xe6, blocksize);
+
+  for (i = 0; i < nblocks * blocksize; i++)
+    plaintext[i] = i;
+
+  /* Create CFB ciphertext manually.  */
+  for (i = 0; i < nblocks * blocksize; i+=blocksize)
+    {
+      err = gcry_cipher_encrypt (hd_one, &ciphertext[i], blocksize,
+                                 iv, blocksize);
+      if (err)
+        {
+          gcry_cipher_close (hd_one);
+          gcry_cipher_close (hd_cfb);
+          xfree(mem);
+          fail ("%s-CFB-%d test failed (ECB encrypt fail)", cipher, blocksize * 8);
+          return -1;
+        }
+      buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize);
+    }
+
+  /* Decrypt using bulk CBC and compare result.  */
+  err = gcry_cipher_setiv (hd_cfb, iv2, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (setiv fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_decrypt (hd_cfb, plaintext2, blocksize * nblocks,
+                             ciphertext, blocksize * nblocks);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (CFB decrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  if (memcmp(plaintext2, plaintext, nblocks * blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (plaintext mismatch, parallel path)",
+            cipher, blocksize * 8);
+      return -1;
+    }
+#if 0
+  if (memcmp(iv2, iv, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_cfb);
+      xfree(mem);
+      fail ("%s-CFB-%d test failed (IV mismatch, parallel path)",
+            cipher, blocksize * 8);
+      return -1;
+    }
+#endif
+
+  gcry_cipher_close (hd_one);
+  gcry_cipher_close (hd_cfb);
+  xfree(mem);
+  return -1;
+}
+
+
+/* Run the tests for <block cipher>-CTR-<block size>, tests IV increment
+   of bulk CTR encryption.  Returns NULL on success. */
+static int
+cipher_ctr_bulk_test (int cipher_algo)
+{
+  const int nblocks = 128 - 1;
+  int blocksize;
+  const char *cipher;
+  gcry_cipher_hd_t hd_one;
+  gcry_cipher_hd_t hd_ctr;
+  gcry_error_t err = 0;
+  int i, j, offs, diff;
+  unsigned char *plaintext, *plaintext2, *ciphertext, *ciphertext2,
+                *iv, *iv2, *mem;
+  unsigned int memsize;
+  unsigned int keylen;
+
+  static const unsigned char key[32] = {
+      0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21,
+      0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+      0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
+    };
+
+  if (gcry_cipher_test_algo (cipher_algo))
+    return -1;
+  blocksize = gcry_cipher_get_algo_blklen(cipher_algo);
+  if (blocksize < 8)
+    return -1;
+  cipher = gcry_cipher_algo_name (cipher_algo);
+  keylen = gcry_cipher_get_algo_keylen (cipher_algo);
+  if (keylen > sizeof(key))
+    {
+      fail ("%s-CTR-%d test failed (key too short)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  memsize = (blocksize * 2) + (blocksize * nblocks * 4) + 16;
+
+  mem = xcalloc (1, memsize);
+  if (!mem)
+    return -1;
+
+  offs = (16 - ((uintptr_t)mem & 15)) & 15;
+  iv = (void*)(mem + offs);
+  iv2 = iv + blocksize;
+  plaintext = iv2 + blocksize;
+  plaintext2 = plaintext + nblocks * blocksize;
+  ciphertext = plaintext2 + nblocks * blocksize;
+  ciphertext2 = ciphertext + nblocks * blocksize;
+
+  err = gcry_cipher_open (&hd_one, cipher_algo, GCRY_CIPHER_MODE_ECB, 0);
+  if (err)
+    {
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (cipher open fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_open (&hd_ctr, cipher_algo, GCRY_CIPHER_MODE_CTR, 0);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (cipher open fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  /* Initialize ctx */
+  if (gcry_cipher_setkey (hd_one, key, keylen) ||
+      gcry_cipher_setkey (hd_ctr, key, keylen))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (setkey fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  /* Test single block code path */
+  memset (iv, 0xff, blocksize);
+  for (i = 0; i < blocksize; i++)
+    plaintext[i] = i;
+
+  /* CTR manually.  */
+  err = gcry_cipher_encrypt (hd_one, ciphertext, blocksize, iv, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (ECB encrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  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);
+  err = gcry_cipher_setctr (hd_ctr, iv2, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (setiv fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_encrypt (hd_ctr, plaintext2, blocksize * 1,
+                             ciphertext, blocksize * 1);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (CTR encrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  if (memcmp (plaintext2, plaintext, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (plaintext mismatch)",
+            cipher, blocksize * 8);
+      return -1;
+    }
+
+#if 0
+  if (memcmp (iv2, iv, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (IV mismatch)", cipher, blocksize * 8);
+      return -1;
+    }
+#endif
+
+  /* Test bulk encryption with typical IV. */
+  memset(iv, 0x57, blocksize-4);
+  iv[blocksize-1] = 1;
+  iv[blocksize-2] = 0;
+  iv[blocksize-3] = 0;
+  iv[blocksize-4] = 0;
+  memset(iv2, 0x57, blocksize-4);
+  iv2[blocksize-1] = 1;
+  iv2[blocksize-2] = 0;
+  iv2[blocksize-3] = 0;
+  iv2[blocksize-4] = 0;
+
+  for (i = 0; i < blocksize * nblocks; i++)
+    plaintext2[i] = plaintext[i] = i;
+
+  /* Create CTR ciphertext manually.  */
+  for (i = 0; i < blocksize * nblocks; i+=blocksize)
+    {
+      err = gcry_cipher_encrypt (hd_one, &ciphertext[i], blocksize,
+                                 iv, blocksize);
+      if (err)
+        {
+          gcry_cipher_close (hd_one);
+          gcry_cipher_close (hd_ctr);
+          xfree(mem);
+          fail ("%s-CTR-%d test failed (ECB encrypt fail)",
+                cipher, blocksize * 8);
+          return -1;
+        }
+      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;
+        }
+    }
+
+  err = gcry_cipher_setctr (hd_ctr, iv2, blocksize);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (setiv fail)", cipher, blocksize * 8);
+      return -1;
+    }
+  err = gcry_cipher_encrypt (hd_ctr, ciphertext2, blocksize * nblocks,
+                             plaintext2, blocksize * nblocks);
+  if (err)
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (CTR encrypt fail)", cipher, blocksize * 8);
+      return -1;
+    }
+
+  if (memcmp (ciphertext2, ciphertext, blocksize * nblocks))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (ciphertext mismatch, bulk)",
+            cipher, blocksize * 8);
+      return -1;
+    }
+#if 0
+  if (memcmp (iv2, iv, blocksize))
+    {
+      gcry_cipher_close (hd_one);
+      gcry_cipher_close (hd_ctr);
+      xfree(mem);
+      fail ("%s-CTR-%d test failed (IV mismatch, bulk)", cipher, blocksize * 8);
+      return -1;
+    }
+#endif
+
+  /* Test parallelized code paths (check counter overflow handling) */
+  for (diff = 0; diff < nblocks; diff++) {
+    memset(iv, 0xff, blocksize);
+    iv[blocksize-1] -= diff;
+    iv[0] = iv[1] = 0;
+    iv[2] = 0x07;
+
+    for (i = 0; i < blocksize * nblocks; i++)
+      plaintext[i] = i;
+
+    /* Create CTR ciphertext manually.  */
+    for (i = 0; i < blocksize * nblocks; i+=blocksize)
+      {
+        err = gcry_cipher_encrypt (hd_one, &ciphertext[i], blocksize,
+                                  iv, blocksize);
+        if (err)
+          {
+            gcry_cipher_close (hd_one);
+            gcry_cipher_close (hd_ctr);
+            xfree(mem);
+            fail ("%s-CTR-%d test failed (ECB encrypt fail)",
+                  cipher, blocksize * 8);
+            return -1;
+          }
+        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;
+    iv2[0] = iv2[1] = 0;
+    iv2[2] = 0x07;
+
+    err = gcry_cipher_setctr (hd_ctr, iv2, blocksize);
+    if (err)
+      {
+        gcry_cipher_close (hd_one);
+        gcry_cipher_close (hd_ctr);
+        xfree(mem);
+        fail ("%s-CTR-%d test failed (setiv fail)", cipher, blocksize * 8);
+        return -1;
+      }
+    err = gcry_cipher_decrypt (hd_ctr, plaintext2, blocksize * nblocks,
+                               ciphertext, blocksize * nblocks);
+    if (err)
+      {
+        gcry_cipher_close (hd_one);
+        gcry_cipher_close (hd_ctr);
+        xfree(mem);
+        fail ("%s-CTR-%d test failed (CTR decrypt fail)", cipher, blocksize * 8);
+        return -1;
+      }
+
+    if (memcmp (plaintext2, plaintext, blocksize * nblocks))
+      {
+        gcry_cipher_close (hd_one);
+        gcry_cipher_close (hd_ctr);
+        xfree(mem);
+        fail ("%s-CTR-%d test failed (plaintext mismatch, diff: %d)",
+              cipher, blocksize * 8, diff);
+        return -1;
+      }
+#if 0
+    if (memcmp(iv2, iv, blocksize))
+      {
+        gcry_cipher_close (hd_one);
+        gcry_cipher_close (hd_ctr);
+        xfree(mem);
+        fail ("%s-CTR-%d test failed (IV mismatch, diff: %d)",
+              cipher, blocksize * 8, diff);
+        return -1;
+      }
+#endif
+  }
+
+  gcry_cipher_close (hd_one);
+  gcry_cipher_close (hd_ctr);
+  xfree(mem);
+  return -1;
+}
+
+
+
 static void
 check_ciphers (void)
 {
@@ -11784,6 +12549,13 @@ check_ciphers (void)
         check_one_cipher (algos[i], GCRY_CIPHER_MODE_OCB, 0);
       if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_XTS_BLOCK_LEN)
         check_one_cipher (algos[i], GCRY_CIPHER_MODE_XTS, 0);
+
+      if (gcry_cipher_get_algo_blklen (algos[i]) >= 8)
+        {
+          cipher_cbc_bulk_test (algos[i]);
+          cipher_cfb_bulk_test (algos[i]);
+          cipher_ctr_bulk_test (algos[i]);
+        }
     }
 
   for (i = 0; algos2[i]; i++)
-- 
2.34.1




More information about the Gcrypt-devel mailing list