📄 vmsha1.cpp
字号:
/*****************************************************************************/
/* SOURCE FILE */
/*****************************************************************************/
/*
$Archive: $
$Revision: $
$Date: $
$Author: $
Description: Implementation of the NIST proposed Secure Hash Standard
Based on work that was put into the public domain by:
Peter C. Gutmann on Written 2 September 1992
*/
static char OBJECT_ID[] = "$Revision: $ : $Date: $";
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "VMSHA1.h"
// The SHS Mysterious Constants
//
const ULONG cK1 = 0x5A827999;
const ULONG cK2 = 0x6ED9EBA1;
const ULONG cK3 = 0x8F1BBCDC;
const ULONG cK4 = 0xCA62C1D6;
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::Hash
DESCRIPTION: Super ordinate method. Calls on other members to do the
required work.
INPUT: pshsInfo - Pointer to output structure for this class.
pbInput - the string to hash through this class
lLength - the length of the string to be hashed.
OUTPUT: none
RETURNS: void -
*/
void VMSHA1Hash::Hash( P_VM_SHS_INFO pshsInfo, const BYTE* pbInput, long lLength )
{
Init( pshsInfo );
Update( pshsInfo, pbInput, lLength );
Final( pshsInfo );
}
/* End of function "VMSHA1Hash::Hash"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::Init
DESCRIPTION: Initialize the SHS values
INPUT: pshsInfo - pointer to the structure to initialize
OUTPUT: none
RETURNS: void
*/
void VMSHA1Hash::Init( P_VM_SHS_INFO pshsInfo )
{
// Set the h-vars to their initial values as defined by the NIST spec
//
pshsInfo->m_ulaDigest[ 0 ] = 0x67452301;
pshsInfo->m_ulaDigest[ 1 ] = 0xEFCDAB89;
pshsInfo->m_ulaDigest[ 2 ] = 0x98BADCFE;
pshsInfo->m_ulaDigest[ 3 ] = 0x10325476;
pshsInfo->m_ulaDigest[ 4 ] = 0xC3D2E1F0;
// Initialise bit count
//
pshsInfo->m_CountLo = pshsInfo->m_CountHi = 0L;
}
/* End of function "VMSHA1Hash::Init"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::Expand
DESCRIPTION: The initial expansion function
INPUT: sCount - the index of the element to expand
OUTPUT: none
RETURNS: void
*/
inline void VMSHA1Hash::Expand( ULONG ulArray[], short sCount )
{
ulArray[ sCount ] = ulArray[ sCount - 3 ]
^ ulArray[ sCount - 8 ]
^ ulArray[ sCount - 14 ]
^ ulArray[ sCount - 16 ];
}
/* End of function "VMSHA1Hash::Expand"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::DoRound1
DESCRIPTION: mangles the values of class members
INPUT: ulValueAtIndex - a specific value to throw into the mix
OUTPUT: none
RETURNS: void
*/
inline void VMSHA1Hash::DoRound1( ULONG ulValueAtIndex )
{
ULONG uTemp;
uTemp = ( ( m_A << 5 ) | ( m_A >> 27 ) ) + ( ( m_B & m_C ) | ( ~m_B & m_D ) ) + m_E + ulValueAtIndex + cK1;
m_E = m_D;
m_D = m_C;
m_C = ( m_B << 30 ) | ( m_B >> 2 );
m_B = m_A;
m_A = uTemp;
}
/* End of function "VMSHA1Hash::DoRound1"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::DoRound2
DESCRIPTION: mangles the values of class members
INPUT: ulValueAtIndex - a specific value to throw into the mix
OUTPUT: none
RETURNS: void
*/
inline void VMSHA1Hash::DoRound2( ULONG ulValueAtIndex )
{
ULONG uTemp;
uTemp = ( ( m_A << 5 ) | ( m_A >> 27 ) ) + ( m_B ^ m_C ^ m_D ) + m_E + ulValueAtIndex + cK2;
m_E = m_D;
m_D = m_C;
m_C = ( m_B << 30 ) | ( m_B >> 2 );
m_B = m_A;
m_A = uTemp;
}
/* End of function "VMSHA1Hash::DoRound2"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::DoRound3
DESCRIPTION: mangles the values of class members
INPUT: ulValueAtIndex - a specific value to throw into the mix
OUTPUT: none
RETURNS: void
*/
inline void VMSHA1Hash::DoRound3( ULONG ulValueAtIndex )
{
ULONG uTemp;
uTemp = ( ( m_A << 5 ) | ( m_A >> 27 ) ) + ( ( m_B & m_C ) | ( m_B & m_D ) | ( m_C & m_D ) ) + m_E + ulValueAtIndex + cK3;
m_E = m_D;
m_D = m_C;
m_C = ( m_B << 30 ) | ( m_B >> 2 );
m_B = m_A;
m_A = uTemp;
}
/* End of function "VMSHA1Hash::DoRound3"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::DoRound4
DESCRIPTION: mangles the values of class members
INPUT: ulValueAtIndex - a specific value to throw into the mix
OUTPUT: none
RETURNS: void
*/
inline void VMSHA1Hash::DoRound4( ULONG ulValueAtIndex )
{
ULONG uTemp;
uTemp = ( ( m_A << 5 ) | ( m_A >> 27 ) ) + ( m_B ^ m_C ^ m_D ) + m_E + ulValueAtIndex + cK4;
m_E = m_D;
m_D = m_C;
m_C = ( m_B << 30 ) | ( m_B >> 2 );
m_B = m_A;
m_A = uTemp;
}
/* End of function "VMSHA1Hash::DoRound4"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::Transform
DESCRIPTION: Perform the SHS transformation. Note that this code, like
MD5, seems to break some optimizing compilers - it may be
necessary to split it into sections, eg based on the four
subrounds
INPUT: pshsInfo -
OUTPUT: none
RETURNS: void
*/
void VMSHA1Hash::Transform( P_VM_SHS_INFO pshsInfo )
{
ULONG ulaWorking[ 80 ];
int iLoop;
// Step A. Copy the data buffer into the local work buffer
//
for( iLoop = 0; iLoop < 16; iLoop++ )
ulaWorking[ iLoop ] = pshsInfo->m_ulaData[ iLoop ];
// Step B. Expand the 16 words into 64 temporary data words
//
for ( iLoop = 16; iLoop < 80; iLoop++ )
Expand( ulaWorking, iLoop );
// Step C. Set up first buffer
//
m_A = pshsInfo->m_ulaDigest[ 0 ];
m_B = pshsInfo->m_ulaDigest[ 1 ];
m_C = pshsInfo->m_ulaDigest[ 2 ];
m_D = pshsInfo->m_ulaDigest[ 3 ];
m_E = pshsInfo->m_ulaDigest[ 4 ];
// Step D. Serious mangling, divided into four sub-rounds
//
for ( iLoop = 0; iLoop < 20; iLoop++ )
DoRound1( ulaWorking[ iLoop ] );
for ( iLoop = 20; iLoop < 40; iLoop++ )
DoRound2( ulaWorking[ iLoop ] );
for ( iLoop = 40; iLoop < 60; iLoop++ )
DoRound3( ulaWorking[ iLoop ] );
for ( iLoop = 60; iLoop < 80; iLoop++ )
DoRound4( ulaWorking[ iLoop ] );
// Step E. Build message digest
//
pshsInfo->m_ulaDigest[ 0 ] += m_A;
pshsInfo->m_ulaDigest[ 1 ] += m_B;
pshsInfo->m_ulaDigest[ 2 ] += m_C;
pshsInfo->m_ulaDigest[ 3 ] += m_D;
pshsInfo->m_ulaDigest[ 4 ] += m_E;
}
/* End of function "VMSHA1Hash::Transform"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: Update
DESCRIPTION: Update SHS for a block of data. This code assumes that
the buffer size is a multiple of ciBlockSize bytes long,
which makes the code a lot more efficient since it does
away with the need to handle partial blocks between calls
to Update()
INPUT: pshsInfo - the "target" of the operation
pBuffer - pointer to the data buffer to operate on
lCount - the length of the input buffer
OUTPUT: pshsInfo contents are modified
RETURNS: void
*/
void VMSHA1Hash::Update( P_VM_SHS_INFO pshsInfo, const BYTE* pBuffer, long lCount )
{
// Update bitcount
//
if ( ( pshsInfo->m_CountLo + ( (ULONG) lCount << 3 ) ) < pshsInfo->m_CountLo )
{
// Carry from low to high bitCount
//
pshsInfo->m_CountHi++;
}
pshsInfo->m_CountLo += ( (ULONG) lCount << 3 );
pshsInfo->m_CountHi += ( (ULONG) lCount >> 29 );
// Process data in ciBlockSize chunks
//
while ( lCount >= ciBlockSize )
{
memcpy( pshsInfo->m_ulaData, pBuffer, ciBlockSize );
#ifdef LITTLE_ENDIAN
ReverseByte( pshsInfo->m_ulaData, ciBlockSize );
#endif
Transform( pshsInfo );
pBuffer += ciBlockSize;
lCount -= ciBlockSize;
}
// Handle any remaining bytes of data. This should
// only happen once on the final lot of data
//
memcpy( pshsInfo->m_ulaData, pBuffer, lCount );
}
/* End of function "VMSHA1Hash::Update"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::Final
DESCRIPTION:
INPUT: pshsInfo - pointer to the structure to operate on
OUTPUT: none
RETURNS: void
*/
void VMSHA1Hash::Final( P_VM_SHS_INFO pshsInfo )
{
int count;
ULONG lowBitcount = pshsInfo->m_CountLo;
ULONG highBitcount = pshsInfo->m_CountHi;
// Compute number of bytes mod 64
//
count = (int) ( ( pshsInfo->m_CountLo >> 3 ) & 0x3F );
// Set the first char of padding to 0x80. This is
// safe since there is always at least one byte free
//
( (BYTE*) pshsInfo->m_ulaData )[ count++ ] = 0x80;
// Pad out to 56 mod 64
//
if( count > 56 )
{
// Two lots of padding: Pad the first block to 64 bytes
//
memset( (BYTE*) &pshsInfo->m_ulaData + count, 0, 64 - count );
#ifdef LITTLE_ENDIAN
ReverseByte( pshsInfo->m_ulaData, ciBlockSize );
#endif
Transform( pshsInfo );
// Now fill the next block with 56 bytes
//
memset( &pshsInfo->m_ulaData, 0, 56 );
}
else
{
// Pad block to 56 bytes
//
memset( (BYTE*) &pshsInfo->m_ulaData + count, 0, 56 - count );
}
#ifdef LITTLE_ENDIAN
ReverseByte( pshsInfo->m_ulaData, ciBlockSize );
#endif
// Append length in bits and transform
//
pshsInfo->m_ulaData[ 14 ] = highBitcount;
pshsInfo->m_ulaData[ 15 ] = lowBitcount;
Transform( pshsInfo );
#ifdef LITTLE_ENDIAN
ReverseByte( pshsInfo->m_ulaData, ciDigestSize );
#endif
}
/* End of function "VMSHA1Hash::Final"
/*****************************************************************************/
#ifdef LITTLE_ENDIAN
/*****************************************************************************/
/*
FUNCTION NAME: VMSHA1Hash::ReverseByte
DESCRIPTION: When run on a little-endian CPU we need to perform byte
reversal on an array of longwords. It is possible to make
the code endianness-independant by fiddling around with
data at the byte level, but this makes for very slow code,
so we rely on the user to sort out endianness at compile time
INPUT: pBuffer - pointer to the buffer to operate on
iByteCount - the size of the buffer
OUTPUT:
RETURNS: void
*/
void VMSHA1Hash::ReverseByte( ULONG* pBuffer, int iByteCount )
{
ULONG value;
int count;
iByteCount /= sizeof( ULONG );
for( count = 0; count < iByteCount; count++ )
{
value = ( pBuffer[ count ] << 16 ) | ( pBuffer[ count ] >> 16 );
pBuffer[ count ] = ( ( value & 0xFF00FF00L ) >> 8 ) | ( ( value & 0x00FF00FFL ) << 8 );
}
}
/* End of function "VMSHA1Hash::ReverseByte"
/*****************************************************************************/
#endif // LITTLE_ENDIAN
/*****************************************************************************/
/* Check-in history */
/*
*$Log: $
*/
/*****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -