diff options
| -rw-r--r-- | src/sha1.c | 576 | ||||
| -rw-r--r-- | src/sha1.h | 46 | 
2 files changed, 344 insertions, 278 deletions
@@ -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 -#include "sha1.h" +----------------- +Modified 7/98 +By James H. Brown <jbrown@burgoyne.com> +Still 100% Public Domain -#include <string.h>	/* For memcpy() */ -#include <arpa/inet.h>	/* For ntohl() */ +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) -static void sha1_core(uint32_t iv[5], unsigned char const *p, size_t nblocks); +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(). -/* 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); -} +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). -#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]; -} -static inline void put_be32(unsigned char const *p, uint32_t v) -{ -        p[0] = v >> 24; -        p[1] = v >> 16; -        p[2] = v >> 8; -        p[3] = v; -} -#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); -} +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. -void SHA1_Update(struct SHA_context *c, void const *p, size_t n) -{ -        size_t pos = c->len & 63;	/* Offset into current input block */ +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. -        c->len += n; +-- +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. -        /* 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; -        } +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 -        /* 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); -} +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 -void SHA1_Final(unsigned char hash[20], struct SHA_context *c) -{ -        size_t pos = c->len & 63; -        unsigned i; +----------------- +Modified 4/01 +By Saul Kravitz <Saul.Kravitz@celera.com> +Still 100% PD +Modified to run on Compaq Alpha hardware. -        /* Append a single 1 bit */ -        c->buf[pos++] = 0x80; +----------------- +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 +*/ -        /* 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; -        } -        memset(c->buf + pos, 0, 56 - pos); +/* +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 +*/ -        /* 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); +/* #define SHA1HANDSOFF  */ -        /* Final hash round */ -        sha1_core(c->iv, c->buf, 1); +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -        /* Copy hash result out */ -        for (i = 0; i < 5; i++) -                put_be32(hash + 4*i, c->iv[i]); -} +#include <stdio.h> +#include <string.h> +#include <stdint.h> +/*#include "os_types.h"*/ +#include "sha1.h" -/* - * Helper macros for sha1_core function.  To avoid clutter, these macros - * are NOT fully parenthesized if it doesn't matter to the actual use. - */ +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); -#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) +#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 -/* 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) +#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); -/* - * 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") +#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]); +} +#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]) +{ +    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 -#define STORE(i, x) W(i) = x +    block = (CHAR64LONG16*)buffer;  #endif +    /* Copy context->state[] to working vars */ +    a = state[0]; +    b = state[1]; +    c = state[2]; +    d = state[3]; +    e = state[4]; -/* 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 */ +    /* 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); -/* 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) */ +    /* Add the working vars back into context.state[] */ +    state[0] += a; +    state[1] += b; +    state[2] += c; +    state[3] += d; +    state[4] += e; -/* 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) +    /* Wipe variables */ +    a = b = c = d = e = 0; +} -/* 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) +/* 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; +} -/* - * 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) + +/* Run your data through this. */ +void SHA1_Update(SHA_CTX* context, const uint8_t* data, const size_t len)  { -        uint32_t e = iv[4], d = iv[3], c = iv[2], b = iv[1], a = iv[0]; -        uint32_t w[16]; +    size_t i, j; -        do { -                uint32_t t; +#ifdef VERBOSE +    SHAPrintContext(context, "before"); +#endif -                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); +    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); +        } +        j = 0; +    } +    else i = 0; +    memcpy(&context->buffer[j], &data[i], len - i); + +#ifdef VERBOSE +    SHAPrintContext(context, "after "); +#endif +} -                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); +/* 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]; -                SHA_ROUND5(F2, K4, CALC, t, 60); -                SHA_ROUND5(F2, K4, CALC, t, 65); -                SHA_ROUND5(F2, K4, CALC, t, 70); +    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); +    } -                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); +    /* Wipe variables */ +    i = 0; +    memset(context->buffer, 0, 64); +    memset(context->state, 0, 20); +    memset(context->count, 0, 8); +    memset(finalcount, 0, 8);	/* SWR */ -                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); +#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite its own static vars */ +    SHA1_Transform(context->state, context->buffer); +#endif  } +/*************************************************************/ -/* Compile with -DUNITTEST for self-tests */ -#if UNITTEST +#if 0 +int main(int argc, char** argv) +{ +int i, j; +SHA_CTX context; +unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384]; +FILE* file; -#include <stdio.h> +    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 -/* Known answer test */ -static void katest(char const *text, size_t len, unsigned char const hash[20]) -{ -        SHA_CTX c; -        unsigned char hash2[20]; -        int i; +/* self test */ -        SHA1_Init(&c); -        SHA1_Update(&c, text, len); -        SHA1_Final(hash2, &c); +#ifdef TEST -        for (i = 0; i < 20; i++) -                if (hash[i] != hash2[i]) -                        goto mismatch; -        printf("%u-byte known answer test PASSED\n", len); -        return; +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"}; -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'); + +void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output) +{ +    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 }; +    int k; +    SHA_CTX context; +    uint8_t digest[20]; +    char output[80]; -        /* 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 }; +    fprintf(stdout, "verifying SHA-1 implementation... "); -        katest(text1, sizeof text1, hash1); -        katest(text2, sizeof text2, hash2); +    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); -        return 0; +        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 */ @@ -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) - */ +/* public api for steve reid's public domain SHA-1 implementation */ +/* this file is in the public domain */ -#include <stddef.h>	/* For size_t */ -#include <stdint.h>	/* For uint32_t, uint64_t */ +#ifndef __SHA1_H +#define __SHA1_H -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 */ +#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 */  | 
