lib_hmd5.c

来自「提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发」· C语言 代码 · 共 281 行

C
281
字号
/****************************************************************************
*																			*
*						cryptlib HMAC-MD5 Hash Routines						*
*						Copyright Peter Gutmann 1997-2000					*
*																			*
****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypt.h"
#include "cryptctx.h"
#ifdef INC_ALL
  #include "md5.h"
#else
  #include "hash/md5.h"
#endif /* Compiler-specific includes */

/* A structure to hold the initial and current MAC state info.  Rather than
   redoing the key processing each time when we're calculating multiple MACs
   with the same key, we just copy the initial state into the current state */

typedef struct {
	MD5_CTX macState, initialMacState;
	} MAC_STATE;

/****************************************************************************
*																			*
*							HMAC-MD5 Self-test Routines						*
*																			*
****************************************************************************/

/* Test the HMAC-MD5 output against the test vectors given in RFC 2104 and
   RFC ???? */

int hmacMD5InitKey( CRYPT_INFO *cryptInfo, const void *key, const int keyLength );
int hmacMD5Hash( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes );

static const struct {
	const char *key;						/* HMAC key */
	const int keyLength;					/* Length of key */
	const char *data;						/* Data to hash */
	const int length;						/* Length of data */
	const BYTE digest[ MD5_DIGEST_LENGTH ];	/* Digest of data */
	} hmacValues[] = {
	{ "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B", 16,
	  "Hi There", 8,
	  { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C,
		0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D } },
	{ "Jefe", 4,
		"what do ya want for nothing?", 28,
	  { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03,
		0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 } },
	{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", 16,
	  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
	  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
	  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
	  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
	  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", 50,
	  { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88,
		0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 } },
	{ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
	  "\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25,
	  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
	  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
	  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
	  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
	  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD", 50,
	  { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA,
		0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 } },
#if 0	/* Should be trunc.to 96 bits - we don't do truncation */
	{ "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C", 16,
	  "Test With Truncation", 20,
	  { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00,
		0xF9, 0xBA, 0xB9, 0x95, 0x69, 0x0E, 0xFD, 0x4C } },
#endif /* 0 */
	{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", 80,
	  "Test Using Larger Than Block-Size Key - Hash Key First", 54,
	  { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F,
		0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD } },
	{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
	  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", 80,
	  "Test Using Larger Than Block-Size Key and Larger Than One "
	  "Block-Size Data", 73,
	  { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE,
		0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E } },
	{ "", 0, NULL, 0, { 0 } }
	};

int hmacMD5SelfTest( void )
	{
	CRYPT_INFO cryptInfo;
	MAC_STATE macState;
	int i;

	/* Set up the dummy cryptInfo structure */
	memset( &cryptInfo, 0, sizeof( CRYPT_INFO ) );
	cryptInfo.ctxMAC.macInfo = &macState;

	/* Test HMAC-MD5 against the test vectors given in RFC 2104 */
	for( i = 0; hmacValues[ i ].data != NULL; i++ )
		{
		/* Initialise the encryption context with enough information to test
		   the HMAC functionality */
		cryptInfo.ctxMAC.done = FALSE;
		MD5_Init( &macState.macState );

		/* Load the HMAC key and perform the hashing */
		hmacMD5InitKey( &cryptInfo, hmacValues[ i ].key,
						hmacValues[ i ].keyLength );
		hmacMD5Hash( &cryptInfo, ( BYTE * ) hmacValues[ i ].data,
					 hmacValues[ i ].length );
		hmacMD5Hash( &cryptInfo, NULL, 0 );

		/* Retrieve the hash and make sure it matches the expected value */
		if( memcmp( cryptInfo.ctxMAC.mac, hmacValues[ i ].digest,
					MD5_DIGEST_LENGTH ) )
			break;
		}

	return( ( hmacValues[ i ].data == NULL ) ? \
			CRYPT_OK : CRYPT_ERROR );
	}

/****************************************************************************
*																			*
*							Init/Shutdown Routines							*
*																			*
****************************************************************************/

/* Perform auxiliary init and shutdown actions on an encryption context */

int hmacMD5Init( CRYPT_INFO *cryptInfo )
	{
	MAC_STATE *macState;
	int status;

	/* Allocate memory for the MD5 context within the encryption context.
	   Since MAC contexts can be reset by deleting the MAC values, this may 
	   already have been allocated previously so we only perform the alloc
	   if it's actually required */
	if( cryptInfo->ctxMAC.macInfo == NULL )
		{
		if( ( status = krnlMemalloc( &cryptInfo->ctxMAC.macInfo,
									 sizeof( MAC_STATE ) ) ) != CRYPT_OK )
			return( status );
		macState = cryptInfo->ctxMAC.macInfo;
		MD5_Init( &macState->macState );
		}
	else
		{
		/* Copy the initial MAC state over into the current MAC state */
		macState = cryptInfo->ctxMAC.macInfo;
		memcpy( &macState->macState, &macState->initialMacState, 
				sizeof( MD5_CTX ) );
		}

	return( CRYPT_OK );
	}

int hmacMD5End( CRYPT_INFO *cryptInfo )
	{
	/* Free any allocated memory */
	krnlMemfree( &cryptInfo->ctxMAC.macInfo );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							HMAC-MD5 Hash Routines							*
*																			*
****************************************************************************/

/* Hash data using HMAC-MD5 */

int hmacMD5Hash( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
	{
	MD5_CTX *md5Info = &( ( MAC_STATE * ) cryptInfo->ctxMAC.macInfo )->macState;

	/* If we've already called MD5_Final(), we can't continue */
	if( cryptInfo->ctxMAC.done )
		return( CRYPT_ERROR_COMPLETE );

	if( !noBytes )
		{
		BYTE hashBuffer[ MD5_CBLOCK ], digestBuffer[ MD5_CBLOCK ];
		int i;

		/* Complete the inner hash and extract the digest */
		MD5_Final( digestBuffer, md5Info );

		/* Perform the of the outer hash using the zero-padded key XOR'd
		   with the opad value followed by the digest from the inner hash */
		memset( hashBuffer, HMAC_OPAD, MD5_CBLOCK );
		memcpy( hashBuffer, cryptInfo->ctxMAC.userKey,
				cryptInfo->ctxMAC.userKeyLength );
		for( i = 0; i < cryptInfo->ctxMAC.userKeyLength; i++ )
			hashBuffer[ i ] ^= HMAC_OPAD;
		MD5_Init( md5Info );
		MD5_Update( md5Info, hashBuffer, MD5_CBLOCK );
		memset( hashBuffer, 0, MD5_CBLOCK );
		MD5_Update( md5Info, digestBuffer, MD5_DIGEST_LENGTH );
		memset( digestBuffer, 0, MD5_DIGEST_LENGTH );
		MD5_Final( cryptInfo->ctxMAC.mac, md5Info );
		cryptInfo->ctxMAC.done = TRUE;
		}
	else
		MD5_Update( md5Info, buffer, noBytes );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							HMAC-MD5 Key Management Routines				*
*																			*
****************************************************************************/

/* Set up an HMAC-MD5 key */

int hmacMD5InitKey( CRYPT_INFO *cryptInfo, const void *key, const int keyLength )
	{
	MD5_CTX *md5Info = &( ( MAC_STATE * ) cryptInfo->ctxMAC.macInfo )->macState;
	BYTE hashBuffer[ MD5_CBLOCK ];
	int i;

	/* If the key size is larger than the MD5 data size, reduce it to the MD5
	   hash size before processing it (yuck.  You're required to do this
	   though) */
	if( keyLength > MD5_CBLOCK )
		{
		/* Hash the user key down to the hash size (MD5_Init() has already
		   been called when the context was created) and use the hashed form
		   of the key */
		MD5_Update( md5Info, ( BYTE * ) key, keyLength );
		MD5_Final( cryptInfo->ctxMAC.userKey, md5Info );
		cryptInfo->ctxMAC.userKeyLength = MD5_DIGEST_LENGTH;

		/* Reset the MD5 state */
		MD5_Init( md5Info );
		}
	else
		{
		/* Copy the key to internal storage */
		if( cryptInfo->ctxMAC.userKey != key )
			memcpy( cryptInfo->ctxMAC.userKey, key, keyLength );
		cryptInfo->ctxMAC.userKeyLength = keyLength;
		}

	/* Perform the start of the inner hash using the zero-padded key XOR'd
	   with the ipad value */
	memset( hashBuffer, HMAC_IPAD, MD5_CBLOCK );
	memcpy( hashBuffer, cryptInfo->ctxMAC.userKey, cryptInfo->ctxMAC.userKeyLength );
	for( i = 0; i < cryptInfo->ctxMAC.userKeyLength; i++ )
		hashBuffer[ i ] ^= HMAC_IPAD;
	MD5_Update( md5Info, hashBuffer, MD5_CBLOCK );
	memset( hashBuffer, 0, MD5_CBLOCK );

	/* Save a copy of the initial state in case it's needed later */
	memcpy( &( ( MAC_STATE * ) cryptInfo->ctxMAC.macInfo )->initialMacState,
			md5Info, sizeof( MD5_CTX ) );

	return( CRYPT_OK );
	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?