paulo@0: /* paulo@0: * $Id: sha1.c,v 1.18 2006/07/09 13:05:20 mkern Exp $ paulo@0: * paulo@0: * (PD) 2001 The Bitzi Corporation paulo@0: * Please see http://bitzi.com/publicdomain for more info. paulo@0: * paulo@0: * NIST Secure Hash Algorithm paulo@0: * heavily modified by Uwe Hollerbach paulo@0: * from Peter C. Gutmann's implementation as found in paulo@0: * Applied Cryptography by Bruce Schneier paulo@0: * Further modifications to include the "UNRAVEL" stuff, below paulo@0: * paulo@0: * New, faster sha1 code. The original code was from Bitzi corporation, and paulo@0: * was in the public domain. [The original header is included.] paulo@0: * paulo@0: * This code is in the public domain. paulo@0: */ paulo@0: paulo@0: #include paulo@0: #include paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: paulo@0: #include "sha1.h" paulo@0: #include "encoding/base32.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: typedef struct sha1_state SHA_INFO; paulo@0: paulo@0: /* define the functions to names private to this plugin */ paulo@0: #define sha_init gt_sha1_init paulo@0: #define sha_update gt_sha1_append paulo@0: #define sha_final gt_sha1_finish paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: void sha_init(SHA_INFO *); paulo@0: void sha_update(SHA_INFO *, const void *, size_t); paulo@0: void sha_final(SHA_INFO *, unsigned char [20]); paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* SHA f()-functions */ paulo@0: paulo@0: #define f1(x,y,z) ((x & y) | (~x & z)) paulo@0: #define f2(x,y,z) (x ^ y ^ z) paulo@0: #define f3(x,y,z) ((x & y) | (x & z) | (y & z)) paulo@0: #define f4(x,y,z) (x ^ y ^ z) paulo@0: paulo@0: /* SHA constants */ paulo@0: paulo@0: #define CONST1 0x5a827999L paulo@0: #define CONST2 0x6ed9eba1L paulo@0: #define CONST3 0x8f1bbcdcL paulo@0: #define CONST4 0xca62c1d6L paulo@0: paulo@0: /* truncate to 32 bits -- should be a null op on 32-bit machines */ paulo@0: paulo@0: #define T32(x) ((x) & 0xffffffffL) paulo@0: paulo@0: /* 32-bit rotate */ paulo@0: paulo@0: #define R32(x,n) T32(((x << n) | (x >> (32 - n)))) paulo@0: paulo@0: /* the generic case, for when the overall rotation is not unraveled */ paulo@0: paulo@0: #define FG(n) \ paulo@0: T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \ paulo@0: E = D; D = C; C = R32(B,30); B = A; A = T paulo@0: paulo@0: /* specific cases, for when the overall rotation is unraveled */ paulo@0: paulo@0: #define FA(n) \ paulo@0: T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30) paulo@0: paulo@0: #define FB(n) \ paulo@0: E = T32(R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n); A = R32(A,30) paulo@0: paulo@0: #define FC(n) \ paulo@0: D = T32(R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n); T = R32(T,30) paulo@0: paulo@0: #define FD(n) \ paulo@0: C = T32(R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n); E = R32(E,30) paulo@0: paulo@0: #define FE(n) \ paulo@0: B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30) paulo@0: paulo@0: #define FT(n) \ paulo@0: A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30) paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: #ifndef WIN32 paulo@0: paulo@0: /* sigh */ paulo@0: #ifdef WORDS_BIGENDIAN paulo@0: # if SIZEOF_LONG == 4 paulo@0: # define SHA_BYTE_ORDER 4321 paulo@0: # elif SIZEOF_LONG == 8 paulo@0: # define SHA_BYTE_ORDER 87654321 paulo@0: # endif paulo@0: #else paulo@0: # if SIZEOF_LONG == 4 paulo@0: # define SHA_BYTE_ORDER 1234 paulo@0: # elif SIZEOF_LONG == 8 paulo@0: # define SHA_BYTE_ORDER 12345678 paulo@0: # endif paulo@0: #endif paulo@0: paulo@0: #else /* WIN32 */ paulo@0: paulo@0: #define SHA_BYTE_ORDER 1234 paulo@0: paulo@0: #endif /* !WIN32 */ paulo@0: paulo@0: paulo@0: /* do SHA transformation */ paulo@0: static void sha_transform(SHA_INFO *sha_info) paulo@0: { paulo@0: int i; paulo@0: uint8_t *dp; paulo@0: unsigned long T, A, B, C, D, E, W[80], *WP; paulo@0: paulo@0: dp = sha_info->data; paulo@0: paulo@0: /* paulo@0: the following makes sure that at least one code block below is paulo@0: traversed or an error is reported, without the necessity for nested paulo@0: preprocessor if/else/endif blocks, which are a great pain in the paulo@0: nether regions of the anatomy... paulo@0: */ paulo@0: #undef SWAP_DONE paulo@0: paulo@0: #if (SHA_BYTE_ORDER == 1234) paulo@0: #define SWAP_DONE paulo@0: for (i = 0; i < 16; ++i) { paulo@0: T = *((unsigned long *) dp); paulo@0: dp += 4; paulo@0: W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | paulo@0: ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); paulo@0: } paulo@0: #endif /* SHA_BYTE_ORDER == 1234 */ paulo@0: paulo@0: #if (SHA_BYTE_ORDER == 4321) paulo@0: #define SWAP_DONE paulo@0: for (i = 0; i < 16; ++i) { paulo@0: T = *((unsigned long *) dp); paulo@0: dp += 4; paulo@0: W[i] = T32(T); paulo@0: } paulo@0: #endif /* SHA_BYTE_ORDER == 4321 */ paulo@0: paulo@0: #if (SHA_BYTE_ORDER == 12345678) paulo@0: #define SWAP_DONE paulo@0: for (i = 0; i < 16; i += 2) { paulo@0: T = *((unsigned long *) dp); paulo@0: dp += 8; paulo@0: W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | paulo@0: ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); paulo@0: T >>= 32; paulo@0: W[i+1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | paulo@0: ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); paulo@0: } paulo@0: #endif /* SHA_BYTE_ORDER == 12345678 */ paulo@0: paulo@0: #if (SHA_BYTE_ORDER == 87654321) paulo@0: #define SWAP_DONE paulo@0: for (i = 0; i < 16; i += 2) { paulo@0: T = *((unsigned long *) dp); paulo@0: dp += 8; paulo@0: W[i] = T32(T >> 32); paulo@0: W[i+1] = T32(T); paulo@0: } paulo@0: #endif /* SHA_BYTE_ORDER == 87654321 */ paulo@0: paulo@0: #ifndef SWAP_DONE paulo@0: #error Unknown byte order -- you need to add code here paulo@0: #endif /* SWAP_DONE */ paulo@0: paulo@0: for (i = 16; i < 80; ++i) { paulo@0: W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; paulo@0: W[i] = R32(W[i], 1); paulo@0: } paulo@0: paulo@0: A = sha_info->digest[0]; paulo@0: B = sha_info->digest[1]; paulo@0: C = sha_info->digest[2]; paulo@0: D = sha_info->digest[3]; paulo@0: E = sha_info->digest[4]; paulo@0: WP = W; paulo@0: paulo@0: FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); paulo@0: FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); paulo@0: FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); paulo@0: FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); paulo@0: FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); paulo@0: FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); paulo@0: FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); paulo@0: FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); paulo@0: paulo@0: sha_info->digest[0] = T32(sha_info->digest[0] + E); paulo@0: sha_info->digest[1] = T32(sha_info->digest[1] + T); paulo@0: sha_info->digest[2] = T32(sha_info->digest[2] + A); paulo@0: sha_info->digest[3] = T32(sha_info->digest[3] + B); paulo@0: sha_info->digest[4] = T32(sha_info->digest[4] + C); paulo@0: } paulo@0: paulo@0: /* initialize the SHA digest */ paulo@0: void sha_init(SHA_INFO *sha_info) paulo@0: { paulo@0: sha_info->digest[0] = 0x67452301L; paulo@0: sha_info->digest[1] = 0xefcdab89L; paulo@0: sha_info->digest[2] = 0x98badcfeL; paulo@0: sha_info->digest[3] = 0x10325476L; paulo@0: sha_info->digest[4] = 0xc3d2e1f0L; paulo@0: sha_info->count_lo = 0L; paulo@0: sha_info->count_hi = 0L; paulo@0: sha_info->local = 0; paulo@0: } paulo@0: paulo@0: /* update the SHA digest */ paulo@0: void sha_update(SHA_INFO *sha_info, const void *data, size_t count) paulo@0: { paulo@0: int i; paulo@0: unsigned long clo; paulo@0: const uint8_t *buffer = data; paulo@0: paulo@0: clo = T32(sha_info->count_lo + ((unsigned long) count << 3)); paulo@0: if (clo < sha_info->count_lo) { paulo@0: ++sha_info->count_hi; paulo@0: } paulo@0: sha_info->count_lo = clo; paulo@0: sha_info->count_hi += (unsigned long) count >> 29; paulo@0: if (sha_info->local) { paulo@0: i = SHA_BLOCKSIZE - sha_info->local; paulo@0: if (i > count) { paulo@0: i = count; paulo@0: } paulo@0: memcpy(sha_info->data + sha_info->local, buffer, i); paulo@0: count -= i; paulo@0: buffer += i; paulo@0: sha_info->local += i; paulo@0: if (sha_info->local == SHA_BLOCKSIZE) { paulo@0: sha_transform(sha_info); paulo@0: } else { paulo@0: return; paulo@0: } paulo@0: } paulo@0: while (count >= SHA_BLOCKSIZE) { paulo@0: memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); paulo@0: buffer += SHA_BLOCKSIZE; paulo@0: count -= SHA_BLOCKSIZE; paulo@0: sha_transform(sha_info); paulo@0: } paulo@0: memcpy(sha_info->data, buffer, count); paulo@0: sha_info->local = count; paulo@0: } paulo@0: paulo@0: /* finish computing the SHA digest */ paulo@0: void sha_final(SHA_INFO *sha_info, unsigned char *digest) paulo@0: { paulo@0: int count; paulo@0: unsigned long lo_bit_count, hi_bit_count; paulo@0: paulo@0: lo_bit_count = sha_info->count_lo; paulo@0: hi_bit_count = sha_info->count_hi; paulo@0: count = (int) ((lo_bit_count >> 3) & 0x3f); paulo@0: sha_info->data[count++] = 0x80; paulo@0: if (count > SHA_BLOCKSIZE - 8) { paulo@0: memset(sha_info->data + count, 0, SHA_BLOCKSIZE - count); paulo@0: sha_transform(sha_info); paulo@0: memset(sha_info->data, 0, SHA_BLOCKSIZE - 8); paulo@0: } else { paulo@0: memset(sha_info->data + count, 0, paulo@0: SHA_BLOCKSIZE - 8 - count); paulo@0: } paulo@0: sha_info->data[56] = (unsigned char) ((hi_bit_count >> 24) & 0xff); paulo@0: sha_info->data[57] = (unsigned char) ((hi_bit_count >> 16) & 0xff); paulo@0: sha_info->data[58] = (unsigned char) ((hi_bit_count >> 8) & 0xff); paulo@0: sha_info->data[59] = (unsigned char) ((hi_bit_count >> 0) & 0xff); paulo@0: sha_info->data[60] = (unsigned char) ((lo_bit_count >> 24) & 0xff); paulo@0: sha_info->data[61] = (unsigned char) ((lo_bit_count >> 16) & 0xff); paulo@0: sha_info->data[62] = (unsigned char) ((lo_bit_count >> 8) & 0xff); paulo@0: sha_info->data[63] = (unsigned char) ((lo_bit_count >> 0) & 0xff); paulo@0: sha_transform(sha_info); paulo@0: digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); paulo@0: digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); paulo@0: digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); paulo@0: digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff); paulo@0: digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); paulo@0: digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); paulo@0: digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); paulo@0: digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff); paulo@0: digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); paulo@0: digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); paulo@0: digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); paulo@0: digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff); paulo@0: digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); paulo@0: digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); paulo@0: digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); paulo@0: digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff); paulo@0: digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); paulo@0: digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); paulo@0: digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); paulo@0: digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: #define BLOCK_SIZE 8192 paulo@0: paulo@0: #if 0 paulo@0: /* compute the SHA digest of a FILE stream */ paulo@0: static void sha_stream(unsigned char digest[20], SHA_INFO *sha_info, FILE *fin) paulo@0: { paulo@0: int i; paulo@0: uint8_t data[BLOCK_SIZE]; paulo@0: paulo@0: sha_init(sha_info); paulo@0: while ((i = fread(data, 1, BLOCK_SIZE, fin)) > 0) { paulo@0: sha_update(sha_info, data, i); paulo@0: } paulo@0: sha_final(sha_info, digest); paulo@0: } paulo@0: paulo@0: /* print a SHA digest */ paulo@0: static void sha_print(unsigned char digest[20]) paulo@0: { paulo@0: int i, j; paulo@0: paulo@0: for (j = 0; j < 5; ++j) { paulo@0: for (i = 0; i < 4; ++i) { paulo@0: printf("%02x", *digest++); paulo@0: } paulo@0: printf("%c", (j < 4) ? ' ' : '\n'); paulo@0: } paulo@0: } paulo@0: #endif paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* paulo@0: * Hash a file with the sha1 algorithm using fread. Hash the whole file if paulo@0: * size == 0. paulo@0: */ paulo@0: static unsigned char *sha1_hash_fread (const char *file, off_t size) paulo@0: { paulo@0: FILE *f; paulo@0: unsigned char *hash; paulo@0: sha1_state_t state; paulo@0: off_t len; paulo@0: ssize_t n; paulo@0: struct stat st; paulo@0: char buf[BLOCK_SIZE]; paulo@0: paulo@0: if (!(f = fopen (file, "rb"))) paulo@0: return NULL; paulo@0: paulo@0: sha_init (&state); paulo@0: paulo@0: if (stat (file, &st) == -1) paulo@0: { paulo@0: fclose (f); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: if (size == 0) paulo@0: size = st.st_size; paulo@0: paulo@0: while (size > 0) paulo@0: { paulo@0: len = MIN (sizeof (buf), size); paulo@0: paulo@0: n = fread (buf, 1, len, f); paulo@0: paulo@0: if (n == 0 || n != len) paulo@0: break; paulo@0: paulo@0: sha_update (&state, (unsigned char *) buf, len); paulo@0: size -= len; paulo@0: } paulo@0: paulo@0: fclose (f); paulo@0: paulo@0: if (size != 0) paulo@0: return NULL; paulo@0: paulo@0: if ((hash = malloc (SHA1_BINSIZE))) paulo@0: sha_final (&state, hash); paulo@0: paulo@0: return hash; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* return a base32 representation of a sha1 hash */ paulo@0: char *sha1_string (const unsigned char *sha1) paulo@0: { paulo@0: char *base32; paulo@0: paulo@0: base32 = malloc (SHA1_STRLEN + 1); paulo@0: paulo@0: if (!base32) paulo@0: return NULL; paulo@0: paulo@0: gt_base32_encode (sha1, SHA1_BINSIZE, base32, SHA1_STRLEN); paulo@0: base32[32] = 0; paulo@0: paulo@0: return base32; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: unsigned char *sha1_bin (const char *ascii) paulo@0: { paulo@0: unsigned char *bin; paulo@0: size_t len; paulo@0: paulo@0: /* TODO: maybe this should copy the string and pad up to the min length if paulo@0: * it's less than 32? */ paulo@0: len = strlen (ascii); paulo@0: assert (len >= SHA1_STRLEN); paulo@0: paulo@0: if (!gt_base32_valid (ascii, SHA1_STRLEN)) paulo@0: return NULL; paulo@0: paulo@0: if (!(bin = malloc (SHA1_BINSIZE))) paulo@0: return NULL; paulo@0: paulo@0: gt_base32_decode (ascii, SHA1_STRLEN, bin, SHA1_BINSIZE); paulo@0: return bin; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: unsigned char *sha1_digest (const char *file, off_t size) paulo@0: { paulo@0: unsigned char *hash; paulo@0: paulo@0: if (!file) paulo@0: return NULL; paulo@0: paulo@0: hash = sha1_hash_fread (file, size); paulo@0: paulo@0: return hash; paulo@0: } paulo@0: paulo@0: unsigned char *sha1_dup (const unsigned char *sha1) paulo@0: { paulo@0: unsigned char *new_sha1; paulo@0: paulo@0: if (!(new_sha1 = malloc (SHA1_BINSIZE))) paulo@0: return NULL; paulo@0: paulo@0: memcpy (new_sha1, sha1, SHA1_BINSIZE); paulo@0: paulo@0: return new_sha1; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: #if 0 paulo@0: #include paulo@0: paulo@0: int main (int argc, char **argv) paulo@0: { paulo@0: int i; paulo@0: paulo@0: for (i = 1; i < argc; i++) paulo@0: { paulo@0: unsigned char *bin; paulo@0: char *str; paulo@0: paulo@0: if (!(bin = sha1_digest (argv[i], 0))) paulo@0: { paulo@0: perror ("sha1_digest"); paulo@0: continue; paulo@0: } paulo@0: paulo@0: if ((str = sha1_string (bin))) paulo@0: printf ("%s\t%s\n", basename (argv[i]), str); paulo@0: paulo@0: free (str); paulo@0: free (bin); paulo@0: } paulo@0: paulo@0: return 0; paulo@0: } paulo@0: #endif