--- ./cipher.c	2004-02-25 18:27:35.000000000 +0000
+++ /home/agl/src/libgcrypt-1.2.1.agl/cipher/cipher.c	2005-06-14 17:35:11.887795706 +0100
@@ -112,6 +112,10 @@
   unsigned char lastiv[MAX_BLOCKSIZE];
   int unused;  /* in IV */
   unsigned char ctr[MAX_BLOCKSIZE];     /* For Counter (CTR) mode. */
+  unsigned char ctr_buffer[MAX_BLOCKSIZE];  /* Used to store the remains of
+                                               a block in the case of a CTR
+                                               encrypt which isn't block
+                                               aligned */
   PROPERLY_ALIGNED_TYPE context;
 };
 
@@ -632,6 +636,8 @@
 	  h->module = module;
 	  h->mode = mode;
 	  h->flags = flags;
+	  h->unused = 0;  /* never let the unused value point into space
+	                     since it's used as an index in some places */
 	}
     }
 
@@ -718,6 +724,7 @@
 	  ivlen = c->cipher->blocksize;
 	memcpy( c->iv, iv, ivlen );
     }
+
     c->unused = 0;
 }
 
@@ -979,25 +986,37 @@
                 unsigned int nbytes )
 {
   unsigned int n;
-  byte tmp[MAX_BLOCKSIZE];
   int i;
 
+  /* CTR mode involves encrypting by XORing with the inf sequence:
+   *   E_k(ctr) | E_k(ctr+1) | ...
+   * where ctr is the IV for this mode. A block of XOR data
+   * (the result of E_k(ctr)) is kept in c->ctr_buffer and the
+   * amount of that buffer which has already been used is kept in
+   * c->unused (which is a little confusing - think of unused as
+   * begin an index at which the unused XOR data is)*/
+
   for(n=0; n < nbytes; n++)
     {
-      if ((n % c->cipher->blocksize) == 0)
-	{
-	  c->cipher->encrypt (&c->context.c, tmp, c->ctr);
+      if (c->unused == 0 || c->unused == c->cipher->blocksize)
+        {
+	  // 0 is not a valid value for unused since,
+	  // if a whole block was left over it wouldn't have been
+	  // generated in the first place. Thus it means `need a
+	  // new buffer'
+	  c->cipher->encrypt (&c->context.c, c->ctr_buffer, c->ctr);
 
+	  // increment the value of ctr
 	  for (i = c->cipher->blocksize; i > 0; i--)
 	    {
 	      c->ctr[i-1]++;
 	      if (c->ctr[i-1] != 0)
 		break;
 	    }
-	}
 
-      /* XOR input with encrypted counter and store in output. */
-      outbuf[n] = inbuf[n] ^ tmp[n % c->cipher->blocksize];
+	  c->unused = 0;
+	}
+      outbuf[n] = inbuf[n] ^ c->ctr_buffer[c->unused++];
     }
 }
 
