You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
9.2 KiB
293 lines
9.2 KiB
#pragma once
|
|
|
|
/*
|
|
SHA-1 in C
|
|
By Steve Reid <steve@edmweb.com>
|
|
100% Public Domain
|
|
*/
|
|
|
|
using uint32_t = unsigned int;
|
|
|
|
typedef struct _sha1_ctx
|
|
{
|
|
uint32_t state[ 5 ];
|
|
uint32_t count[ 2 ];
|
|
unsigned char buffer[ 64 ];
|
|
} sha1_ctx, *psha1_ctx;
|
|
|
|
void sha1_transform( uint32_t state[ 5 ], const unsigned char buffer[ 64 ] );
|
|
|
|
void sha1_init( sha1_ctx *context );
|
|
|
|
void sha1_update( sha1_ctx *context, const unsigned char *data, uint32_t len );
|
|
|
|
void sha1_final( unsigned char digest[ 20 ], sha1_ctx *context );
|
|
|
|
void sha1( char *hash_out, const char *str, int len );
|
|
|
|
#define SHA1HANDSOFF
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#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 */
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
#define blk0( i ) \
|
|
( block->l[ i ] = ( rol( block->l[ i ], 24 ) & 0xFF00FF00 ) | ( rol( block->l[ i ], 8 ) & 0x00FF00FF ) )
|
|
#elif BYTE_ORDER == BIG_ENDIAN
|
|
#define blk0( i ) block->l[ i ]
|
|
#else
|
|
#error "Endianness not defined!"
|
|
#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 );
|
|
|
|
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
|
|
|
inline void sha1_transform( uint32_t state[ 5 ], const unsigned char buffer[ 64 ] )
|
|
{
|
|
uint32_t a, b, c, d, e;
|
|
|
|
typedef union
|
|
{
|
|
unsigned char c[ 64 ];
|
|
uint32_t l[ 16 ];
|
|
} CHAR64LONG16;
|
|
|
|
#ifdef SHA1HANDSOFF
|
|
CHAR64LONG16 block[ 1 ]; /* use array to appear as a pointer */
|
|
|
|
memcpy( block, buffer, 64 );
|
|
#else
|
|
/* The following had better never be used because it causes the
|
|
* pointer-to-const buffer to be cast into a pointer to non-const.
|
|
* And the result is written through. I threw a "const" in, hoping
|
|
* this will cause a diagnostic.
|
|
*/
|
|
CHAR64LONG16 *block = ( const CHAR64LONG16 * )buffer;
|
|
#endif
|
|
/* 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;
|
|
#ifdef SHA1HANDSOFF
|
|
memset( block, '\0', sizeof( block ) );
|
|
#endif
|
|
}
|
|
|
|
/* SHA1Init - Initialize new context */
|
|
|
|
inline void sha1_init( sha1_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;
|
|
}
|
|
|
|
/* Run your data through this. */
|
|
|
|
inline void sha1_update( sha1_ctx *context, const unsigned char *data, uint32_t len )
|
|
{
|
|
uint32_t i;
|
|
|
|
uint32_t j;
|
|
|
|
j = context->count[ 0 ];
|
|
if ( ( context->count[ 0 ] += len << 3 ) < j )
|
|
context->count[ 1 ]++;
|
|
context->count[ 1 ] += ( len >> 29 );
|
|
j = ( j >> 3 ) & 63;
|
|
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 );
|
|
}
|
|
|
|
/* Add padding and return the message digest. */
|
|
|
|
inline void sha1_final( unsigned char digest[ 20 ], sha1_ctx *context )
|
|
{
|
|
unsigned i;
|
|
|
|
unsigned char finalcount[ 8 ];
|
|
|
|
unsigned char c;
|
|
|
|
#if 0 /* untested "improvement" by DHR */
|
|
/* Convert context->count to a sequence of bytes
|
|
* in finalcount. Second element first, but
|
|
* big-endian order within element.
|
|
* But we do it all backwards.
|
|
*/
|
|
unsigned char* fcp = &finalcount[8];
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
uint32_t t = context->count[i];
|
|
|
|
int j;
|
|
|
|
for (j = 0; j < 4; t >>= 8, j++)
|
|
*--fcp = (unsigned char)t
|
|
}
|
|
#else
|
|
for ( i = 0; i < 8; i++ )
|
|
{
|
|
finalcount[ i ] = ( unsigned char )( ( context->count[ ( i >= 4 ? 0 : 1 ) ] >> ( ( 3 - ( i & 3 ) ) * 8 ) ) &
|
|
255 ); /* Endian independent */
|
|
}
|
|
#endif
|
|
c = 0200;
|
|
sha1_update( context, &c, 1 );
|
|
while ( ( context->count[ 0 ] & 504 ) != 448 )
|
|
{
|
|
c = 0000;
|
|
sha1_update( context, &c, 1 );
|
|
}
|
|
sha1_update( context, finalcount, 8 ); /* Should cause a SHA1Transform() */
|
|
for ( i = 0; i < 20; i++ )
|
|
{
|
|
digest[ i ] = ( unsigned char )( ( context->state[ i >> 2 ] >> ( ( 3 - ( i & 3 ) ) * 8 ) ) & 255 );
|
|
}
|
|
/* Wipe variables */
|
|
memset( context, '\0', sizeof( *context ) );
|
|
memset( &finalcount, '\0', sizeof( finalcount ) );
|
|
}
|
|
|
|
inline void sha1( char *hash_out, const char *str, int len )
|
|
{
|
|
sha1_ctx ctx;
|
|
unsigned int ii;
|
|
|
|
sha1_init( &ctx );
|
|
for ( ii = 0; ii < len; ii += 1 )
|
|
sha1_update( &ctx, ( const unsigned char * )str + ii, 1 );
|
|
sha1_final( ( unsigned char * )hash_out, &ctx );
|
|
hash_out[ 20 ] = '\0';
|
|
} |