Check-in [5ebe069cbf]
Overview
Comment:Started work on an internal sha1 implementation
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | internal_sha1
Files: files | file ages | folders
SHA1:5ebe069cbf84ca6b68349f8378c0913ae7015b72
User & Date: rkeene on 2014-11-03 23:16:49
Other Links: manifest | tags
Context
2014-11-06
00:37
Merged in updates from trunk check-in: ee9eb7ed98 user: rkeene tags: internal_sha1
2014-11-03
23:16
Started work on an internal sha1 implementation check-in: 5ebe069cbf user: rkeene tags: internal_sha1
22:59
Updated to complain if hash cannot be computed check-in: 0cefa306d2 user: rkeene tags: trunk
Changes

Added sha1.c version [633b35595f].

            1  +/* This code is public-domain - it is based on libcrypt
            2  + * placed in the public domain by Wei Dai and other contributors.
            3  + */
            4  +/* http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c */
            5  +
            6  +#include <tcl.h>
            7  +#include <sys/types.h>
            8  +#include <sys/stat.h>
            9  +#include <unistd.h>
           10  +#include <stdint.h>
           11  +#include <string.h>
           12  +#include <fcntl.h>
           13  +
           14  +#ifdef __BIG_ENDIAN__
           15  +#	define SHA_BIG_ENDIAN
           16  +#elif defined __LITTLE_ENDIAN__
           17  +#elif defined __BYTE_ORDER
           18  +# if __BYTE_ORDER__ ==  __ORDER_BIG_ENDIAN__
           19  +# define SHA_BIG_ENDIAN
           20  +# endif
           21  +#else /* ! defined __LITTLE_ENDIAN__ */
           22  +# include <endian.h> /* machine/endian.h */
           23  +# if __BYTE_ORDER__ ==  __ORDER_BIG_ENDIAN__
           24  +#  define SHA_BIG_ENDIAN
           25  +# endif
           26  +#endif
           27  +
           28  +/* header */
           29  +#define HASH_LENGTH 20
           30  +#define BLOCK_LENGTH 64
           31  +
           32  +typedef struct sha1info {
           33  +	uint32_t buffer[BLOCK_LENGTH / 4];
           34  +	uint32_t state[HASH_LENGTH / 4];
           35  +	uint32_t byteCount;
           36  +	uint8_t bufferOffset;
           37  +	uint8_t keyBuffer[BLOCK_LENGTH];
           38  +	uint8_t innerHash[HASH_LENGTH];
           39  +} sha1info;
           40  +
           41  +/* public API - prototypes - TODO: doxygen*/
           42  +
           43  +/**
           44  + */
           45  +static void sha1_init(sha1info *s);
           46  +/**
           47  + */
           48  +static void sha1_writebyte(sha1info *s, uint8_t data);
           49  +/**
           50  + */
           51  +static void sha1_write(sha1info *s, const char *data, size_t len);
           52  +/**
           53  + */
           54  +static uint8_t *sha1_result(sha1info *s);
           55  +/**
           56  + */
           57  +static void sha1_initHmac(sha1info *s, const uint8_t *key, int keyLength);
           58  +/**
           59  + */
           60  +static uint8_t *sha1_resultHmac(sha1info *s);
           61  +
           62  +/* code */
           63  +#define SHA1_K0  0x5a827999
           64  +#define SHA1_K20 0x6ed9eba1
           65  +#define SHA1_K40 0x8f1bbcdc
           66  +#define SHA1_K60 0xca62c1d6
           67  +
           68  +static void sha1_init(sha1info *s) {
           69  +	s->state[0] = 0x67452301;
           70  +	s->state[1] = 0xefcdab89;
           71  +	s->state[2] = 0x98badcfe;
           72  +	s->state[3] = 0x10325476;
           73  +	s->state[4] = 0xc3d2e1f0;
           74  +	s->byteCount = 0;
           75  +	s->bufferOffset = 0;
           76  +}
           77  +
           78  +static uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
           79  +	return ((number << bits) | (number >> (32 - bits)));
           80  +}
           81  +
           82  +static void sha1_hashBlock(sha1info *s) {
           83  +	uint8_t i;
           84  +	uint32_t a, b, c, d, e, t;
           85  +
           86  +	a = s->state[0];
           87  +	b = s->state[1];
           88  +	c = s->state[2];
           89  +	d = s->state[3];
           90  +	e = s->state[4];
           91  +	for (i = 0; i < 80; i++) {
           92  +		if (i >= 16) {
           93  +			t = s->buffer[(i + 13) & 15] ^ s->buffer[(i + 8) & 15] ^ s->buffer[(i + 2) & 15] ^ s->buffer[i & 15];
           94  +			s->buffer[i & 15] = sha1_rol32(t, 1);
           95  +		}
           96  +		if (i < 20) {
           97  +			t = (d ^ (b & (c ^ d))) + SHA1_K0;
           98  +		} else if (i < 40) {
           99  +			t = (b ^ c ^ d) + SHA1_K20;
          100  +		} else if (i < 60) {
          101  +			t = ((b & c) | (d & (b | c))) + SHA1_K40;
          102  +		} else {
          103  +			t = (b ^ c ^ d) + SHA1_K60;
          104  +		}
          105  +		t += sha1_rol32(a, 5) + e + s->buffer[i & 15];
          106  +		e = d;
          107  +		d = c;
          108  +		c = sha1_rol32(b, 30);
          109  +		b = a;
          110  +		a = t;
          111  +	}
          112  +	s->state[0] += a;
          113  +	s->state[1] += b;
          114  +	s->state[2] += c;
          115  +	s->state[3] += d;
          116  +	s->state[4] += e;
          117  +}
          118  +
          119  +static void sha1_addUncounted(sha1info *s, uint8_t data) {
          120  +	uint8_t * const b = (uint8_t *) s->buffer;
          121  +#ifdef SHA_BIG_ENDIAN
          122  +	b[s->bufferOffset] = data;
          123  +#else
          124  +	b[s->bufferOffset ^ 3] = data;
          125  +#endif
          126  +	s->bufferOffset++;
          127  +	if (s->bufferOffset == BLOCK_LENGTH) {
          128  +		sha1_hashBlock(s);
          129  +		s->bufferOffset = 0;
          130  +	}
          131  +}
          132  +
          133  +static void sha1_writebyte(sha1info *s, uint8_t data) {
          134  +	++s->byteCount;
          135  +	sha1_addUncounted(s, data);
          136  +}
          137  +
          138  +static void sha1_write(sha1info *s, const char *data, size_t len) {
          139  +	for (; len--; ) {
          140  +		sha1_writebyte(s, (uint8_t) *data++);
          141  +	}
          142  +}
          143  +
          144  +static void sha1_pad(sha1info *s) {
          145  +	/* Implement SHA-1 padding (fips180-2 ยง5.1.1) */
          146  +
          147  +	/* Pad with 0x80 followed by 0x00 until the end of the block */
          148  +	sha1_addUncounted(s, 0x80);
          149  +	while (s->bufferOffset != 56) {
          150  +		sha1_addUncounted(s, 0x00);
          151  +	}
          152  +
          153  +	/* Append length in the last 8 bytes */
          154  +	sha1_addUncounted(s, 0); /* We're only using 32 bit lengths */
          155  +	sha1_addUncounted(s, 0); /* But SHA-1 supports 64 bit lengths */
          156  +	sha1_addUncounted(s, 0); /* So zero pad the top bits */
          157  +	sha1_addUncounted(s, s->byteCount >> 29); /* Shifting to multiply by 8 */
          158  +	sha1_addUncounted(s, s->byteCount >> 21); /* as SHA-1 supports bitstreams as well as */
          159  +	sha1_addUncounted(s, s->byteCount >> 13); /* byte. */
          160  +	sha1_addUncounted(s, s->byteCount >> 5);
          161  +	sha1_addUncounted(s, s->byteCount << 3);
          162  +}
          163  +
          164  +static uint8_t *sha1_result(sha1info *s) {
          165  +	int i;
          166  +
          167  +	/* Pad to complete the last block */
          168  +	sha1_pad(s);
          169  +
          170  +#ifndef SHA_BIG_ENDIAN
          171  +	/* Swap byte order back */
          172  +	for (i = 0; i < 5; i++) {
          173  +		s->state[i]=
          174  +			  (((s->state[i]) << 24) & 0xff000000)
          175  +			| (((s->state[i]) <<  8) & 0x00ff0000)
          176  +			| (((s->state[i]) >>  8) & 0x0000ff00)
          177  +			| (((s->state[i]) >> 24) & 0x000000ff);
          178  +	}
          179  +#endif
          180  +	/* Return pointer to hash (20 characters) */
          181  +	return((uint8_t *) s->state);
          182  +}
          183  +
          184  +#define HMAC_IPAD 0x36
          185  +#define HMAC_OPAD 0x5c
          186  +
          187  +static void sha1_initHmac(sha1info *s, const uint8_t *key, int keyLength) {
          188  +	uint8_t i;
          189  +
          190  +	memset(s->keyBuffer, 0, BLOCK_LENGTH);
          191  +	if (keyLength > BLOCK_LENGTH) {
          192  +		/* Hash long keys */
          193  +		sha1_init(s);
          194  +		for (; keyLength--; ) {
          195  +			sha1_writebyte(s, *key++);
          196  +		}
          197  +		memcpy(s->keyBuffer, sha1_result(s), HASH_LENGTH);
          198  +	} else {
          199  +		/* Block length keys are used as is */
          200  +		memcpy(s->keyBuffer, key, keyLength);
          201  +	}
          202  +
          203  +	/* Start inner hash */
          204  +	sha1_init(s);
          205  +	for (i=0; i<BLOCK_LENGTH; i++) {
          206  +		sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_IPAD);
          207  +	}
          208  +
          209  +	return;
          210  +}
          211  +
          212  +static uint8_t *sha1_resultHmac(sha1info *s) {
          213  +	uint8_t i;
          214  +
          215  +	/* Complete inner hash */
          216  +	memcpy(s->innerHash, sha1_result(s), HASH_LENGTH);
          217  +
          218  +	/* Calculate outer hash */
          219  +	sha1_init(s);
          220  +
          221  +	for (i = 0; i < BLOCK_LENGTH; i++) {
          222  +		sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_OPAD);
          223  +	}
          224  +	for (i = 0; i < HASH_LENGTH; i++) {
          225  +		sha1_writebyte(s, s->innerHash[i]);
          226  +	}
          227  +
          228  +	return(sha1_result(s));
          229  +}
          230  +
          231  +static Tcl_Obj* c_sha1__sha1_file(char* file) {
          232  +
          233  +	sha1info sha1;
          234  +	uint8_t buf[4096];
          235  +	int fd;
          236  +	ssize_t read_ret;
          237  +	Tcl_Obj *ret;
          238  +
          239  +	fd = open(file, O_RDONLY);
          240  +	if (fd < 0) {
          241  +		return(NULL);
          242  +	}
          243  +
          244  +	sha1_init(&sha1);
          245  +
          246  +	while (1) {
          247  +		read_ret = read(fd, buf, sizeof(buf));
          248  +
          249  +		if (read_ret == 0) {
          250  +			break;
          251  +		}
          252  +
          253  +		if (read_ret < 0) {
          254  +			close(fd);
          255  +
          256  +			return(NULL);
          257  +		}
          258  +
          259  +		sha1_write(&sha1, buf, read_ret);
          260  +	}
          261  +
          262  +	close(fd);
          263  +
          264  +	sha1_result(&sha1);
          265  +
          266  +	ret = Tcl_NewByteArrayObj(sha1_result(&sha1), HASH_LENGTH);
          267  +
          268  +	return(ret);
          269  +}
          270  +
          271  +static int tcl_sha1__sha1_file(ClientData dummy, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[]) {
          272  +	char* _file;
          273  +	Tcl_Obj* rv;
          274  +	if (objc != 2) {
          275  +		Tcl_WrongNumArgs(ip, 1, objv, "file");
          276  +		return TCL_ERROR;
          277  +	}
          278  +	_file = Tcl_GetString(objv[1]);
          279  +
          280  +	rv = c_sha1__sha1_file(_file);
          281  +	if (rv == NULL) {
          282  +		return(TCL_ERROR);
          283  +	}
          284  +	Tcl_SetObjResult(ip, rv); Tcl_DecrRefCount(rv);
          285  +	return TCL_OK;
          286  +}
          287  +
          288  +static Tcl_Obj* c_sha1__sha1_string(Tcl_Obj* str) {
          289  +
          290  +	sha1info sha1;
          291  +	unsigned char *buf;
          292  +	int buf_len;
          293  +	Tcl_Obj *ret;
          294  +
          295  +	sha1_init(&sha1);
          296  +
          297  +	buf = Tcl_GetByteArrayFromObj(str, &buf_len);
          298  +	if (buf == NULL) {
          299  +		return(NULL);
          300  +	}
          301  +
          302  +	sha1_write(&sha1, buf, buf_len);
          303  +
          304  +	sha1_result(&sha1);
          305  +
          306  +	ret = Tcl_NewByteArrayObj(sha1_result(&sha1), HASH_LENGTH);
          307  +
          308  +	return(ret);
          309  +}
          310  +
          311  +static int tcl_sha1__sha1_string(ClientData dummy, Tcl_Interp *ip, int objc, Tcl_Obj *CONST objv[]) {
          312  +	Tcl_Obj* _str;
          313  +	Tcl_Obj* rv;
          314  +	if (objc != 2) {
          315  +		Tcl_WrongNumArgs(ip, 1, objv, "str");
          316  +		return TCL_ERROR;
          317  +	}
          318  +	_str = objv[1];
          319  +
          320  +	rv = c_sha1__sha1_string(_str);
          321  +	if (rv == NULL) {
          322  +		return(TCL_ERROR);
          323  +	}
          324  +	Tcl_SetObjResult(ip, rv); Tcl_DecrRefCount(rv);
          325  +	return TCL_OK;
          326  +}
          327  +
          328  +int Sha1_Init(Tcl_Interp *interp) {
          329  +#ifdef USE_TCL_STUBS
          330  +	if (Tcl_InitStubs(interp, TCL_VERSION, 0) == 0L) {
          331  +		return TCL_ERROR;
          332  +	}
          333  +#endif
          334  +	Tcl_CreateObjCommand(interp, "sha1::_sha1_file", tcl_sha1__sha1_file, NULL, NULL);
          335  +	Tcl_CreateObjCommand(interp, "sha1::_sha1_string", tcl_sha1__sha1_string, NULL, NULL);
          336  +	Tcl_PkgProvide(interp, "sha1", "1.0");
          337  +	return(TCL_OK);
          338  +}