/* *****************************************************************
* sha.c
* © Copyright 1994 John Halleck
* All rights reserved
*
* --ABSTRACT-- sha.c
* This implements the "Secure Hash Algorithm" as per the original
* NIST specs, with the latest NIST version as an option.
*
* --KEYWORDS-- sha.c
*
* --CONTENTS-- sha.c
* Date, Department, Author
* 20may1994, John Halleck
* Revision history
* For each revision: Date, change summary, authorizing document,
* change department, section, author
* 3nov1999, Corrected padding bug.
* 20apr1995, change to default context option, John Halleck.
* 19nov1994, portablility changes, output string code.
* 1aug1994, Changes per NIST
* 20may1994, Initial Creation, John Halleck
* Unit purpose
* (What does this do?)
* Implements the "Secure Hash Algorithm" as proposed by NSA
* Unit function
* (How does it do it?)
* Straight forward reduction of the spec to code.
* External Units accessed
* Name, purpose, access summary
* Exceptions propagated by this unit
* [None]
* Input Output
* Device name, Access type, Access purpose, access summary
* [None]
* Machine-dependencies
* Access type, purpose, and justification
* Assumes a 32 bit word is availiable.
* Compiler-dependencies
* [None]
*******************************************************************
*/
#include <string.h>
#include "environ.h"
/* This code is independent of the byte order of the
* underlying machine. (Bigendian and Littleendian were
* bad enough, but when I started to deal with machines like
* the PDP-11 getting the order right became difficult without
* a redesign...
*/
/* Public part of this unit. */
#include "sha.h"
#ifndef NOPROTOTYPES
/* Private part of this unit */
void shapad (sha_context_ptr context);
void shaTransform (sha_context_ptr context);
void shaTransformCanned (void);
#endif
#define SHF_LENGTH_PAD 8
#define SHF_PAD_WORDS 2
/* Part of the padding needs to be message length (2 4 byte words) */
#define SHF_PADDING (SHF_BLOCKSIZE - SHF_LENGTH_PAD)
/* Remainder of block to be padded */
/* We have to exercise special care on machines with a natural
* wordlength >32 characters that we do masking properly
*/
#ifdef BITS32_GREATERTHAN_32
#define MASK32 & 0xFFFFFFFF
#define MASK8 & 0xFF
#else
#define MASK32
#define MASK8
#endif
int debugi; /* DEBUG */
static sha_context canned_context;
/* Place for contextless calls to have context. */
/* Implementation */
#ifdef NOPROTOTYPES
void shaInit (context, version)
sha_context_ptr context;
int version;
{
#else
void shaInit (sha_context_ptr context, int version) {
#endif
int loopindex;
if (!context) context = &canned_context;
/* Set initial values */
context->digest[0] = 0x67452301L;
context->digest[1] = 0xEFCDAB89L;
context->digest[2] = 0x98BADCFEL;
context->digest[3] = 0x10325476L;
context->digest[4] = 0xC3D2E1F0L;
/* Initialize bit count */
context->countLo = 0L;
context->countHi = 0L;
/* Initialize buffer to empty. */
context->thisword = 0;
context->thisbyte = 0;
/* Zero out data */
for (loopindex=0;loopindex<SHF_BLOCKWORDSIZE;loopindex++)
context->data[loopindex] = 0;
/* What sort of SHA are we doing? */
context->kind = version;
}
/*
****************************************************************
*/
/* Rotate Left n bits (32 bit) */
#define S(n,X) (((X)<<(n)) | ((X)>>(32-(n))))
#ifdef NOPROTOTYPES
static void shaTransform (context)
sha_context_ptr context;
{
#else
static void shaTransform (sha_context_ptr context) {
#endif
BITS32 W[80], temp; int i;
/* A buffer of 5 32-bit words */
BITS32 A, B, C, D, E;
#define DG context->digest
if (!context) context = &canned_context;
/* Get digest */
A = DG[0]; B = DG[1]; C = DG[2]; D = DG[3]; E = DG[4];
/* Copy the data buffer into the work buffer */
for (i=0; i<SHF_BLOCKWORDSIZE; i++)
{W[i] = context->data[i];context->data[i] = 0;}
/* Expand the 16 words into the SHF_BLOCKSIZE temporary data words */
for (i=16; i<80; i++) {
W[i] = W[i-3]^W[i-8]^W[i-14]^W[i-16];
if (context->kind) W[i] = S(1,W[i]);
}
/* Guts (four sub-rounds) */
#define PRE temp = W[i] + S(5,A) + E +
#define POST ; E = D; D = C; C = S(30,B); B = A; A = temp;
for (i= 0; i<20; i++) {PRE 0x5A827999L + (( B & C ) | (~B & D)) POST}
for (i=20; i<40; i++) {PRE 0x6ED9EBA1L + (B^C^D) POST}
for (i=40; i<60; i++) {PRE 0x8F1BBCDCL + ((B&C) | (B&D) | (C&D)) POST}
for (i=60; i<80; i++) {PRE 0xCA62C1D6L + (B^C^D) POST}
/* Update digest */
DG[0] += A; DG[1] += B; DG[2] += C; DG[3] += D; DG[4] += E;
#if BITS32_GREATERTHAN_32
DG[0] &= 0xFFFFFFFF;
DG[1] &= 0xFFFFFFFF;
DG[2] &= 0xFFFFFFFF;
DG[3] &= 0xFFFFFFFF;
DG[4] &= 0xFFFFFFFF;
#endif
/* Block is now empty */
context->thisword = 0;
context->thisbyte = 0;
}
/* ******************************* */
#ifdef NOPROTOTYPES
void shaUpdate (context, buffer, count)
sha_context_ptr context;
BITS8 *buffer;
int count;
{
#else
void shaUpdate (sha_context_ptr context, BITS8 *buffer, int count) {
#endif
BITS32 thebits; /* current bit pattern being processed */
int theword; /* Which word in the buffer we are dealing with. */
int i;
if (!context) context = &canned_context;
/* Add a potentially 32 bit count to the two word count */
context->countHi += count >> 29; /* handle count > 2**29 */
context->countLo += count & 0x1FFFFFFF; /* Handle count <=2**29 */
context->countHi += context->countLo >> 29;/* Handle carry */
context->countLo &= 0x1FFFFFFF; /* Clear carry */
theword = context->thisword;
thebits = context->data[theword];
while (count--) {
thebits = (thebits << 8) | *buffer++;
if (++context->thisbyte >= 4) {
context->data[theword++] = thebits; thebits = 0;
if (theword >= SHF_BLOCKWORDSIZE) {
shaTransform (context);
theword = 0;
}
context->thisbyte = 0;
}
}
context->data[theword] = thebits;
context->thisword = theword;
}
/* ************************************ */
#ifdef NOPROTOTYPES
void shaStrUpdate (context, input)
sha_context_ptr context;
char *input;
#else
void shaStrUpdate (sha_context_ptr context, char *input)
#endif
{shaUpdate (context, (BITS8 *)input, strlen(input));}
/* ************************************ */
/* Pad out a block. */
#ifdef NOPROTOTYPES
static void shapad(context)
sha_context_ptr context;
{
#else
static void shapad(sha_context_ptr context) {
#endif
int loopindex;
if (!context) context = &canned_context;
context->data[context->thisword]<<=8;
context->data[context->thisword] |= 0x80;
/* pad out the rest of this word */
switch (context->thisbyte) {
case 3: ;break;
case 2: context->data[context->thisword]<<= 8;break;
case 1: context->data[context->thisword]<<=16;break;
case 0: context->data[context->thisword]<<=24;break;
}
/* and then the rest of the words in the block */
for (loopindex=context->thisword + 1; loopindex < SHF_BLOCKWORDSIZE;loopindex++)
context->data[loopindex] = 0;
/* And note it is now empty */
context->thisword = 0; context->thisbyte = 0;
}
/* ************************************ */
/* Convert a word digest to bytes, in a byte order independent manner */
#ifdef NOPROTOTYPES
void shaBytes (context, adigest)
sha_context_ptr context;
sha_digest adigest;
{
#else
void shaBytes (sha_context_ptr context, sha_digest adigest) {
#endif
int loopindex;
if (!context) context = &canned_context;
for (loopindex=0;loopindex<SHF_DIGESTWORDSIZE;loopindex++) {
*adigest++ = (BITS8) (context->digest[loopindex] >> 24 MASK8);
*adigest++ = (BITS8) (context->digest[loopindex] >> 16 & (BITS32) 0xFF);
*adigest++ = (BITS8) (context->digest[loopindex] >> 8 & (BITS32) 0xFF);
*adigest++ = (BITS8) (context->digest[loopindex] & (BITS32) 0xFF);
}
}
/* ************************************ */
#ifdef NOPROTOTYPES
void shaString (adigest, outputstring)
sha_digest adigest;
char *outputstring;
{
#else
void shaString (sha_digest adigest, char *outputstring) {
#endif
char output [17];
int loop; int abyte;
strcpy (output, "0123456789ABCDEF");
for (loop = 0; loop < SHF_DIGESTSIZE; loop++) {
abyte = *adigest++;
*outputstring++ = output [ (abyte >> 4) & 0xF ];
*outputstring++ = output [ abyte & 0xF ];
}
*outputstring = 0;
}
/* ************************************ */
#ifdef NOPROTOTYPES
void shaFinal(context, adigest)
sha_context_ptr context;
sha_digest adigest;
{
#else
void shaFinal (sha_context_ptr context, sha_digest adigest) {
#endif
int loopindex; int bytesused;
if (!context) context = &canned_context;
/* bytes used in the buffer */
bytesused = context->thisword * 4 + context->thisbyte + 2;
/* +1 for un zerobasing, +1 for the pad character we're about to do */
/* Pad, but with the convention that the 0 pad starts with a single */
/* one bit. */
shapad(context);
/* if we don't have room for the message size, then start a new block */
if (bytesused > (SHF_BLOCKSIZE - SHF_LENGTH_PAD)) {
shaTransform(context);
for (loopindex=0; loopindex<(SHF_BLOCKWORDSIZE-SHF_PAD_WORDS); loopindex++)
context->data[loopindex] = 0;
context->thisword = SHF_BLOCKWORDSIZE;
context->thisbyte = 0;
}
/* Append length in bits, and transform */
context->data[14] = context->countHi;
context->data[15] = context->countLo<<3; /* We keep it as a byte count */
shaTransform (context);
/* get the digest out to the user. */
shaBytes (context, adigest);
} /* end routine shaFinal */
/* ************************************************************ */
#ifdef NOPROTOTYPES
void shaHash (version, buffer, count, adigest)
int version;
BITS8 *buffer;
int count;
sha_digest adigest;
{
#else
void shaHash (int version, BITS8 *buffer, int count, sha_digest adigest) {
#endif
sha_context example;
shaInit (&example, version);
shaUpdate (&example, buffer, count);
shaFinal (&example, adigest);
}
/* end sha.c **************************************************** */
This page is http://www.cc.utah.edu/~nahaj/c/sha/sha.c.html
© Copyright 2000 by John Halleck, All Rights Reserved.
This snapshot was last modified on August 23rd, 2000
And the underlying file was last modified on May 30th, 2000