From 6347f449fe1b48e59f18327bbdcce60b2883f86e Mon Sep 17 00:00:00 2001
From: Tharre <tharre3@gmail.com>
Date: Fri, 12 Dec 2014 09:15:31 +0100
Subject: Exchange sha1 implementation

---
 src/sha1.c | 614 ++++++++++++++++++++++++++++++++++---------------------------
 src/sha1.h |  50 ++---
 2 files changed, 365 insertions(+), 299 deletions(-)

(limited to 'src')

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 */
-- 
cgit v1.2.3-70-g09d2