diff options
author | Tharre <tharre3@gmail.com> | 2014-12-12 09:15:31 +0100 |
---|---|---|
committer | Tharre <tharre3@gmail.com> | 2014-12-12 09:15:31 +0100 |
commit | 6347f449fe1b48e59f18327bbdcce60b2883f86e (patch) | |
tree | 281eee72e885612e2e0a06c285f3208b93991f86 | |
parent | b8ffd5621f5495b0ad1a92a67b51b7e0e15b0b6e (diff) | |
download | redo-6347f449fe1b48e59f18327bbdcce60b2883f86e.tar.gz redo-6347f449fe1b48e59f18327bbdcce60b2883f86e.tar.xz redo-6347f449fe1b48e59f18327bbdcce60b2883f86e.zip |
Exchange sha1 implementation
-rw-r--r-- | src/sha1.c | 614 | ||||
-rw-r--r-- | src/sha1.h | 50 |
2 files changed, 365 insertions, 299 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 + +----------------- +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 */ @@ -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 */ |