From 8ab9b5dd843bd8ff8abe4cc4b1c23c7b6a9445f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se>
Date: Fri, 1 Jul 2011 23:53:49 +0200
Subject: [PATCH] (CBC_BUFFER_LIMIT): Reduced to 512 bytes. (cbc_decrypt): For
 in-place operation, use overlapping memxor3 and eliminate a memcpy.

Rev: nettle/cbc.c:1.3
---
 cbc.c | 93 ++++++++++++++++++++++++++++-------------------------------
 1 file changed, 44 insertions(+), 49 deletions(-)

diff --git a/cbc.c b/cbc.c
index 6bd9f9ae..8a0a3ba0 100644
--- a/cbc.c
+++ b/cbc.c
@@ -52,28 +52,8 @@ cbc_encrypt(void *ctx, nettle_crypt_func f,
     }
 }
 
-/* Requires that dst != src */
-static void
-cbc_decrypt_internal(void *ctx, nettle_crypt_func f,
-		     unsigned block_size, uint8_t *iv,
-		     unsigned length, uint8_t *dst,
-		     const uint8_t *src)
-{
-  assert(length);
-  assert( !(length % block_size) );
-  assert(src != dst);
-  
-  /* Decrypt in ECB mode */
-  f(ctx, length, dst, src);
-
-  /* XOR the cryptotext, shifted one block */
-  memxor(dst, iv, block_size);
-  memxor(dst + block_size, src, length - block_size);
-  memcpy(iv, src + length - block_size, block_size);
-}
-
 /* Don't allocate any more space than this on the stack */
-#define CBC_BUFFER_LIMIT 4096
+#define CBC_BUFFER_LIMIT 512
 
 void
 cbc_decrypt(void *ctx, nettle_crypt_func f,
@@ -87,19 +67,28 @@ cbc_decrypt(void *ctx, nettle_crypt_func f,
     return;
 
   if (src != dst)
-    cbc_decrypt_internal(ctx, f, block_size, iv,
-			 length, dst, src);
+    {
+      /* Decrypt in ECB mode */
+      f(ctx, length, dst, src);
+
+      /* XOR the cryptotext, shifted one block */
+      memxor(dst, iv, block_size);
+      memxor(dst + block_size, src, length - block_size);
+      memcpy(iv, src + length - block_size, block_size);
+    }
+
   else
     {
-      /* We need a copy of the ciphertext, so we can't ECB decrypt in
-       * place.
-       *
-       * If length is small, we allocate a complete copy of src on the
-       * stack. Otherwise, we allocate a block of size at most
-       * CBC_BUFFER_LIMIT, and process that amount of data at a
-       * time.
-       *
-       * NOTE: We assume that block_size <= CBC_BUFFER_LIMIT. */
+      /* For in-place CBC, we decrypt into a temporary buffer of size
+       * at most CBC_BUFFER_LIMIT, and process that amount of data at
+       * a time. */
+      
+      /* NOTE: We assume that block_size <= CBC_BUFFER_LIMIT, and we
+	 depend on memxor3 working from the end of the area, allowing
+	 certain overlapping operands. */ 
+
+      TMP_DECL(buffer, uint8_t, CBC_BUFFER_LIMIT);
+      TMP_DECL(initial_iv, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE);
 
       unsigned buffer_size;
 
@@ -109,23 +98,29 @@ cbc_decrypt(void *ctx, nettle_crypt_func f,
 	buffer_size
 	  = CBC_BUFFER_LIMIT - (CBC_BUFFER_LIMIT % block_size);
 
-      {
-	TMP_DECL(buffer, uint8_t, CBC_BUFFER_LIMIT);
-	TMP_ALLOC(buffer, buffer_size);
-
-	for ( ; length > buffer_size;
-	      length -= buffer_size, dst += buffer_size, src += buffer_size)
-	  {
-	    memcpy(buffer, src, buffer_size);
-	    cbc_decrypt_internal(ctx, f, block_size, iv,
-				 buffer_size, dst, buffer);
-	  }
-	/* Now, we have at most CBC_BUFFER_LIMIT octets left */
-	memcpy(buffer, src, length);
-	
-	cbc_decrypt_internal(ctx, f, block_size, iv,
-			     length, dst, buffer);
-      }
+      TMP_ALLOC(buffer, buffer_size);
+      TMP_ALLOC(initial_iv, block_size);
+
+      for ( ; length > buffer_size;
+	    length -= buffer_size, src += buffer_size, dst += buffer_size)
+	{
+	  f(ctx, buffer_size, buffer, src);
+	  memcpy(initial_iv, iv, block_size);
+	  memcpy(iv, src + buffer_size - block_size, block_size);
+	  memxor3(dst + block_size, buffer + block_size, src,
+		  buffer_size - block_size);
+	  memxor3(dst, buffer, initial_iv, block_size);
+	}
+
+      f(ctx, length, buffer, src);
+      memcpy(initial_iv, iv, block_size);
+      /* Copies last block */
+      memcpy(iv, src + length - block_size, block_size);
+      /* Writes all but first block, reads all but last block. */
+      memxor3(dst + block_size, buffer + block_size, src,
+	      length - block_size);
+      /* Writes first block. */
+      memxor3(dst, buffer, initial_iv, block_size);
     }
 }
 
-- 
GitLab