home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
crypl200.zip
/
LIB_SHA.C
< prev
next >
Wrap
Text File
|
1996-09-29
|
8KB
|
280 lines
/****************************************************************************
* *
* cryptlib SHA Hash Routines *
* Copyright Peter Gutmann 1992-1996 *
* *
****************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypt.h"
#ifdef INC_ALL
#include "sha.h"
#else
#include "hash/sha.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* SHA Self-test Routines *
* *
****************************************************************************/
/* Test the SHA output against the test vectors given in FIPS 180 and FIPS
180-1 (the first three values are the SHA results, the second three are
the SHA1 results).
We skip the third test since this takes several seconds to execute, which
leads to an unacceptable delay in the library startup time */
void shaHashBuffer( void *hashInfo, BYTE *outBuffer, BYTE *inBuffer,
int length, const HASH_STATE hashState );
static struct {
char *data; /* Data to hash */
int length; /* Length of data */
BYTE digest[ SHA_DIGESTSIZE ]; /* Digest of data */
} digestValues[] = {
{ "abc", 3,
{ 0x01, 0x64, 0xB8, 0xA9, 0x14, 0xCD, 0x2A, 0x5E,
0x74, 0xC4, 0xF7, 0xFF, 0x08, 0x2C, 0x4D, 0x97,
0xF1, 0xED, 0xF8, 0x80 } },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
{ 0xD2, 0x51, 0x6E, 0xE1, 0xAC, 0xFA, 0x5B, 0xAF,
0x33, 0xDF, 0xC1, 0xC4, 0x71, 0xE4, 0x38, 0x44,
0x9E, 0xF1, 0x34, 0xC8 } },
/* { "aaaaa...", 1000000L,
{ 0x32, 0x32, 0xAF, 0xFA, 0x48, 0x62, 0x8A, 0x26,
0x65, 0x3B, 0x5A, 0xAA, 0x44, 0x54, 0x1F, 0xD9,
0x0D, 0x69, 0x06, 0x03 } }, */
{ "abc", 3,
{ 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A,
0xBA, 0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C,
0x9C, 0xD0, 0xD8, 0x9D } },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
0xE5, 0x46, 0x70, 0xF1 } },
/* { "aaaaa...", 1000000L,
{ 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4,
0xF6, 0x1E, 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31,
0x65, 0x34, 0x01, 0x6F } }, */
{ NULL, 0, { 0 } }
};
int shaSelfTest( void )
{
SHA_INFO shaInfo;
BYTE digest[ SHA_DIGESTSIZE ], *digestPtr;
int i;
/* Test SHA against the test vectors given in FIPS 180. We can't use the
internal shaHashBuffer() API for this since it defaults to SHA-1, so
we duplicate the functionality of shaHashBuffer() here */
shaInitial( &shaInfo );
shaUpdate( &shaInfo, ( BYTE * ) digestValues[ 0 ].data,
digestValues[ 0 ].length );
shaFinal( &shaInfo );
digestPtr = digest;
for( i = 0; i < SHA_DIGESTSIZE / 4; i++ )
{
mputBLong( digestPtr, shaInfo.digest[ i ] );
}
if( memcmp( digest, digestValues[ 0 ].digest, SHA_DIGESTSIZE ) )
return( CRYPT_SELFTEST );
shaInitial( &shaInfo );
shaUpdate( &shaInfo, ( BYTE * ) digestValues[ 1 ].data,
digestValues[ 1 ].length );
shaFinal( &shaInfo );
digestPtr = digest;
for( i = 0; i < SHA_DIGESTSIZE / 4; i++ )
{
mputBLong( digestPtr, shaInfo.digest[ i ] );
}
if( memcmp( digest, digestValues[ 1 ].digest, SHA_DIGESTSIZE ) )
return( CRYPT_SELFTEST );
/* Test SHA against values given in FIPS 180-1 */
for( i = 2; digestValues[ i ].data != NULL; i++ )
{
shaHashBuffer( NULL, digest, ( BYTE * ) digestValues[ i ].data,
digestValues[ i ].length, HASH_ALL );
if( memcmp( digest, digestValues[ i ].digest, SHA_DIGESTSIZE ) )
return( CRYPT_SELFTEST );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Init/Shutdown Routines *
* *
****************************************************************************/
/* Perform auxiliary init and shutdown actions on an encryption context */
int shaInitEx( CRYPT_INFO *cryptInfo, void *cryptInfoEx )
{
CRYPT_INFO_SHA *cryptInfoExPtr = ( CRYPT_INFO_SHA * ) cryptInfoEx;
int status;
/* Allocate memory for the SHA context within the encryption context */
if( cryptInfo->privateData != NULL )
return( CRYPT_INITED );
if( ( status = secureMalloc( &cryptInfo->privateData, sizeof( SHA_INFO ) ) ) != CRYPT_OK )
return( status );
if( cryptInfoExPtr->isSHA == CRYPT_USE_DEFAULT )
{
cryptInfo->privateUseDefaults = TRUE;
setSHAinfo( cryptInfo, FALSE );
}
else
setSHAinfo( cryptInfo, ( BOOLEAN ) cryptInfoExPtr->isSHA );
if( ( ( SHA_INFO * ) cryptInfo->privateData )->isSHA )
shaInitial( ( SHA_INFO * ) cryptInfo->privateData );
else
sha1Initial( ( SHA_INFO * ) cryptInfo->privateData );
return( CRYPT_OK );
}
int shaInit( CRYPT_INFO *cryptInfo )
{
CRYPT_INFO_SHA cryptInfoEx;
/* Use SHA1 */
memset( &cryptInfoEx, 0, sizeof( CRYPT_INFO_SHA ) );
cryptInfoEx.isSHA = CRYPT_USE_DEFAULT;
/* Pass through to the extended setup routine */
return( shaInitEx( cryptInfo, &cryptInfoEx ) );
}
int shaEnd( CRYPT_INFO *cryptInfo )
{
/* Free any allocated memory */
secureFree( &cryptInfo->privateData );
return( CRYPT_OK );
}
/****************************************************************************
* *
* SHA Hash Routines *
* *
****************************************************************************/
/* Hash data using SHA */
int shaHash( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
{
SHA_INFO *shaInfo = ( SHA_INFO * ) cryptInfo->privateData;
/* If we've already called shaFinal(), we can't continue */
if( shaInfo->done )
return( CRYPT_COMPLETE );
if( !noBytes )
{
if( shaInfo->isSHA )
shaFinal( shaInfo );
else
sha1Final( shaInfo );
}
else
{
if( shaInfo->isSHA )
shaUpdate( shaInfo, buffer, noBytes );
else
sha1Update( shaInfo, buffer, noBytes );
}
return( CRYPT_OK );
}
/* Retrieve the hash value */
int shaGetData( CRYPT_INFO *cryptInfo, BYTE *buffer )
{
SHA_INFO *shaInfo = ( SHA_INFO * ) cryptInfo->privateData;
int i;
/* Extract the digest into the memory buffer */
for( i = 0; i < SHA_DIGESTSIZE / 4; i++ )
{
mputBLong( buffer, shaInfo->digest[ i ] );
}
return( ( shaInfo->done ) ? CRYPT_OK : CRYPT_INCOMPLETE );
}
/* Internal API: Hash a single block of memory without the overhead of
creating an encryption context. This always uses SHA1 */
void shaHashBuffer( void *hashInfo, BYTE *outBuffer, BYTE *inBuffer,
int length, const HASH_STATE hashState )
{
SHA_INFO *shaInfo = ( SHA_INFO * ) hashInfo, shaInfoBuffer;
int i;
/* If the user has left it up to us to allocate the hash context buffer,
use the internal buffer */
if( shaInfo == NULL )
shaInfo = &shaInfoBuffer;
if( hashState == HASH_ALL )
{
sha1Initial( shaInfo );
sha1Update( shaInfo, inBuffer, length );
sha1Final( shaInfo );
for( i = 0; i < SHA_DIGESTSIZE / 4; i++ )
{
mputBLong( outBuffer, shaInfo->digest[ i ] );
}
}
else
switch( hashState )
{
case HASH_START:
sha1Initial( shaInfo );
/* Drop through */
case HASH_CONTINUE:
sha1Update( shaInfo, inBuffer, length );
break;
case HASH_END:
sha1Update( shaInfo, inBuffer, length );
sha1Final( shaInfo );
for( i = 0; i < SHA_DIGESTSIZE / 4; i++ )
{
mputBLong( outBuffer, shaInfo->digest[ i ] );
}
}
/* Clean up */
zeroise( &shaInfoBuffer, sizeof( SHA_INFO ) );
}
/****************************************************************************
* *
* SHA Key Management Routines *
* *
****************************************************************************/
/* Get/set algorithm-specific parameters */
BOOLEAN getSHAinfo( const CRYPT_INFO *cryptInfo )
{
return( ( ( SHA_INFO * ) cryptInfo->privateData )->isSHA );
}
void setSHAinfo( CRYPT_INFO *cryptInfo, const BOOLEAN isSHA )
{
( ( SHA_INFO * ) cryptInfo->privateData )->isSHA = isSHA;
}