/* sha.c - Functions to compute the SHA1 hash (message-digest) of files
or blocks of memory. Complies to the NIST specification FIPS-180-1.
- Copyright (C) 2000 Scott G. Miller
+ Copyright (C) 2000, 2001, 2003 Scott G. Miller
Credits:
Robert Klep <robert@ilse.nl> -- Expansion function fix
# include <config.h>
#endif
+#include "sha.h"
+
#include <sys/types.h>
-#if STDC_HEADERS || defined _LIBC
-# include <stdlib.h>
-# include <string.h>
-#else
-# ifndef HAVE_MEMCPY
-# define memcpy(d, s, n) bcopy ((s), (d), (n))
-# endif
-#endif
+#include <stdlib.h>
+#include <string.h>
-#include "md5.h"
-#include "sha.h"
+#include "unlocked-io.h"
/*
Not-swap is a macro that does an endian swap on architectures that are
# define SWAP(n) (n)
#endif
+#define BLOCKSIZE 4096
+/* Ensure that BLOCKSIZE is a multiple of 64. */
+#if BLOCKSIZE % 64 != 0
+/* FIXME-someday (soon?): use #error instead of this kludge. */
+"invalid BLOCKSIZE"
+#endif
+
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (RFC 1321, 3.1: Step 1) */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
int
sha_stream (FILE *stream, void *resblock)
{
- /* Important: BLOCKSIZE must be a multiple of 64. */
-#define BLOCKSIZE 4096
struct sha_ctx ctx;
char buffer[BLOCKSIZE + 72];
size_t sum;
sum = 0;
/* Read block. Take care for partial reads. */
- do
+ while (1)
{
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
sum += n;
- }
- while (sum < BLOCKSIZE && n != 0);
- if (n == 0 && ferror (stream))
- return 1;
- /* If end of file is reached, end the loop. */
- if (n == 0)
- break;
+ 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;
+ }
/* Process buffer with BLOCKSIZE bytes. Note that
BLOCKSIZE % 64 == 0
sha_process_block (buffer, BLOCKSIZE, &ctx);
}
- /* Add the last bytes if necessary. */
+ process_partial_block:;
+
+ /* Process any remaining bytes. */
if (sum > 0)
sha_process_bytes (buffer, sum, &ctx);
memcpy (&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
- if (left_over + add > 64)
+ if (ctx->buflen > 64)
{
- sha_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
+ sha_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+ ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
- (left_over + add) & 63);
- ctx->buflen = (left_over + add) & 63;
+ ctx->buflen);
}
buffer = (const char *) buffer + add;
}
/* Process available complete blocks. */
- if (len > 64)
+ if (len >= 64)
{
- sha_process_block (buffer, len & ~63, ctx);
- buffer = (const char *) buffer + (len & ~63);
- len &= 63;
+#if !_STRING_ARCH_unaligned
+/* To check alignment gcc has an appropriate operator. Other
+ compilers don't. */
+# if __GNUC__ >= 2
+# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0)
+# else
+# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0)
+# endif
+ if (UNALIGNED_P (buffer))
+ while (len > 64)
+ {
+ sha_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+ buffer = (const char *) buffer + 64;
+ len -= 64;
+ }
+ else
+#endif
+ {
+ sha_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
- memcpy (ctx->buffer, buffer, len);
- ctx->buflen = len;
+ size_t left_over = ctx->buflen;
+
+ memcpy (&ctx->buffer[left_over], buffer, len);
+ left_over += len;
+ if (left_over >= 64)
+ {
+ sha_process_block (ctx->buffer, 64, ctx);
+ left_over -= 64;
+ memcpy (ctx->buffer, &ctx->buffer[64], left_over);
+ }
+ ctx->buflen = left_over;
}
}
#define F4(B,C,D) (B ^ C ^ D)
/* Process LEN bytes of BUFFER, accumulating context into CTX.
- It is assumed that LEN % 64 == 0. */
+ It is assumed that LEN % 64 == 0.
+ Most of this code comes from GnuPG's cipher/sha1.c. */
void
sha_process_block (const void *buffer, size_t len, struct sha_ctx *ctx)
const md5_uint32 *words = buffer;
size_t nwords = len / sizeof (md5_uint32);
const md5_uint32 *endp = words + nwords;
- md5_uint32 x[80];
+ md5_uint32 x[16];
md5_uint32 a = ctx->A;
md5_uint32 b = ctx->B;
md5_uint32 c = ctx->C;
#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \
^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \
- , (x[I&0x0f] = (tm << 1) | (tm >> 31)) )
+ , (x[I&0x0f] = rol(tm, 1)) )
#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \
+ F( B, C, D ) \
{
md5_uint32 tm;
int t;
+ /* FIXME: see sha1.c for a better implementation. */
for (t = 0; t < 16; t++)
{
x[t] = NOTSWAP (*words);