aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTharre <tharre3@gmail.com>2014-12-12 09:15:31 +0100
committerTharre <tharre3@gmail.com>2014-12-12 09:15:31 +0100
commit6347f449fe1b48e59f18327bbdcce60b2883f86e (patch)
tree281eee72e885612e2e0a06c285f3208b93991f86
parentb8ffd5621f5495b0ad1a92a67b51b7e0e15b0b6e (diff)
downloadredo-6347f449fe1b48e59f18327bbdcce60b2883f86e.tar.gz
redo-6347f449fe1b48e59f18327bbdcce60b2883f86e.tar.xz
redo-6347f449fe1b48e59f18327bbdcce60b2883f86e.zip
Exchange sha1 implementation
-rw-r--r--src/sha1.c614
-rw-r--r--src/sha1.h50
2 files changed, 365 insertions, 299 deletions
diff --git a/src/sha1.c b/src/sha1.c
index 871206c..3475dd2 100644
--- a/src/sha1.c
+++ b/src/sha1.c
@@ -1,314 +1,376 @@
/*
- * Secure Hash Algorith SHA-1, as published in FIPS PUB 180-2.
- *
- * This implementation is in the public domain. Copyright abandoned.
- * You may do anything you like with it, including evil things.
- *
- * This is a rewrite from scratch, based on Linus Torvalds' "block-sha1"
- * from the git mailing list (August, 2009). Additional optimization
- * ideas cribbed from
- * - Artur Skawina (x86, particularly P4, and much benchmarking)
- * - Nicolas Pitre (ARM)
- */
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+ void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned int
+len)
+to
+ void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it. This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Modified 07/2002
+By Ralph Giles <giles@ghostscript.com>
+Still 100% public domain
+modified for use with stdint types, autoconf
+code cleanup, removed attribution comments
+switched SHA1Final() argument order for consistency
+use SHA1_ prefix for public api
+move public api to sha1.h
+*/
-#include "sha1.h"
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define SHA1HANDSOFF */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
-#include <string.h> /* For memcpy() */
-#include <arpa/inet.h> /* For ntohl() */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
-static void sha1_core(uint32_t iv[5], unsigned char const *p, size_t nblocks);
+/*#include "os_types.h"*/
+#include "sha1.h"
-/* Machine specific hacks */
-#if defined(__i386__) || defined(__x86_64__) || defined (__ppc__) || \
- defined(__ppc64__) || defined(__powerpc__) || defined (__powerpc64__) || \
- defined(__s390__) || defined(__s390x__)
-/* Unaligned access is okay */
-static inline uint32_t get_be32(unsigned char const *p)
-{
- return ntohl(*(uint32_t const *)p);
-}
-static inline void put_be32(unsigned char const *p, uint32_t v)
-{
- *(uint32_t *)p = htonl(v);
-}
+void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+/* FIXME: can we do this in an endian-proof way? */
+#ifdef WORDS_BIGENDIAN
+#define blk0(i) block->l[i]
#else
-/* Unaligned access is not okay; do conversion as byte fetches */
-static inline uint32_t get_be32(unsigned char const *p)
-{
- return p[0] << 24 || p[1] << 16 | p[8] << 8 | p[3];
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+#ifdef VERBOSE /* SAK */
+void SHAPrintContext(SHA_CTX *context, char *msg){
+ printf("%s (%d,%d) %x %x %x %x %x\n",
+ msg,
+ context->count[0], context->count[1],
+ context->state[0],
+ context->state[1],
+ context->state[2],
+ context->state[3],
+ context->state[4]);
}
-static inline void put_be32(unsigned char const *p, uint32_t v)
+#endif /* VERBOSE */
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
{
- p[0] = v >> 24;
- p[1] = v >> 16;
- p[2] = v >> 8;
- p[3] = v;
-}
+ uint32_t a, b, c, d, e;
+ typedef union {
+ uint8_t c[64];
+ uint32_t l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16* block;
+
+#ifdef SHA1HANDSOFF
+ static uint8_t workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
#endif
-void SHA1_Init(struct SHA_context *c)
-{
- /* This is a prefix of the SHA_context structure */
- static struct {
- uint64_t len;
- uint32_t iv[5];
- } const iv = { 0,
- { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }
- };
-
- memcpy(c, &iv, sizeof iv);
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ /* Wipe variables */
+ a = b = c = d = e = 0;
}
-void SHA1_Update(struct SHA_context *c, void const *p, size_t n)
-{
- size_t pos = c->len & 63; /* Offset into current input block */
-
- c->len += n;
-
- /* Initial partial block (if any) */
- if (pos) {
- size_t space = 63 - pos;
- if (n < space)
- goto end;
- memcpy(c->buf + pos, p, space);
- sha1_core(c->iv, c->buf, 1);
- n -= space;
- p = (char const *)p + space;
- }
- /* The large middle piece */
- if (n >> 6) {
- sha1_core(c->iv, p, n >> 6);
- p = (char const *)p + (n & -(size_t)64);
- n &= 63;
- }
- pos = 0;
-end:
- /* Final partial block (may be zero size) */
- memcpy(c->buf + pos, p, n);
+/* SHA1Init - Initialize new context */
+void SHA1_Init(SHA_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
}
-void SHA1_Final(unsigned char hash[20], struct SHA_context *c)
+
+/* Run your data through this. */
+void SHA1_Update(SHA_CTX* context, const uint8_t* data, const size_t len)
{
- size_t pos = c->len & 63;
- unsigned i;
+ size_t i, j;
- /* Append a single 1 bit */
- c->buf[pos++] = 0x80;
+#ifdef VERBOSE
+ SHAPrintContext(context, "before");
+#endif
- /* Append 0 bits until 64 bits remain in a block */
- if (pos > 56) {
- memset(c->buf + pos, 0, 64 - pos);
- sha1_core(c->iv, c->buf, 1);
- pos = 0;
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1_Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1_Transform(context->state, data + i);
}
- memset(c->buf + pos, 0, 56 - pos);
-
- /* Append total input length in bits */
- ((uint32_t *)c->buf)[14] = htonl((uint32_t)(c->len >> 29));
- ((uint32_t *)c->buf)[15] = htonl((uint32_t)c->len << 3);
-
- /* Final hash round */
- sha1_core(c->iv, c->buf, 1);
-
- /* Copy hash result out */
- for (i = 0; i < 5; i++)
- put_be32(hash + 4*i, c->iv[i]);
-}
-
-
-/*
- * Helper macros for sha1_core function. To avoid clutter, these macros
- * are NOT fully parenthesized if it doesn't matter to the actual use.
- */
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
-#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
-/*
- * GCC by itself only generates left rotates. Use right rotates if
- * possible to be kinder to dinky implementations with iterative rotate
- * instructions.
- */
-#define ROT(op, x, k) \
- ({ uint32_t y; __asm__(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
-#define ROL(x,k) ROT("roll", x, k)
-#define ROR(x,k) ROT("rorl", x, k)
-
-#else
-/* Generic C equivalent */
-#define ROT(x,l,r) ((x) << (l) | (x) >> (r))
-#define ROL(x,k) ROT(x,k,32-(k))
-#define ROR(x,k) ROT(x,32-(k),k)
+#ifdef VERBOSE
+ SHAPrintContext(context, "after ");
#endif
+}
-/*
- * An important temporary array in SHA-1 is the working array W[],
- * which holds a scheduled key word per round. Only the last 16 words
- * are relevant, so only use 16 words...
- */
-#define W(i) w[(i) & 15]
-
-/*
- * If you have a small register set, it helps GCC to force stores to
- * the w[] array to memory. Given 22 or more registers (e.g. PowerPC),
- * GCC can map the entire w[] array to registers and this becomes
- * counterproductive.
- *
- * The optimal kludge seems to differ between x86 and ARM. On the latter,
- * forcing a full memory barrier is required to stop GCC from splitting
- * live ranges for each round and generating a separate stack slot for
- * each. (Which produces a huge stack frame and kills performance.)
- */
-#if defined(__i386__) || defined(__x86_64__)
-#define STORE(i, x) *(volatile uint32_t *)&W(i) = x
-#elif __GNUC__ && defined(__arm__)
-#define STORE(i, x) W(i) = x; __asm__("":::"memory")
-#else
-#define STORE(i, x) W(i) = x
+/* Add padding and return the message digest. */
+void SHA1_Final(uint8_t digest[SHA1_DIGEST_SIZE], SHA_CTX* context)
+{
+ uint32_t i;
+ uint8_t finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1_Update(context, (uint8_t *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1_Update(context, (uint8_t *)"\0", 1);
+ }
+ SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
+ for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
+ digest[i] = (uint8_t)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+
+ /* Wipe variables */
+ i = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(finalcount, 0, 8); /* SWR */
+
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
+ SHA1_Transform(context->state, context->buffer);
#endif
+}
+/*************************************************************/
-/* The three round functions. F2 is also used as F4 */
-#define F1(b,c,d) (((d ^ c) & b) ^ d) /* Bitwise b ? c : d */
-#define F2(b,c,d) (d ^ c ^ b) /* Even parity */
-#define F3(b,c,d) (d & c) + ((d ^ c) & b) /* Majority function */
-
-/* The four round constants */
-#define K1 0x5a827999 /* 2^30 * sqrt(2) */
-#define K2 0x6ed9eba1 /* 2^30 * sqrt(3) */
-#define K3 0x8f1bbcdc /* 2^30 * sqrt(5) */
-#define K4 0xca62c1d6 /* 2^30 * sqrt(10) */
-
-/* Rounds 0..15 fetch a word from the input */
-#define FETCH(t,i) t = get_be32(p + 4*(i)); STORE(i,t)
-/* Rounds 16..79 mix previous words to get a new one */
-#define MIX(t,i) t = W(i) ^ W(i+2) ^ W(i+8) ^ W(i+13); t = ROL(t, 1)
-/* Rounds 16..76 have to store back the result */
-#define CALC(t,i) MIX(t,i); STORE(i,t)
-
-/* The basic SHA-1 round */
-#define SHA_ROUND(a,b,c,d,e,f,k,src,t,i) \
- src(t,i); \
- e += t + f(b,c,d) + k + ROL(a,5); \
- b = ROR(b,2)
-
-/* An aligned group of 5 rounds */
-#define SHA_ROUND5(f,k,src,t,i) \
- SHA_ROUND(a,b,c,d,e, f,k,src,t,i); \
- SHA_ROUND(e,a,b,c,d, f,k,src,t,i+1); \
- SHA_ROUND(d,e,a,b,c, f,k,src,t,i+2); \
- SHA_ROUND(c,d,e,a,b, f,k,src,t,i+3); \
- SHA_ROUND(b,c,d,e,a, f,k,src,t,i+4)
-
-/*
- * The core SHA-1 transform.
- *
- * iv[5] = Current SHA-1 hash state.
- * p = Pointer to source data. Not necessarily aligned.
- * nblocks = Number of 64-byte blocks at p. Guaranteed non-zero.
- */
-static void
-sha1_core(uint32_t iv[5], unsigned char const *p, size_t nblocks)
+#if 0
+int main(int argc, char** argv)
{
- uint32_t e = iv[4], d = iv[3], c = iv[2], b = iv[1], a = iv[0];
- uint32_t w[16];
-
- do {
- uint32_t t;
-
- SHA_ROUND5(F1, K1, FETCH, t, 0);
- SHA_ROUND5(F1, K1, FETCH, t, 5);
- SHA_ROUND5(F1, K1, FETCH, t, 10);
- SHA_ROUND(a,b,c,d,e, F1, K1, FETCH, t, 15);
- SHA_ROUND(e,a,b,c,d, F1, K1, CALC, t, 16);
- SHA_ROUND(d,e,a,b,c, F1, K1, CALC, t, 17);
- SHA_ROUND(c,d,e,a,b, F1, K1, CALC, t, 18);
- SHA_ROUND(b,c,d,e,a, F1, K1, CALC, t, 19);
-
- SHA_ROUND5(F2, K2, CALC, t, 20);
- SHA_ROUND5(F2, K2, CALC, t, 25);
- SHA_ROUND5(F2, K2, CALC, t, 30);
- SHA_ROUND5(F2, K2, CALC, t, 35);
-
- SHA_ROUND5(F3, K3, CALC, t, 40);
- SHA_ROUND5(F3, K3, CALC, t, 45);
- SHA_ROUND5(F3, K3, CALC, t, 50);
- SHA_ROUND5(F3, K3, CALC, t, 55);
-
- SHA_ROUND5(F2, K4, CALC, t, 60);
- SHA_ROUND5(F2, K4, CALC, t, 65);
- SHA_ROUND5(F2, K4, CALC, t, 70);
-
- SHA_ROUND(a,b,c,d,e, F2, K4, CALC, t, 75);
- SHA_ROUND(e,a,b,c,d, F2, K4, CALC, t, 76);
- /* Last 3 rounds don't need to store mixed value */
- SHA_ROUND(d,e,a,b,c, F2, K4, MIX, t, 77);
- SHA_ROUND(c,d,e,a,b, F2, K4, MIX, t, 78);
- SHA_ROUND(b,c,d,e,a, F2, K4, MIX, t, 79);
-
- iv[4] = e += iv[4];
- iv[3] = d += iv[3];
- iv[2] = c += iv[2];
- iv[1] = b += iv[1];
- iv[0] = a += iv[0];
- } while (--nblocks);
+int i, j;
+SHA_CTX context;
+unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384];
+FILE* file;
+
+ if (argc > 2) {
+ puts("Public domain SHA-1 implementation - by Steve Reid <sreid@sea-to-sky.net>");
+ puts("Modified for 16 bit environments 7/98 - by James H. Brown <jbrown@burgoyne.com>"); /* JHB */
+ puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");
+ return(0);
+ }
+ if (argc < 2) {
+ file = stdin;
+ }
+ else {
+ if (!(file = fopen(argv[1], "rb"))) {
+ fputs("Unable to open file.", stderr);
+ return(-1);
+ }
+ }
+ SHA1_Init(&context);
+ while (!feof(file)) { /* note: what if ferror(file) */
+ i = fread(buffer, 1, 16384, file);
+ SHA1_Update(&context, buffer, i);
+ }
+ SHA1_Final(&context, digest);
+ fclose(file);
+ for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
+ for (j = 0; j < 4; j++) {
+ printf("%02X", digest[i*4+j]);
+ }
+ putchar(' ');
+ }
+ putchar('\n');
+ return(0); /* JHB */
}
+#endif
+/* self test */
-/* Compile with -DUNITTEST for self-tests */
-#if UNITTEST
+#ifdef TEST
+
+static char *test_data[] = {
+ "abc",
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "A million repetitions of 'a'"};
+static char *test_results[] = {
+ "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
+ "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
+ "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"};
-#include <stdio.h>
-/* Known answer test */
-static void katest(char const *text, size_t len, unsigned char const hash[20])
+void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output)
{
- SHA_CTX c;
- unsigned char hash2[20];
- int i;
-
- SHA1_Init(&c);
- SHA1_Update(&c, text, len);
- SHA1_Final(hash2, &c);
-
- for (i = 0; i < 20; i++)
- if (hash[i] != hash2[i])
- goto mismatch;
- printf("%u-byte known answer test PASSED\n", len);
- return;
-
-mismatch:
- printf("%u-byte known answer test FAILED:\n", len);
- printf("Input: \"%.*s\"\n", len, text);
- printf("Computed:");
- for (i = 0; i < 20; i++)
- printf(" %02x", hash2[i]);
- printf("\nExpected:");
- for (i = 0; i < 20; i++)
- printf(" %02x", hash[i]);
- putchar('\n');
+ int i,j;
+ char *c = output;
+
+ for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {
+ for (j = 0; j < 4; j++) {
+ sprintf(c,"%02X", digest[i*4+j]);
+ c += 2;
+ }
+ sprintf(c, " ");
+ c += 1;
+ }
+ *(c - 1) = '\0';
}
-int
-main(void)
+int main(int argc, char** argv)
{
- /* FIPS PUB 180.1 example A.1 */
- static char const text1[3] = "abc";
- static unsigned char const hash1[20] = {
- 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
- 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d };
-
- /* FIPS PUB 180.1 example A.2 */
- static char const text2[56] =
- "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
- static unsigned char const hash2[20] = {
- 0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
- 0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1 };
-
- katest(text1, sizeof text1, hash1);
- katest(text2, sizeof text2, hash2);
-
- return 0;
+ int k;
+ SHA_CTX context;
+ uint8_t digest[20];
+ char output[80];
+
+ fprintf(stdout, "verifying SHA-1 implementation... ");
+
+ for (k = 0; k < 2; k++){
+ SHA1_Init(&context);
+ SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k]));
+ SHA1_Final(digest, &context);
+ digest_to_hex(digest, output);
+
+ if (strcmp(output, test_results[k])) {
+ fprintf(stdout, "FAIL\n");
+ fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]);
+ fprintf(stderr,"\t%s returned\n", output);
+ fprintf(stderr,"\t%s is correct\n", test_results[k]);
+ return (1);
+ }
+ }
+ /* million 'a' vector we feed separately */
+ SHA1_Init(&context);
+ for (k = 0; k < 1000000; k++)
+ SHA1_Update(&context, (uint8_t*)"a", 1);
+ SHA1_Final(digest, &context);
+ digest_to_hex(digest, output);
+ if (strcmp(output, test_results[2])) {
+ fprintf(stdout, "FAIL\n");
+ fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]);
+ fprintf(stderr,"\t%s returned\n", output);
+ fprintf(stderr,"\t%s is correct\n", test_results[2]);
+ return (1);
+ }
+
+ /* success */
+ fprintf(stdout, "ok\n");
+ return(0);
}
-#endif
+#endif /* TEST */
diff --git a/src/sha1.h b/src/sha1.h
index ee59229..dbcfe58 100644
--- a/src/sha1.h
+++ b/src/sha1.h
@@ -1,25 +1,29 @@
-/*
- * Secure Hash Algorith SHA-1, as published in FIPS PUB 180-2.
- *
- * This implementation is in the public domain. Copyright abandoned.
- * You may do anything you like with it, including evil things.
- *
- * This is a rewrite from scratch, based on Linus Torvalds' "block-sha1"
- * from the git mailing list (August, 2009). Additional optimization
- * ideas cribbed from
- * - Artur Skawina (x86, particularly P4, and much benchmarking)
- * - Nicolas Pitre (ARM)
- */
-
-#include <stddef.h> /* For size_t */
-#include <stdint.h> /* For uint32_t, uint64_t */
-
-typedef struct SHA_context {
- uint64_t len; /* May be shrunk to uint32_t */
- uint32_t iv[5];
- unsigned char buf[64]; /* Must be 32-bit aligned */
+/* public api for steve reid's public domain SHA-1 implementation */
+/* this file is in the public domain */
+
+#ifndef __SHA1_H
+#define __SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ uint8_t buffer[64];
} SHA_CTX;
-void SHA1_Init(struct SHA_context *c);
-void SHA1_Update(struct SHA_context *c, void const *p, size_t n);
-void SHA1_Final(unsigned char hash[20], struct SHA_context *c);
+#define SHA1_DIGEST_SIZE 20
+
+void SHA1_Init(SHA_CTX* context);
+void SHA1_Update(SHA_CTX* context, const uint8_t* data, const size_t len);
+void SHA1_Final(uint8_t digest[SHA1_DIGEST_SIZE], SHA_CTX* context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SHA1_H */