md5, sha1, sha256, sha512: use openssl routines if available
[gnulib.git] / lib / sha512.c
index 261a7bb..8429bb9 100644 (file)
@@ -1,7 +1,7 @@
 /* sha512.c - Functions to compute SHA512 and SHA384 message digest of files or
    memory blocks according to the NIST specification FIPS-180-2.
 
-   Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include <config.h>
 
+#if HAVE_OPENSSL_SHA512
+# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
+#endif
 #include "sha512.h"
 
-#include <stddef.h>
+#include <stdalign.h>
+#include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 #if USE_UNLOCKED_IO
 # define SWAP(n) (n)
 #else
 # define SWAP(n) \
-    u64or (u64or (u64or (u64shl (n, 56),                               \
-                        u64shl (u64and (n, u64lo (0x0000ff00)), 40)),  \
-                 u64or (u64shl (u64and (n, u64lo (0x00ff0000)), 24),   \
-                        u64shl (u64and (n, u64lo (0xff000000)),  8))), \
-          u64or (u64or (u64and (u64shr (n,  8), u64lo (0xff000000)),   \
-                        u64and (u64shr (n, 24), u64lo (0x00ff0000))),  \
-                 u64or (u64and (u64shr (n, 40), u64lo (0x0000ff00)),   \
-                        u64shr (n, 56))))
+    u64or (u64or (u64or (u64shl (n, 56),                                \
+                         u64shl (u64and (n, u64lo (0x0000ff00)), 40)),  \
+                  u64or (u64shl (u64and (n, u64lo (0x00ff0000)), 24),   \
+                         u64shl (u64and (n, u64lo (0xff000000)),  8))), \
+           u64or (u64or (u64and (u64shr (n,  8), u64lo (0xff000000)),   \
+                         u64and (u64shr (n, 24), u64lo (0x00ff0000))),  \
+                  u64or (u64and (u64shr (n, 40), u64lo (0x0000ff00)),   \
+                         u64shr (n, 56))))
 #endif
 
-#define BLOCKSIZE 4096
+#define BLOCKSIZE 32768
 #if BLOCKSIZE % 128 != 0
 # error "invalid BLOCKSIZE"
 #endif
 
+#if ! HAVE_OPENSSL_SHA512
 /* This array contains the bytes used to pad the buffer to the next
    128-byte boundary.  */
 static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ...  */ };
@@ -57,7 +63,7 @@ static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ...  */ };
 
 /*
   Takes a pointer to a 512 bit block of data (eight 64 bit ints) and
-  intializes it to the start constants of the SHA512 algorithm.  This
+  initializes it to the start constants of the SHA512 algorithm.  This
   must be called before using hash in the call to sha512_hash
 */
 void
@@ -95,7 +101,7 @@ sha384_init_ctx (struct sha512_ctx *ctx)
 /* Copy the value from V into the memory location pointed to by *CP,
    If your architecture allows unaligned access, this is equivalent to
    * (__typeof__ (v) *) cp = v  */
-static inline void
+static void
 set_uint64 (char *cp, u64 v)
 {
   memcpy (cp, &v, sizeof v);
@@ -145,10 +151,10 @@ sha512_conclude_ctx (struct sha512_ctx *ctx)
      Use set_uint64 rather than a simple assignment, to avoid risk of
      unaligned access.  */
   set_uint64 ((char *) &ctx->buffer[size - 2],
-             SWAP (u64or (u64shl (ctx->total[1], 3),
-                          u64shr (ctx->total[0], 61))));
+              SWAP (u64or (u64shl (ctx->total[1], 3),
+                           u64shr (ctx->total[0], 61))));
   set_uint64 ((char *) &ctx->buffer[size - 1],
-             SWAP (u64shl (ctx->total[0], 3)));
+              SWAP (u64shl (ctx->total[0], 3)));
 
   memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes);
 
@@ -169,6 +175,7 @@ sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf)
   sha512_conclude_ctx (ctx);
   return sha384_read_ctx (ctx, resbuf);
 }
+#endif
 
 /* Compute SHA512 message digest for bytes read from STREAM.  The
    resulting message digest number will be written into the 64 bytes
@@ -177,9 +184,12 @@ int
 sha512_stream (FILE *stream, void *resblock)
 {
   struct sha512_ctx ctx;
-  char buffer[BLOCKSIZE + 72];
   size_t sum;
 
+  char *buffer = malloc (BLOCKSIZE + 72);
+  if (!buffer)
+    return 1;
+
   /* Initialize the computation context.  */
   sha512_init_ctx (&ctx);
 
@@ -187,40 +197,43 @@ sha512_stream (FILE *stream, void *resblock)
   while (1)
     {
       /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-        computation function processes the whole buffer so that with the
-        next round of the loop another block can be read.  */
+         computation function processes the whole buffer so that with the
+         next round of the loop another block can be read.  */
       size_t n;
       sum = 0;
 
       /* Read block.  Take care for partial reads.  */
       while (1)
-       {
-         n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-         sum += n;
-
-         if (sum == BLOCKSIZE)
-           break;
-
-         if (n == 0)
-           {
-             /* Check for the error flag IFF N == 0, so that we don't
-                exit the loop after a partial read due to e.g., EAGAIN
-                or EWOULDBLOCK.  */
-             if (ferror (stream))
-               return 1;
-             goto process_partial_block;
-           }
-
-         /* We've read at least one byte, so ignore errors.  But always
-            check for EOF, since feof may be true even though N > 0.
-            Otherwise, we could end up calling fread after EOF.  */
-         if (feof (stream))
-           goto process_partial_block;
-       }
+        {
+          n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+          sum += n;
+
+          if (sum == BLOCKSIZE)
+            break;
+
+          if (n == 0)
+            {
+              /* Check for the error flag IFF N == 0, so that we don't
+                 exit the loop after a partial read due to e.g., EAGAIN
+                 or EWOULDBLOCK.  */
+              if (ferror (stream))
+                {
+                  free (buffer);
+                  return 1;
+                }
+              goto process_partial_block;
+            }
+
+          /* We've read at least one byte, so ignore errors.  But always
+             check for EOF, since feof may be true even though N > 0.
+             Otherwise, we could end up calling fread after EOF.  */
+          if (feof (stream))
+            goto process_partial_block;
+        }
 
       /* Process buffer with BLOCKSIZE bytes.  Note that
-                       BLOCKSIZE % 128 == 0
+                        BLOCKSIZE % 128 == 0
        */
       sha512_process_block (buffer, BLOCKSIZE, &ctx);
     }
@@ -233,6 +246,7 @@ sha512_stream (FILE *stream, void *resblock)
 
   /* Construct result in desired memory.  */
   sha512_finish_ctx (&ctx, resblock);
+  free (buffer);
   return 0;
 }
 
@@ -241,9 +255,12 @@ int
 sha384_stream (FILE *stream, void *resblock)
 {
   struct sha512_ctx ctx;
-  char buffer[BLOCKSIZE + 72];
   size_t sum;
 
+  char *buffer = malloc (BLOCKSIZE + 72);
+  if (!buffer)
+    return 1;
+
   /* Initialize the computation context.  */
   sha384_init_ctx (&ctx);
 
@@ -251,40 +268,43 @@ sha384_stream (FILE *stream, void *resblock)
   while (1)
     {
       /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-        computation function processes the whole buffer so that with the
-        next round of the loop another block can be read.  */
+         computation function processes the whole buffer so that with the
+         next round of the loop another block can be read.  */
       size_t n;
       sum = 0;
 
       /* Read block.  Take care for partial reads.  */
       while (1)
-       {
-         n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-         sum += n;
-
-         if (sum == BLOCKSIZE)
-           break;
-
-         if (n == 0)
-           {
-             /* Check for the error flag IFF N == 0, so that we don't
-                exit the loop after a partial read due to e.g., EAGAIN
-                or EWOULDBLOCK.  */
-             if (ferror (stream))
-               return 1;
-             goto process_partial_block;
-           }
-
-         /* We've read at least one byte, so ignore errors.  But always
-            check for EOF, since feof may be true even though N > 0.
-            Otherwise, we could end up calling fread after EOF.  */
-         if (feof (stream))
-           goto process_partial_block;
-       }
+        {
+          n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+          sum += n;
+
+          if (sum == BLOCKSIZE)
+            break;
+
+          if (n == 0)
+            {
+              /* Check for the error flag IFF N == 0, so that we don't
+                 exit the loop after a partial read due to e.g., EAGAIN
+                 or EWOULDBLOCK.  */
+              if (ferror (stream))
+                {
+                  free (buffer);
+                  return 1;
+                }
+              goto process_partial_block;
+            }
+
+          /* We've read at least one byte, so ignore errors.  But always
+             check for EOF, since feof may be true even though N > 0.
+             Otherwise, we could end up calling fread after EOF.  */
+          if (feof (stream))
+            goto process_partial_block;
+        }
 
       /* Process buffer with BLOCKSIZE bytes.  Note that
-                       BLOCKSIZE % 128 == 0
+                        BLOCKSIZE % 128 == 0
        */
       sha512_process_block (buffer, BLOCKSIZE, &ctx);
     }
@@ -297,9 +317,11 @@ sha384_stream (FILE *stream, void *resblock)
 
   /* Construct result in desired memory.  */
   sha384_finish_ctx (&ctx, resblock);
+  free (buffer);
   return 0;
 }
 
+#if ! HAVE_OPENSSL_SHA512
 /* Compute SHA512 message digest for LEN bytes beginning at BUFFER.  The
    result is always in little endian byte order, so that a byte-wise
    output yields to the wanted ASCII representation of the message
@@ -348,15 +370,15 @@ sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx)
       ctx->buflen += add;
 
       if (ctx->buflen > 128)
-       {
-         sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx);
+        {
+          sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx);
 
-         ctx->buflen &= 127;
-         /* The regions in the following copy operation cannot overlap.  */
-         memcpy (ctx->buffer,
-                 &((char *) ctx->buffer)[(left_over + add) & ~127],
-                 ctx->buflen);
-       }
+          ctx->buflen &= 127;
+          /* The regions in the following copy operation cannot overlap.  */
+          memcpy (ctx->buffer,
+                  &((char *) ctx->buffer)[(left_over + add) & ~127],
+                  ctx->buflen);
+        }
 
       buffer = (const char *) buffer + add;
       len -= add;
@@ -366,22 +388,21 @@ sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx)
   if (len >= 128)
     {
 #if !_STRING_ARCH_unaligned
-# define alignof(type) offsetof (struct { char c; type x; }, x)
-# define UNALIGNED_P(p) (((size_t) p) % alignof (u64) != 0)
+# define UNALIGNED_P(p) ((uintptr_t) (p) % alignof (u64) != 0)
       if (UNALIGNED_P (buffer))
-       while (len > 128)
-         {
-           sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx);
-           buffer = (const char *) buffer + 128;
-           len -= 128;
-         }
+        while (len > 128)
+          {
+            sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx);
+            buffer = (const char *) buffer + 128;
+            len -= 128;
+          }
       else
 #endif
-       {
-         sha512_process_block (buffer, len & ~127, ctx);
-         buffer = (const char *) buffer + (len & ~127);
-         len &= 127;
-       }
+        {
+          sha512_process_block (buffer, len & ~127, ctx);
+          buffer = (const char *) buffer + (len & ~127);
+          len &= 127;
+        }
     }
 
   /* Move remaining bytes in internal buffer.  */
@@ -392,11 +413,11 @@ sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx)
       memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
       left_over += len;
       if (left_over >= 128)
-       {
-         sha512_process_block (ctx->buffer, 128, ctx);
-         left_over -= 128;
-         memcpy (ctx->buffer, &ctx->buffer[16], left_over);
-       }
+        {
+          sha512_process_block (ctx->buffer, 128, ctx);
+          left_over -= 128;
+          memcpy (ctx->buffer, &ctx->buffer[16], left_over);
+        }
       ctx->buflen = left_over;
     }
 }
@@ -470,35 +491,37 @@ sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx)
   u64 f = ctx->state[5];
   u64 g = ctx->state[6];
   u64 h = ctx->state[7];
+  u64 lolen = u64size (len);
 
   /* First increment the byte count.  FIPS PUB 180-2 specifies the possible
      length of the file up to 2^128 bits.  Here we only compute the
      number of bytes.  Do a double word increment.  */
-  ctx->total[0] = u64plus (ctx->total[0], u64lo (len));
-  if (u64lt (ctx->total[0], u64lo (len)))
-    ctx->total[1] = u64plus (ctx->total[1], u64lo (1));
+  ctx->total[0] = u64plus (ctx->total[0], lolen);
+  ctx->total[1] = u64plus (ctx->total[1],
+                           u64plus (u64size (len >> 31 >> 31 >> 2),
+                                    u64lo (u64lt (ctx->total[0], lolen))));
 
 #define S0(x) u64xor (u64rol(x, 63), u64xor (u64rol (x, 56), u64shr (x, 7)))
 #define S1(x) u64xor (u64rol (x, 45), u64xor (u64rol (x, 3), u64shr (x, 6)))
 #define SS0(x) u64xor (u64rol (x, 36), u64xor (u64rol (x, 30), u64rol (x, 25)))
 #define SS1(x) u64xor (u64rol(x, 50), u64xor (u64rol (x, 46), u64rol (x, 23)))
 
-#define M(I) (x[(I) & 15]                                                \
-             = u64plus (x[(I) & 15],                                     \
-                        u64plus (S1 (x[((I) - 2) & 15]),                 \
-                                 u64plus (x[((I) - 7) & 15],             \
-                                          S0 (x[((I) - 15) & 15])))))
-
-#define R(A, B, C, D, E, F, G, H, K, M)                                          \
-  do                                                                     \
-    {                                                                    \
-      u64 t0 = u64plus (SS0 (A), F2 (A, B, C));                                  \
-      u64 t1 =                                                           \
-       u64plus (H, u64plus (SS1 (E),                                     \
-                            u64plus (F1 (E, F, G), u64plus (K, M))));    \
-      D = u64plus (D, t1);                                               \
-      H = u64plus (t0, t1);                                              \
-    }                                                                    \
+#define M(I) (x[(I) & 15]                                                 \
+              = u64plus (x[(I) & 15],                                     \
+                         u64plus (S1 (x[((I) - 2) & 15]),                 \
+                                  u64plus (x[((I) - 7) & 15],             \
+                                           S0 (x[((I) - 15) & 15])))))
+
+#define R(A, B, C, D, E, F, G, H, K, M)                                   \
+  do                                                                      \
+    {                                                                     \
+      u64 t0 = u64plus (SS0 (A), F2 (A, B, C));                           \
+      u64 t1 =                                                            \
+        u64plus (H, u64plus (SS1 (E),                                     \
+                             u64plus (F1 (E, F, G), u64plus (K, M))));    \
+      D = u64plus (D, t1);                                                \
+      H = u64plus (t0, t1);                                               \
+    }                                                                     \
   while (0)
 
   while (words < endp)
@@ -506,10 +529,10 @@ sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx)
       int t;
       /* FIXME: see sha1.c for a better implementation.  */
       for (t = 0; t < 16; t++)
-       {
-         x[t] = SWAP (*words);
-         words++;
-       }
+        {
+          x[t] = SWAP (*words);
+          words++;
+        }
 
       R( a, b, c, d, e, f, g, h, K( 0), x[ 0] );
       R( h, a, b, c, d, e, f, g, K( 1), x[ 1] );
@@ -602,3 +625,4 @@ sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx)
       h = ctx->state[7] = u64plus (ctx->state[7], h);
     }
 }
+#endif