Cleaned up the cipher encrypy/decrypt constraints checks.
authorWerner Koch <wk@gnupg.org>
Thu, 10 Dec 2009 16:51:25 +0000 (16:51 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 10 Dec 2009 16:51:25 +0000 (16:51 +0000)
NEWS
cipher/ChangeLog
cipher/cipher.c
random/ChangeLog
random/rndw32.c
tests/ChangeLog
tests/basic.c
tests/benchmark.c

diff --git a/NEWS b/NEWS
index ba2c3ab..f97f0e2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,14 @@ Noteworthy changes in version 1.5.x (unreleased)
 
  * New cipher algorithm mode for AES-WRAP.
 
+ * Fix minor memory leak in DSA key generation.
+
+ * No switch into FIPS mode if /proc/version is not readable.
+
+ * Fix sigill during Padlock detection on old CPUs.
+
+ * Fix a hang on some W2000 machines.
+
  * Interface changes relative to the 1.4.2 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  GCRY_CIPHER_MODE_AESWRAP   NEW.
index 2ddd1d9..26b9e7b 100644 (file)
@@ -1,3 +1,18 @@
+2009-12-10  Werner Koch  <wk@g10code.com>
+
+       * cipher.c (do_ctr_encrypt): Add arg OUTBUFLEN.  Check for
+       suitable value.  Add check for valid inputlen.  Wipe temporary
+       memory.
+       (do_ctr_decrypt): Likewise.
+       (do_cbc_encrypt, do_cbc_decrypt): Add arg OUTBUFLEN.  Check for
+       suitable value.  Move check for valid inputlen to here; change
+       returned error from INV_ARG to INV_LENGTH.
+       (do_ecb_encrypt, do_ecb_decrypt): Ditto.
+       (do_cfb_encrypt, do_cfb_decrypt): Ditto.
+       (do_ofb_encrypt, do_ofb_decrypt): Ditto.
+       (cipher_encrypt, cipher_encrypt): Adjust for above changes.
+       (gcry_cipher_encrypt, gcry_cipher_decrypt): Simplify.
+
 2009-12-09  Werner Koch  <wk@g10code.com>
 
        * cipher.c (gcry_cipher_open): Allow for GCRY_CIPHER_MODE_AESWRAP.
index 355ba68..4808a5f 100644 (file)
@@ -1,6 +1,6 @@
 /* cipher.c  - cipher dispatcher
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- *               2005, 2007, 2008 Free Software Foundation, Inc.
+ *               2005, 2007, 2008, 2009 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -937,48 +937,78 @@ cipher_reset (gcry_cipher_hd_t c)
 }
 
 
-static void
-do_ecb_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
-                unsigned int nblocks )
+\f
+static gcry_err_code_t
+do_ecb_encrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
-  unsigned int n;
+  unsigned int blocksize = c->cipher->blocksize;
+  unsigned int n, nblocks;
   
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+  if ((inbuflen % blocksize))
+    return GPG_ERR_INV_LENGTH;
+
+  nblocks = inbuflen / c->cipher->blocksize;
+
   for (n=0; n < nblocks; n++ )
     {
-      c->cipher->encrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf );
-      inbuf  += c->cipher->blocksize;
-      outbuf += c->cipher->blocksize;
+      c->cipher->encrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf);
+      inbuf  += blocksize;
+      outbuf += blocksize;
     }
+  return 0;
 }
 
-static void
-do_ecb_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
-                unsigned int nblocks )
+static gcry_err_code_t
+do_ecb_decrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
-  unsigned int n;
+  unsigned int blocksize = c->cipher->blocksize;
+  unsigned int n, nblocks;
+
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+  if ((inbuflen % blocksize))
+    return GPG_ERR_INV_LENGTH;
+  nblocks = inbuflen / c->cipher->blocksize;
 
   for (n=0; n < nblocks; n++ ) 
     {
-      c->cipher->decrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf );
-      inbuf  += c->cipher->blocksize;
-      outbuf += c->cipher->blocksize;
+      c->cipher->decrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf );
+      inbuf  += blocksize;
+      outbuf += blocksize;
     }
+
+  return 0;
 }
 
 
-static void
-do_cbc_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, 
-                const unsigned char *inbuf, unsigned int nbytes )
+static gcry_err_code_t
+do_cbc_encrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
   unsigned int n;
   unsigned char *ivp;
   int i;
   size_t blocksize = c->cipher->blocksize;
-  unsigned nblocks = nbytes / blocksize;
+  unsigned nblocks = inbuflen / blocksize;
+
+  if (outbuflen < ((c->flags & GCRY_CIPHER_CBC_MAC)? blocksize : inbuflen))
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  if ((inbuflen % c->cipher->blocksize)
+      && !(inbuflen > c->cipher->blocksize
+           && (c->flags & GCRY_CIPHER_CBC_CTS)))
+    return GPG_ERR_INV_LENGTH;
 
-  if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) 
+  if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) 
     {
-      if ((nbytes % blocksize) == 0)
+      if ((inbuflen % blocksize) == 0)
        nblocks--;
     }
 
@@ -1004,17 +1034,17 @@ do_cbc_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
         }
     }
 
-  if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize)
+  if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize)
     {
       /* We have to be careful here, since outbuf might be equal to
          inbuf.  */
       int restbytes;
       unsigned char b;
 
-      if ((nbytes % blocksize) == 0)
+      if ((inbuflen % blocksize) == 0)
         restbytes = blocksize;
       else
-        restbytes = nbytes % blocksize;
+        restbytes = inbuflen % blocksize;
 
       outbuf -= blocksize;
       for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++)
@@ -1029,23 +1059,34 @@ do_cbc_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
       c->cipher->encrypt (&c->context.c, outbuf, outbuf);
       memcpy (c->u_iv.iv, outbuf, blocksize);
     }
+
+  return 0;
 }
 
 
-static void
-do_cbc_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, 
-                const unsigned char *inbuf, unsigned int nbytes)
+static gcry_err_code_t
+do_cbc_decrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
   unsigned int n;
   unsigned char *ivp;
   int i;
   size_t blocksize = c->cipher->blocksize;
-  unsigned int nblocks = nbytes / blocksize;
+  unsigned int nblocks = inbuflen / blocksize;
+
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  if ((inbuflen % c->cipher->blocksize)
+      && !(inbuflen > c->cipher->blocksize
+           && (c->flags & GCRY_CIPHER_CBC_CTS)))
+    return GPG_ERR_INV_LENGTH;
 
-  if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize)
+  if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize)
     {
       nblocks--;
-      if ((nbytes % blocksize) == 0)
+      if ((inbuflen % blocksize) == 0)
        nblocks--;
       memcpy (c->lastiv, c->u_iv.iv, blocksize);
     }
@@ -1073,14 +1114,14 @@ do_cbc_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
         }
     }
 
-  if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) 
+  if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) 
     {
       int restbytes;
       
-      if ((nbytes % blocksize) == 0)
+      if ((inbuflen % blocksize) == 0)
         restbytes = blocksize;
       else
-        restbytes = nbytes % blocksize;
+        restbytes = inbuflen % blocksize;
       
       memcpy (c->lastiv, c->u_iv.iv, blocksize );         /* Save Cn-2. */
       memcpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */
@@ -1097,32 +1138,38 @@ do_cbc_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
         outbuf[i] ^= *ivp++;
       /* c->lastiv is now really lastlastiv, does this matter? */
     }
+
+  return 0;
 }
 
 
-static void
-do_cfb_encrypt( gcry_cipher_hd_t c, unsigned char *outbuf, 
-                const unsigned char *inbuf, unsigned int nbytes )
+static gcry_err_code_t
+do_cfb_encrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
   unsigned char *ivp;
   size_t blocksize = c->cipher->blocksize;
   size_t blocksize_x_2 = blocksize + blocksize;
   
-  if ( nbytes <= c->unused )
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  if ( inbuflen <= c->unused )
     {
       /* Short enough to be encoded by the remaining XOR mask. */
       /* XOR the input with the IV and store input into IV. */
       for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused;
-           nbytes;
-           nbytes--, c->unused-- )
+           inbuflen;
+           inbuflen--, c->unused-- )
         *outbuf++ = (*ivp++ ^= *inbuf++);
-      return;
+      return 0;
     }
 
   if ( c->unused )
     {
       /* XOR the input with the IV and store input into IV */
-      nbytes -= c->unused;
+      inbuflen -= c->unused;
       for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- )
         *outbuf++ = (*ivp++ ^= *inbuf++);
     }
@@ -1130,17 +1177,17 @@ do_cfb_encrypt( gcry_cipher_hd_t c, unsigned char *outbuf,
   /* Now we can process complete blocks.  We use a loop as long as we
      have at least 2 blocks and use conditions for the rest.  This
      also allows to use a bulk encryption function if available.  */
-  if (nbytes >= blocksize_x_2 && c->bulk.cfb_enc)
+  if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc)
     {
-      unsigned int nblocks = nbytes / blocksize;
+      unsigned int nblocks = inbuflen / blocksize;
       c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); 
       outbuf += nblocks * blocksize;
       inbuf  += nblocks * blocksize;
-      nbytes -= nblocks * blocksize;
+      inbuflen -= nblocks * blocksize;
     }
   else
     {
-      while ( nbytes >= blocksize_x_2 )
+      while ( inbuflen >= blocksize_x_2 )
         {
           int i;
           /* Encrypt the IV. */
@@ -1148,11 +1195,11 @@ do_cfb_encrypt( gcry_cipher_hd_t c, unsigned char *outbuf,
           /* XOR the input with the IV and store input into IV.  */
           for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
             *outbuf++ = (*ivp++ ^= *inbuf++);
-          nbytes -= blocksize;
+          inbuflen -= blocksize;
         }
     }
 
-  if ( nbytes >= blocksize )
+  if ( inbuflen >= blocksize )
     {
       int i;
       /* Save the current IV and then encrypt the IV. */
@@ -1161,25 +1208,27 @@ do_cfb_encrypt( gcry_cipher_hd_t c, unsigned char *outbuf,
       /* XOR the input with the IV and store input into IV */
       for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
         *outbuf++ = (*ivp++ ^= *inbuf++);
-      nbytes -= blocksize;
+      inbuflen -= blocksize;
     }
-  if ( nbytes ) 
+  if ( inbuflen ) 
     {
       /* Save the current IV and then encrypt the IV. */
       memcpy( c->lastiv, c->u_iv.iv, blocksize );
       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
       c->unused = blocksize;
       /* Apply the XOR. */
-      c->unused -= nbytes;
-      for(ivp=c->u_iv.iv; nbytes; nbytes-- )
+      c->unused -= inbuflen;
+      for(ivp=c->u_iv.iv; inbuflen; inbuflen-- )
         *outbuf++ = (*ivp++ ^= *inbuf++);
     }
+  return 0;
 }
 
 
-static void
-do_cfb_decrypt( gcry_cipher_hd_t c, unsigned char *outbuf, 
-                const unsigned char *inbuf, unsigned int nbytes )
+static gcry_err_code_t
+do_cfb_decrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
   unsigned char *ivp;
   unsigned long temp;
@@ -1187,25 +1236,28 @@ do_cfb_decrypt( gcry_cipher_hd_t c, unsigned char *outbuf,
   size_t blocksize = c->cipher->blocksize;
   size_t blocksize_x_2 = blocksize + blocksize;
   
-  if (nbytes <= c->unused)
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  if (inbuflen <= c->unused)
     {
       /* Short enough to be encoded by the remaining XOR mask. */
       /* XOR the input with the IV and store input into IV. */
       for (ivp=c->u_iv.iv+blocksize - c->unused;
-           nbytes
-           nbytes--, c->unused--)
+           inbuflen
+           inbuflen--, c->unused--)
         {
           temp = *inbuf++;
           *outbuf++ = *ivp ^ temp;
           *ivp++ = temp;
         }
-      return;
+      return 0;
     }
   
   if (c->unused)
     {
       /* XOR the input with the IV and store input into IV. */
-      nbytes -= c->unused;
+      inbuflen -= c->unused;
       for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- )
         {
           temp = *inbuf++;
@@ -1217,17 +1269,17 @@ do_cfb_decrypt( gcry_cipher_hd_t c, unsigned char *outbuf,
   /* Now we can process complete blocks.  We use a loop as long as we
      have at least 2 blocks and use conditions for the rest.  This
      also allows to use a bulk encryption function if available.  */
-  if (nbytes >= blocksize_x_2 && c->bulk.cfb_dec)
+  if (inbuflen >= blocksize_x_2 && c->bulk.cfb_dec)
     {
-      unsigned int nblocks = nbytes / blocksize;
+      unsigned int nblocks = inbuflen / blocksize;
       c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); 
       outbuf += nblocks * blocksize;
       inbuf  += nblocks * blocksize;
-      nbytes -= nblocks * blocksize;
+      inbuflen -= nblocks * blocksize;
     }
   else
     {
-      while (nbytes >= blocksize_x_2 )
+      while (inbuflen >= blocksize_x_2 )
         {
           /* Encrypt the IV. */
           c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
@@ -1238,11 +1290,11 @@ do_cfb_decrypt( gcry_cipher_hd_t c, unsigned char *outbuf,
               *outbuf++ = *ivp ^ temp;
               *ivp++ = temp;
             }
-          nbytes -= blocksize;
+          inbuflen -= blocksize;
         }
     }
 
-  if (nbytes >= blocksize )
+  if (inbuflen >= blocksize )
     {
       /* Save the current IV and then encrypt the IV. */
       memcpy ( c->lastiv, c->u_iv.iv, blocksize);
@@ -1254,54 +1306,59 @@ do_cfb_decrypt( gcry_cipher_hd_t c, unsigned char *outbuf,
           *outbuf++ = *ivp ^ temp;
           *ivp++ = temp;
         }
-      nbytes -= blocksize;
+      inbuflen -= blocksize;
     }
 
-  if (nbytes)
+  if (inbuflen)
     { 
       /* Save the current IV and then encrypt the IV. */
       memcpy ( c->lastiv, c->u_iv.iv, blocksize );
       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
       c->unused = blocksize;
       /* Apply the XOR. */
-      c->unused -= nbytes;
-      for (ivp=c->u_iv.iv; nbytes; nbytes-- )
+      c->unused -= inbuflen;
+      for (ivp=c->u_iv.iv; inbuflen; inbuflen-- )
         {
           temp = *inbuf++;
           *outbuf++ = *ivp ^ temp;
           *ivp++ = temp;
         }
     }
+  return 0;
 }
 
 
-static void
-do_ofb_encrypt( gcry_cipher_hd_t c,
-                byte *outbuf, const byte *inbuf, unsigned nbytes )
+static gcry_err_code_t
+do_ofb_encrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
-  byte *ivp;
+  unsigned char *ivp;
   size_t blocksize = c->cipher->blocksize;
 
-  if ( nbytes <= c->unused )
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  if ( inbuflen <= c->unused )
     {
       /* Short enough to be encoded by the remaining XOR mask. */
       /* XOR the input with the IV */
       for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused;
-           nbytes;
-           nbytes--, c->unused-- )
+           inbuflen;
+           inbuflen--, c->unused-- )
         *outbuf++ = (*ivp++ ^ *inbuf++);
-      return;
+      return 0;
     }
 
   if( c->unused )
     {
-      nbytes -= c->unused;
+      inbuflen -= c->unused;
       for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- )
         *outbuf++ = (*ivp++ ^ *inbuf++);
     }
 
   /* Now we can process complete blocks. */
-  while ( nbytes >= blocksize )
+  while ( inbuflen >= blocksize )
     {
       int i;
       /* Encrypt the IV (and save the current one). */
@@ -1310,43 +1367,48 @@ do_ofb_encrypt( gcry_cipher_hd_t c,
       
       for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
         *outbuf++ = (*ivp++ ^ *inbuf++);
-      nbytes -= blocksize;
+      inbuflen -= blocksize;
     }
-  if ( nbytes )
+  if ( inbuflen )
     { /* process the remaining bytes */
       memcpy( c->lastiv, c->u_iv.iv, blocksize );
       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
       c->unused = blocksize;
-      c->unused -= nbytes;
-      for(ivp=c->u_iv.iv; nbytes; nbytes-- )
+      c->unused -= inbuflen;
+      for(ivp=c->u_iv.iv; inbuflen; inbuflen-- )
         *outbuf++ = (*ivp++ ^ *inbuf++);
     }
+  return 0;
 }
 
-static void
-do_ofb_decrypt( gcry_cipher_hd_t c,
-                byte *outbuf, const byte *inbuf, unsigned int nbytes )
+static gcry_err_code_t
+do_ofb_decrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
-  byte *ivp;
+  unsigned char *ivp;
   size_t blocksize = c->cipher->blocksize;
   
-  if( nbytes <= c->unused )
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  if( inbuflen <= c->unused )
     {
       /* Short enough to be encoded by the remaining XOR mask. */
-      for (ivp=c->u_iv.iv+blocksize - c->unused; nbytes; nbytes--,c->unused--)
+      for (ivp=c->u_iv.iv+blocksize - c->unused; inbuflen; inbuflen--,c->unused--)
         *outbuf++ = *ivp++ ^ *inbuf++;
-      return;
+      return 0;
     }
 
   if ( c->unused )
     {
-      nbytes -= c->unused;
+      inbuflen -= c->unused;
       for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- )
         *outbuf++ = *ivp++ ^ *inbuf++;
     }
 
   /* Now we can process complete blocks. */
-  while ( nbytes >= blocksize )
+  while ( inbuflen >= blocksize )
     {
       int i;
       /* Encrypt the IV (and save the current one). */
@@ -1354,36 +1416,45 @@ do_ofb_decrypt( gcry_cipher_hd_t c,
       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
       for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
         *outbuf++ = *ivp++ ^ *inbuf++;
-      nbytes -= blocksize;
+      inbuflen -= blocksize;
     }
-  if ( nbytes ) 
+  if ( inbuflen ) 
     { /* Process the remaining bytes. */
       /* Encrypt the IV (and save the current one). */
       memcpy( c->lastiv, c->u_iv.iv, blocksize );
       c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
       c->unused = blocksize;
-      c->unused -= nbytes;
-      for (ivp=c->u_iv.iv; nbytes; nbytes-- )
+      c->unused -= inbuflen;
+      for (ivp=c->u_iv.iv; inbuflen; inbuflen-- )
         *outbuf++ = *ivp++ ^ *inbuf++;
     }
+  return 0;
 }
 
 
-static void
-do_ctr_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
-                unsigned int nbytes )
+static gcry_err_code_t
+do_ctr_encrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
   unsigned int n;
-  byte tmp[MAX_BLOCKSIZE];
+  unsigned char tmp[MAX_BLOCKSIZE];
   int i;
+  unsigned int blocksize = c->cipher->blocksize;
 
-  for(n=0; n < nbytes; n++)
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  if ((inbuflen % blocksize))
+    return GPG_ERR_INV_LENGTH;
+
+  for (n=0; n < inbuflen; n++)
     {
-      if ((n % c->cipher->blocksize) == 0)
+      if ((n % blocksize) == 0)
        {
          c->cipher->encrypt (&c->context.c, tmp, c->ctr);
 
-         for (i = c->cipher->blocksize; i > 0; i--)
+         for (i = blocksize; i > 0; i--)
            {
              c->ctr[i-1]++;
              if (c->ctr[i-1] != 0)
@@ -1391,16 +1462,20 @@ do_ctr_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
            }
        }
 
-      /* XOR input with encrypted counter and store in output. */
-      outbuf[n] = inbuf[n] ^ tmp[n % c->cipher->blocksize];
+      /* XOR input with encrypted counter and store in output.  */
+      outbuf[n] = inbuf[n] ^ tmp[n % blocksize];
     }
+
+  wipememory (tmp, sizeof tmp);
+  return 0;
 }
 
-static void
-do_ctr_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
-                unsigned int nbytes )
+static gcry_err_code_t
+do_ctr_decrypt (gcry_cipher_hd_t c,
+                unsigned char *outbuf, unsigned int outbuflen,
+                const unsigned char *inbuf, unsigned int inbuflen)
 {
-  do_ctr_encrypt (c, outbuf, inbuf, nbytes);
+  return do_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
 }
 
 
@@ -1578,45 +1653,38 @@ static gcry_err_code_t
 cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen,
                const byte *inbuf, unsigned int inbuflen)
 {
-  gcry_err_code_t rc = 0;
+  gcry_err_code_t rc;
 
   switch (c->mode)
     {
     case GCRY_CIPHER_MODE_ECB:
-      if (!(inbuflen % c->cipher->blocksize))
-        do_ecb_encrypt(c, outbuf, inbuf, inbuflen/c->cipher->blocksize );
-      else 
-        rc = GPG_ERR_INV_ARG;
+      rc = do_ecb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_CBC:
-      if (!(inbuflen % c->cipher->blocksize)
-          || (inbuflen > c->cipher->blocksize
-              && (c->flags & GCRY_CIPHER_CBC_CTS)))
-        do_cbc_encrypt(c, outbuf, inbuf, inbuflen );
-      else 
-        rc = GPG_ERR_INV_ARG;
+      rc = do_cbc_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
       
     case GCRY_CIPHER_MODE_CFB:
-      do_cfb_encrypt(c, outbuf, inbuf, inbuflen );
+      rc = do_cfb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_OFB:
-      do_ofb_encrypt(c, outbuf, inbuf, inbuflen );
+      rc = do_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_CTR:
-      do_ctr_encrypt(c, outbuf, inbuf, inbuflen );
+      rc = do_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_AESWRAP:
-      rc = do_aeswrap_encrypt (c, outbuf, outbuflen, inbuf, inbuflen );
+      rc = do_aeswrap_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_STREAM:
       c->cipher->stencrypt (&c->context.c,
-                            outbuf, (byte*)/*arggg*/inbuf, inbuflen );
+                            outbuf, (byte*)/*arggg*/inbuf, inbuflen);
+      rc = 0;
       break;
 
     case GCRY_CIPHER_MODE_NONE:
@@ -1627,8 +1695,9 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen,
         }
       else
         {
-          if ( inbuf != outbuf )
+          if (inbuf != outbuf)
             memmove (outbuf, inbuf, inbuflen);
+          rc = 0;
         }
       break;
       
@@ -1652,20 +1721,8 @@ gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
 {
   gcry_err_code_t err;
 
-  if (!in)
-    {
-      /* Caller requested in-place encryption.  */
-      err = cipher_encrypt (h, out, outsize, out, outsize);
-    }
-  else if (outsize < ((h->flags & GCRY_CIPHER_CBC_MAC) ?
-                      h->cipher->blocksize : inlen))
-    err = GPG_ERR_BUFFER_TOO_SHORT;
-  else if ((h->mode == GCRY_CIPHER_MODE_ECB
-           || (h->mode == GCRY_CIPHER_MODE_CBC
-               && (! ((h->flags & GCRY_CIPHER_CBC_CTS)
-                      && (inlen > h->cipher->blocksize)))))
-          && (inlen % h->cipher->blocksize))
-    err = GPG_ERR_INV_ARG;
+  if (!in)  /* Caller requested in-place encryption.  */
+    err = cipher_encrypt (h, out, outsize, out, outsize);
   else
     err = cipher_encrypt (h, out, outsize, in, inlen);
 
@@ -1682,51 +1739,44 @@ gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
 /****************
  * Decrypt INBUF to OUTBUF with the mode selected at open.
  * inbuf and outbuf may overlap or be the same.
- * Depending on the mode some some contraints apply to NBYTES.
+ * Depending on the mode some some contraints apply to INBUFLEN.
  */
 static gcry_err_code_t
 cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen,
                 const byte *inbuf, unsigned int inbuflen)
 {
-  gcry_err_code_t rc = 0;
+  gcry_err_code_t rc;
 
   switch (c->mode)
     {
     case GCRY_CIPHER_MODE_ECB:
-      if (!(inbuflen % c->cipher->blocksize))
-        do_ecb_decrypt (c, outbuf, inbuf, inbuflen/c->cipher->blocksize );
-      else 
-        rc = GPG_ERR_INV_ARG;
+      rc = do_ecb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_CBC:
-      if (!(inbuflen % c->cipher->blocksize)
-          || (inbuflen > c->cipher->blocksize
-              && (c->flags & GCRY_CIPHER_CBC_CTS)))
-        do_cbc_decrypt (c, outbuf, inbuf, inbuflen );
-      else 
-        rc = GPG_ERR_INV_ARG;
+      rc = do_cbc_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_CFB:
-      do_cfb_decrypt (c, outbuf, inbuf, inbuflen );
-
+      rc = do_cfb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
+
     case GCRY_CIPHER_MODE_OFB:
-      do_ofb_decrypt (c, outbuf, inbuf, inbuflen );
+      rc = do_ofb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_CTR:
-      do_ctr_decrypt (c, outbuf, inbuf, inbuflen );
+      rc = do_ctr_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_AESWRAP:
-      rc = do_aeswrap_decrypt (c, outbuf, outbuflen, inbuf, inbuflen );
+      rc = do_aeswrap_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
       break;
 
     case GCRY_CIPHER_MODE_STREAM:
       c->cipher->stdecrypt (&c->context.c,
-                            outbuf, (byte*)/*arggg*/inbuf, inbuflen );
+                            outbuf, (byte*)/*arggg*/inbuf, inbuflen);
+      rc = 0;
       break;
 
     case GCRY_CIPHER_MODE_NONE:
@@ -1739,6 +1789,7 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen,
         {
           if (inbuf != outbuf)
             memmove (outbuf, inbuf, inbuflen);
+          rc = 0;
         }
       break;
       
@@ -1756,26 +1807,10 @@ gcry_error_t
 gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
                     const void *in, size_t inlen)
 {
-  gcry_err_code_t err = 0;
+  gcry_err_code_t err;
 
-  if (!in)
-    {
-      /* Caller requested in-place encryption. */
-      err = cipher_decrypt (h, out, outsize, out, outsize);
-    }
-  else if (outsize < inlen && h->mode != GCRY_CIPHER_MODE_AESWRAP)
-    {
-      /* Note that do_aeswrap_decrypt does its own length checking.
-         Fixme: we should move all buffer length checkings to teh
-         actual decryption functions.  */
-      err = GPG_ERR_BUFFER_TOO_SHORT;
-    }
-  else if (((h->mode == GCRY_CIPHER_MODE_ECB)
-           || ((h->mode == GCRY_CIPHER_MODE_CBC)
-               && (! ((h->flags & GCRY_CIPHER_CBC_CTS)
-                      && (inlen > h->cipher->blocksize)))))
-          && (inlen % h->cipher->blocksize) != 0)
-    err = GPG_ERR_INV_ARG;
+  if (!in) /* Caller requested in-place encryption. */
+    err = cipher_decrypt (h, out, outsize, out, outsize);
   else
     err = cipher_decrypt (h, out, outsize, in, inlen);
 
index 1c29a7a..31208b6 100644 (file)
@@ -1,3 +1,10 @@
+2009-12-10  Werner Koch  <wk@g10code.com>
+
+       * rndw32.c (system_is_w2000): New.
+       (_gcry_rndw32_gather_random): Set it.
+       (slow_gatherer): Ignore SystemObjectInformation on W2000.  Fixes
+       bug#1167.
+
 2009-07-09  Werner Koch  <wk@g10code.com>
 
        * rndlinux.c (_gcry_rndlinux_gather_random): Print real values for
index c514019..d250c06 100644 (file)
@@ -245,6 +245,8 @@ static HCRYPTPROV hRNGProv;      /* Handle to Intel RNG CSP. */
 
 static int debug_me;  /* Debug flag.  */
 
+static int system_is_w2000;     /* True if running on W2000.  */
+
 
 
 \f
@@ -643,6 +645,12 @@ slow_gatherer ( void (*add)(const void*, size_t, enum random_origins),
     {
       switch (dwType)
         {
+          /* ID 17 = SystemObjectInformation hangs on some win2k systems.  */
+        case 17:
+          if (system_is_w2000)
+            continue;
+          break;
+
           /* Some information types are write-only (the IDs are shared with
              a set-information call), we skip these.  */
         case 26: case 27: case 38: case 46: case 47: case 48: case 52:
@@ -768,6 +776,7 @@ _gcry_rndw32_gather_random (void (*add)(const void*, size_t,
       GetVersionEx( &osvi );
       if ( osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
         log_fatal ("can only run on a Windows NT platform\n" );
+      system_is_w2000 = (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0);
       init_system_rng ();
       is_initialized = 1;
     }
index c8332a6..e4776cf 100644 (file)
@@ -1,3 +1,9 @@
+2009-12-10  Werner Koch  <wk@g10code.com>
+
+       * basic.c (check_ctr_cipher): Add some return code checks.
+
+       * benchmark.c (cipher_bench): Merge Stream with ECB column.
+
 2009-12-09  Werner Koch  <wk@g10code.com>
 
        * aeswrap.c: New.
index 53305dd..2cd6d9f 100644 (file)
@@ -1,5 +1,6 @@
 /* basic.c  -  basic regression tests
- * Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2005, 2008,
+ *               2009 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -459,7 +460,7 @@ check_ctr_cipher (void)
        }
 
       if (verbose)
-       fprintf (stderr, "  checking CTR mode for for %s [%i]\n", 
+       fprintf (stderr, "  checking CTR mode for %s [%i]\n", 
                 gcry_cipher_algo_name (tv[i].algo),
                 tv[i].algo);
       for (j = 0; tv[i].data[j].inlen; j++)
@@ -493,8 +494,82 @@ check_ctr_cipher (void)
 
          if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
            fail ("aes-ctr, decrypt mismatch entry %d:%d\n", i, j);
-       }
 
+        }
+          
+      /* Now check that we get valid return codes back for good and
+         bad inputs.  */
+      err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+                                 "1234567890123456", 16);
+      if (err)
+        fail ("aes-ctr, encryption failed for valid input");
+      
+      err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+                                 "1234567890123456", 15);
+      if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
+        fail ("aes-ctr, too short input returned wrong error: %s\n",
+              gpg_strerror (err));
+      
+      err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+                                 "12345678901234567", 17);
+      if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
+        fail ("aes-ctr, too long input returned wrong error: %s\n",
+              gpg_strerror (err));
+      
+      err = gcry_cipher_encrypt (hde, out, 15,
+                                 "1234567890123456", 16);
+      if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
+        fail ("aes-ctr, too short output buffer returned wrong error: %s\n",
+              gpg_strerror (err));
+      
+      err = gcry_cipher_encrypt (hde, out, 0,
+                                 "1234567890123456", 16);
+      if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
+        fail ("aes-ctr, 0 length output buffer returned wrong error: %s\n",
+              gpg_strerror (err));
+      
+      err = gcry_cipher_encrypt (hde, out, 16,
+                                 "1234567890123456", 16);
+      if (err)
+        fail ("aes-ctr, correct length output buffer returned error: %s\n",
+              gpg_strerror (err));
+
+      /* Again, now for decryption.  */
+      err = gcry_cipher_decrypt (hde, out, MAX_DATA_LEN,
+                                 "1234567890123456", 16);
+      if (err)
+        fail ("aes-ctr, decryption failed for valid input");
+      
+      err = gcry_cipher_decrypt (hde, out, MAX_DATA_LEN,
+                                 "1234567890123456", 15);
+      if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
+        fail ("aes-ctr, too short input returned wrong error: %s\n",
+              gpg_strerror (err));
+      
+      err = gcry_cipher_decrypt (hde, out, MAX_DATA_LEN,
+                                 "12345678901234567", 17);
+      if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
+        fail ("aes-ctr, too long input returned wrong error: %s\n",
+              gpg_strerror (err));
+      
+      err = gcry_cipher_decrypt (hde, out, 15,
+                                 "1234567890123456", 16);
+      if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
+        fail ("aes-ctr, too short output buffer returned wrong error: %s\n",
+              gpg_strerror (err));
+      
+      err = gcry_cipher_decrypt (hde, out, 0,
+                                 "1234567890123456", 16);
+      if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
+        fail ("aes-ctr, 0 length output buffer returned wrong error: %s\n",
+              gpg_strerror (err));
+      
+      err = gcry_cipher_decrypt (hde, out, 16,
+                                 "1234567890123456", 16);
+      if (err)
+        fail ("aes-ctr, correct length output buffer returned error: %s\n",
+              gpg_strerror (err));
+      
       gcry_cipher_close (hde);
       gcry_cipher_close (hdd);
     }
index 83ddf37..214858d 100644 (file)
@@ -460,12 +460,12 @@ cipher_bench ( const char *algoname )
   size_t allocated_buflen, buflen;
   int repetitions;
   static struct { int mode; const char *name; int blocked; } modes[] = {
-    { GCRY_CIPHER_MODE_ECB, "      ECB", 1 },
+    { GCRY_CIPHER_MODE_ECB, "   ECB/Stream", 1 },
     { GCRY_CIPHER_MODE_CBC, "      CBC", 1 },
     { GCRY_CIPHER_MODE_CFB, "      CFB", 0 },
     { GCRY_CIPHER_MODE_OFB, "      OFB", 0 },
     { GCRY_CIPHER_MODE_CTR, "      CTR", 0 },
-    { GCRY_CIPHER_MODE_STREAM, "    STREAM", 0 },
+    { GCRY_CIPHER_MODE_STREAM, "", 0 },
     {0}
   };
   int modeidx;
@@ -501,11 +501,13 @@ cipher_bench ( const char *algoname )
         printf ("Running each test %d times.\n", cipher_repetitions);
       printf ("%-12s", "");
       for (modeidx=0; modes[modeidx].mode; modeidx++)
-        printf (" %-15s", modes[modeidx].name );
+        if (*modes[modeidx].name)
+          printf (" %-15s", modes[modeidx].name );
       putchar ('\n');
       printf ("%-12s", "");
       for (modeidx=0; modes[modeidx].mode; modeidx++)
-        printf (" ---------------" );
+        if (*modes[modeidx].name)
+          printf (" ---------------" );
       putchar ('\n');
       header_printed = 1;
     }
@@ -548,10 +550,7 @@ cipher_bench ( const char *algoname )
     {
       if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM)
           | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
-        {
-          printf ("                " );
-          continue;
-        }
+        continue;
 
       for (i=0; i < sizeof buf; i++)
         buf[i] = i;