/* * Copyright Ó 1992 by Xerox Corporation. All rights reserved. * September 30, 1992 * A straightforward implementation of the proposed Secure * Hash Standard (SHS), dated 22 January 1992. * * To use: allocate an SHS_CTX and pass it to SHSInit; * repeatedly call SHSUpdate on successive chunks of the message * then call SHSFinal(hash, ctx). * The hash is in ctx->state, as 4 byte integers * and, properly reorganized for endian-ness, in *hash. * */ #include "SHS.h" static void onem(); static char endianTest[4] = {0, 0, 0, 1}; static int littleEndian; static void intFromChars(); void SHSInit (ctx) SHS_CTX *ctx; { int testInt; intFromChars( &testInt, endianTest ); littleEndian = (*((int *)endianTest)==1 ? 0 : 1); ctx->state[0] = 0x67452301; ctx->state[1] = 0x0efcdab89; ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476; ctx->state[4] = 0x0c3d2e1f0; ctx->count[0] = 0; ctx->count[1] = 0; } void SHSUpdate (ctx, bytes, nBytes) SHS_CTX *ctx; unsigned char *bytes; unsigned int nBytes; { unsigned int inBuffer = (unsigned int)((ctx->count[1]/8) % 64); /* number of bytes left in buffer from previous call */ unsigned int inp = 0; if ((ctx->count[1] += ((UINT4)nBytes << 3)) < ((UINT4)nBytes << 3)) ctx->count[0]++; ctx->count[0] += ((UINT4)nBytes >> 29); if (inBuffer != 0) { if ((inBuffer+nBytes) >= 64) { bcopy( bytes, &ctx->buffer[inBuffer], inp=(64-inBuffer) ); onem( ctx->buffer, ctx->state ); inBuffer=0; } }; while (inp+64 <= nBytes ) { onem( bytes[inp], ctx->state ); inp += 64; }; bcopy( bytes+inp, &(ctx->buffer[inBuffer]), nBytes-inp ); } static void charsFromInt ( p, i ) unsigned char *p; unsigned int i; { int j; for (j = 3 ; j>=0; j--) { p[j] = i % 256; i = i / 256; } } static void intFromChars (i, p) unsigned int *i; unsigned char *p; { unsigned int sum = 0; unsigned int j; for (j = 0 ; j<4; j++) { sum = (sum)*256 + p[j]; }; *i = sum; } void SHSFinal ( hash, ctx ) unsigned char hash[20]; SHS_CTX *ctx; { unsigned char countAsChars[8]; unsigned int inBuffer; unsigned char terminator = 0x80; /* number of bytes left in buffer from previous call */ charsFromInt(&(countAsChars[0]), ctx->count[0]); charsFromInt(&(countAsChars[4]), ctx->count[1]); SHSUpdate( ctx, &terminator, 1 ); inBuffer = (unsigned int)((ctx->count[1]/8) % 64); if (inBuffer > 64-8) { bzero(&(ctx->buffer[inBuffer]), 64-inBuffer); onem( ctx->buffer, ctx->state ); inBuffer = 0; }; bzero(&(ctx->buffer[inBuffer]), (64-8)-inBuffer); bcopy(countAsChars, &(ctx->buffer[64-8]), 8); onem( ctx->buffer, ctx->state ); { unsigned int i; char *p; for ((i=0, p=(char *)hash); i<5; (i++, p += 4)) { charsFromInt( p, ctx->state[i] ); } } } #define S5(x) (((x)<<5) | ((x)>>27)) #define S30(x) (((x)<<30) | ((x)>>2)) #define K0 0x5a827999 #define K1 0x6ed9eba1 #define K2 0x8f1bbcdc #define K3 0x0ca62c1d6 #define AND(x,y) ((x)&(y)) #define F0(x,y,z) (AND(x,y) | AND(~(x),z)) #define F1(x,y,z) ((x)^(y)^(z)) #define F2(x,y,z) (AND(x,y) | AND(x,z) | AND(y,z)) #define word unsigned long static void onem(m, h) word m[16]; word h[5]; { word w[80]; int t; word A, B, C, D, E; word *p, *q; word *pm3, *pm8, *pm14, *pm16; word temp; int i; if (littleEndian) for (i=0; i < 16; i++ ) { intFromChars(&(m[i]), &(m[i]) ); }; A = h[0]; B=h[1]; C=h[2]; D=h[3]; E=h[4]; for (p = m, q=w; p < m+16; p++, q++) { *q = *p; } pm3 = w+13; pm8 = w+8; pm14=w+2; pm16=w; for (p=w+16; p < w+80; p++, pm3++, pm8++, pm14++, pm16++) { *p = *pm3 ^ *pm8 ^ *pm14 ^ *pm16; } for (i=0; i<20; i++) { temp = S5(A) + F0(B,C,D) + E + w[i] + K0; E=D; D=C; C=S30(B); B=A; A=temp; } for (i=20; i<40; i++) { temp = S5(A) + F1(B,C,D) + E + w[i] + K1; E=D; D=C; C=S30(B); B=A; A=temp; } for (i=40; i<60; i++) { temp = S5(A) + F2(B,C,D) + E + w[i] + K2; E=D; D=C; C=S30(B); B=A; A=temp; } for (i=60; i<80; i++) { temp = S5(A) + F1(B,C,D) + E + w[i] + K3; E=D; D=C; C=S30(B); B=A; A=temp; } h[0]=h[0]+A; h[1]=h[1]+B; h[2]=h[2]+C; h[3]=h[3]+D; h[4]=h[4]+E; }