?? cryptmis.c
字號(hào):
/****************************************************************************
* *
* cryptlib Misc Routines *
* Copyright Peter Gutmann 1992-2002 *
* *
****************************************************************************/
/* NSA motto: In God we trust... all others we monitor.
-- Stanley Miller */
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypt.h"
#ifdef INC_ALL
#include "md2.h"
#include "md4.h"
#include "md5.h"
#include "ripemd.h"
#include "sha.h"
#include "stream.h"
#else
#include "hash/md2.h"
#include "hash/md4.h"
#include "hash/md5.h"
#include "hash/ripemd.h"
#include "hash/sha.h"
#include "keymgmt/stream.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Internal API Functions *
* *
****************************************************************************/
/* Determine the parameters for a particular hash algorithm */
void getHashParameters( const CRYPT_ALGO hashAlgorithm,
HASHFUNCTION *hashFunction, int *hashSize )
{
void md2HashBuffer( void *hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void md5HashBuffer( void *hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void ripemd160HashBuffer( void *hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void shaHashBuffer( void *hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
void sha2HashBuffer( void *hashInfo, BYTE *outBuffer,
const BYTE *inBuffer, const int length,
const HASH_STATE hashState );
switch( hashAlgorithm )
{
case CRYPT_ALGO_MD2:
*hashFunction = md2HashBuffer;
*hashSize = MD2_DIGESTSIZE;
return;
case CRYPT_ALGO_MD5:
*hashFunction = md5HashBuffer;
*hashSize = MD5_DIGEST_LENGTH;
return;
case CRYPT_ALGO_RIPEMD160:
*hashFunction = ripemd160HashBuffer;
*hashSize = RIPEMD160_DIGESTSIZE;
return;
case CRYPT_ALGO_SHA:
*hashFunction = shaHashBuffer;
*hashSize = SHA_DIGEST_LENGTH;
return;
}
assert( NOTREACHED );
}
/* Byte-reverse an array of 16- and 32-bit words to/from network byte order
to account for processor endianness. These routines assume the given
count is a multiple of 16 or 32 bits. They are safe even for CPU's with
a word size > 32 bits since on a little-endian CPU the important 32 bits
are stored first, so that by zeroizing the first 32 bits and oring the
reversed value back in we don't need to rely on the processor only writing
32 bits into memory */
void longReverse( LONG *buffer, int count )
{
#if defined( _BIG_WORDS )
BYTE *bufPtr = ( BYTE * ) buffer, temp;
count /= 4; /* sizeof( LONG ) != 4 */
while( count-- )
{
#if 0
LONG temp;
/* This code is cursed */
temp = value = *buffer & 0xFFFFFFFFUL;
value = ( ( value & 0xFF00FF00UL ) >> 8 ) | \
( ( value & 0x00FF00FFUL ) << 8 );
value = ( ( value << 16 ) | ( value >> 16 ) ) ^ temp;
*buffer ^= value;
buffer = ( LONG * ) ( ( BYTE * ) buffer + 4 );
#endif /* 0 */
/* There's really no nice way to do this - the above code generates
misaligned accesses on processors with a word size > 32 bits, so
we have to work at the byte level (either that or turn misaligned
access warnings off by trapping the signal the access corresponds
to. However a context switch per memory access is probably
somewhat slower than the current byte-twiddling mess) */
temp = bufPtr[ 3 ];
bufPtr[ 3 ] = bufPtr[ 0 ];
bufPtr[ 0 ] = temp;
temp = bufPtr[ 2 ];
bufPtr[ 2 ] = bufPtr[ 1 ];
bufPtr[ 1 ] = temp;
bufPtr += 4;
}
#elif defined( __WIN32__ )
/* The following code which makes use of bswap is significantly faster
than what the compiler would otherwise generate. This code is used
such a lot that it's worth the effort */
__asm {
mov ecx, count
mov edx, buffer
shr ecx, 2
swapLoop:
mov eax, [edx]
bswap eax
mov [edx], eax
add edx, 4
dec ecx
jnz swapLoop
}
#else
LONG value;
count /= sizeof( LONG );
while( count-- )
{
value = *buffer;
value = ( ( value & 0xFF00FF00UL ) >> 8 ) | \
( ( value & 0x00FF00FFUL ) << 8 );
*buffer++ = ( value << 16 ) | ( value >> 16 );
}
#endif /* _BIG_WORDS */
}
void wordReverse( WORD *buffer, int count )
{
WORD value;
count /= sizeof( WORD );
while( count-- )
{
value = *buffer;
*buffer++ = ( value << 8 ) | ( value >> 8 );
}
}
/* Get a random (but not necessarily unpredictable) nonce. It doesn't matter
much what it is, as long as it's completely different for each call */
void getNonce( void *nonce, int nonceLength )
{
static BOOLEAN nonceDataInitialised = FALSE;
static BYTE nonceData[ CRYPT_MAX_HASHSIZE ];
static HASHFUNCTION hashFunction;
BYTE *noncePtr = nonce;
static int hashSize;
enterMutex( MUTEX_NONCE );
/* Get the hash algorithm information and seed the nonce data with a
value which is guaranteed to be different each time (unless the entire
program is rerun more than twice a second, which is doubtful) */
if( !nonceDataInitialised )
{
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
time( ( time_t * ) nonceData );
nonceDataInitialised = TRUE;
}
/* Shuffle the pool and copy it to the output buffer until it's full */
while( nonceLength > 0 )
{
const int count = ( nonceLength > hashSize ) ? hashSize : nonceLength;
/* Hash the data and copy the appropriate amount of data to the output
buffer */
hashFunction( NULL, nonceData, nonceData, hashSize, HASH_ALL );
memcpy( noncePtr, nonceData, count );
/* Move on to the next block of the output buffer */
noncePtr += hashSize;
nonceLength -= hashSize;
}
exitMutex( MUTEX_NONCE );
}
/* Perform the FIPS-140 statistical checks which are feasible on a byte
string. The full suite of tests assumes an infinite source of values (and
time) is available, the following is a scaled-down version used to sanity-
check keys and other short random data blocks. Note that this check
requires at least 64 bits of data in order to produce useful results */
BOOLEAN checkEntropy( const BYTE *data, const int dataLength )
{
const int delta = ( dataLength < 16 ) ? 1 : 0;
int bitCount[ 4 ] = { 0 }, noOnes, i;
for( i = 0; i < dataLength; i++ )
{
const int value = data[ i ];
bitCount[ value & 3 ]++;
bitCount[ ( value >> 2 ) & 3 ]++;
bitCount[ ( value >> 4 ) & 3 ]++;
bitCount[ value >> 6 ]++;
}
/* Monobit test: Make sure at least 1/4 of the bits are ones and 1/4 are
zeroes */
noOnes = bitCount[ 1 ] + bitCount[ 2 ] + ( 2 * bitCount[ 3 ] );
if( noOnes < dataLength * 2 || noOnes > dataLength * 6 )
return( FALSE );
/* Poker test (almost): Make sure each bit pair is present at least
1/16 of the time. The FIPS 140 version uses 4-bit values, but the
numer of samples available from the keys is far too small for this.
This isn't precisely 1/16, for short samples (< 128 bits) we adjust
the count by one because of the small sample size, and for odd-length
data we're getting four more samples so the actual figure is slightly
less than 1/16 */
if( ( bitCount[ 0 ] + delta < dataLength / 2 ) || \
( bitCount[ 1 ] + delta < dataLength / 2 ) || \
( bitCount[ 2 ] + delta < dataLength / 2 ) || \
( bitCount[ 3 ] + delta < dataLength / 2 ) )
return( FALSE );
return( TRUE );
}
/* Copy a string attribute to external storage, with various range checks
to follow the cryptlib semantics */
int attributeCopy( RESOURCE_DATA *msgData, const void *attribute,
const int attributeLength )
{
if( attributeLength == 0 )
{
msgData->length = 0;
return( CRYPT_ERROR_NOTFOUND );
}
if( msgData->data != NULL )
{
assert( attribute != NULL );
assert( attributeLength > 0 );
if( attributeLength > msgData->length || \
checkBadPtrWrite( msgData->data, attributeLength ) )
return( CRYPT_ARGERROR_STR1 );
memcpy( msgData->data, attribute, attributeLength );
}
msgData->length = attributeLength;
return( CRYPT_OK );
}
int attributePtrCopy( void *dest, int *destLength, const void *attribute,
const int attributeLength )
{
if( dest != NULL )
{
assert( attribute != NULL );
assert( attributeLength > 0 );
if( attributeLength > *destLength || \
checkBadPtrWrite( dest, attributeLength ) )
return( CRYPT_ARGERROR_STR1 );
memcpy( dest, attribute, attributeLength );
}
*destLength = attributeLength;
return( CRYPT_OK );
}
/* Check whether a given algorithm is available */
BOOLEAN algoAvailable( const CRYPT_ALGO cryptAlgo )
{
CRYPT_QUERY_INFO queryInfo;
return( cryptStatusOK( krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_QUERYCAPABILITY,
&queryInfo, cryptAlgo ) ) ? TRUE : FALSE );
}
/****************************************************************************
* *
* Extended libc Functions *
* *
****************************************************************************/
/* Match a given substring against a string in a case-insensitive manner */
#if defined( __UNIX__ )
int strnicmp( const char *src, const char *dest, const int length )
{
return( strncasecmp( src, dest, length ) );
}
int stricmp( const char *src, const char *dest )
{
return( strcasecmp( src, dest ) );
}
#elif !( defined( __WINDOWS__ ) || defined( __MSDOS__ ) || \
defined( __OS2__ ) || defined( __IBM4758__ ) || \
defined( __TANDEM__ ) ) || defined( NT_DRIVER )
int strnicmp( const char *src, const char *dest, int length )
{
char srcCh, destCh;
while( length-- )
{
/* Need to be careful with toupper() side-effects */
srcCh = *src++;
srcCh = toupper( srcCh );
destCh = *dest++;
destCh = toupper( destCh );
if( srcCh != destCh )
return( srcCh - destCh );
}
return( 0 );
}
int stricmp( const char *src, const char *dest )
{
int length = strlen( src );
if( length != strlen( dest ) )
return( 1 ); /* Lengths differ */
return( strnicmp( src, dest, length ) );
}
#endif /* OS-specific case-insensitive string compares */
/****************************************************************************
* *
* OS-specific Helper Functions *
* *
****************************************************************************/
#if defined( __SCO_VERSION__ ) && defined( USE_THREADS )
int createThread( void *( *function )( void * ), void *arg )
{
pthread_attr_t attr;
pthread_t dummy;
int status;
/* Create the thread, setting the stack size to a sensible value
rather than the default used by SCO */
pthread_attr_init( &attr );
pthread_attr_setstacksize( &attr, 32768 );
status = pthread_create( &dummy, &attr, function, arg );
pthread_attr_destroy( &attr );
return( status );
}
#endif /* UnixWare/SCO with threading */
/****************************************************************************
* *
* Base64 En/Decoding Functions *
* *
****************************************************************************/
/* Some interfaces can't handle binary data, so we base64-encode it using the
following encode/decode tables (from RFC 1113) */
#define BPAD '=' /* Padding for odd-sized output */
#define BERR 0xFF /* Illegal char marker */
#define BEOF 0x7F /* EOF marker (padding char or EOL) */
static const char binToAscii[] = \
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#if 'A' == 0x41 /* ASCII */
static const BYTE asciiToBin[] =
{ BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BEOF, BERR, BERR, BEOF, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, 0x3E, BERR, BERR, BERR, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
0x3C, 0x3D, BERR, BERR, BERR, BEOF, BERR, BERR,
BERR, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, BERR, BERR, BERR, BERR, BERR,
BERR, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR
};
#elif 'A' == 0xC1 /* EBCDIC */
/* EBCDIC character mappings:
A-I C1-C9
J-R D1-D9
S-Z E2-E9
a-i 81-89
j-r 91-99
s-z A2-A9
0-9 F0-F9
+ 4E
/ 61
= 7E Uses BEOF in table */
static const BYTE asciiToBin[] =
{ BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*00*/
BERR, BERR, BEOF, BERR, BERR, BEOF, BERR, BERR, /* CR, LF */
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*10*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*20*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*30*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*40*/
BERR, BERR, BERR, BERR, BERR, BERR, 0x3E, BERR, /* + */
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*50*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, 0x3F, BERR, BERR, BERR, BERR, BERR, BERR, /*60*/ /* / */
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*70*/
BERR, BERR, BERR, BERR, BERR, BERR, BEOF, BERR, /* = */
BERR, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, /*80*/ /* a-i */
0x21, 0x22, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /*90*/ /* j-r */
0x2A, 0x2B, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, /*A0*/ /* s-z */
0x32, 0x33, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*B0*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR
BERR, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /*C0*/ /* A-I */
0x07, 0x08, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /*D0*/ /* J-R */
0x10, 0x11, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /*E0*/ /* S-Z */
0x18, x019, BERR, BERR, BERR, BERR, BERR, BERR,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, /*F0*/ /* 0-9 */
0x3C, 0x3D, BERR, BERR, BERR, BERR, BERR, BERR
};
#else
#error System is neither ASCII nor EBCDIC
#endif /* Different character code mappings */
/* The size of lines for PEM-type formatting. This is only used for encoding,
for decoding we adjust to whatever size the sender has used */
#define TEXT_LINESIZE 64
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -