/*********************************************************************
*
* Hash Function Library
* Library for Microchip TCP/IP Stack
* -Calculates MD5 and SHA-1 Hashes
* -Reference: RFC 1321 (MD5), RFC 3174 and FIPS 180-1 (SHA-1)
*
*********************************************************************
* FileName: Hashes.c
* Dependencies: None
* Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
* Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
* Compiler: Microchip C32 v1.05 or higher
* Microchip C30 v3.12 or higher
* Microchip C18 v3.30 or higher
* HI-TECH PICC-18 PRO 9.63PL2 or higher
* Company: Microchip Technology, Inc.
*
* Software License Agreement
*
* Copyright (C) 2002-2009 Microchip Technology Inc. All rights
* reserved.
*
* Microchip licenses to you the right to use, modify, copy, and
* distribute:
* (i) the Software when embedded on a Microchip microcontroller or
* digital signal controller product ("Device") which is
* integrated into Licensee's product; or
* (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
* ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
* used in conjunction with a Microchip ethernet controller for
* the sole purpose of interfacing with the ethernet controller.
*
* You should refer to the license agreement accompanying this
* Software for additional information regarding your rights and
* obligations.
*
* THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
* WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
* LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
* PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
* BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
* THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
* SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
* (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
*
* IMPORTANT: The implementation and use of third party algorithms,
* specifications and/or other technology may require a license from
* various third parties. It is your responsibility to obtain
* information regarding any applicable licensing obligations.
*
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Elliott Wood 5/01/07 Original
* Elliott Wood 11/21/07 Greatly increased HashBlock speed
********************************************************************/
#define __HASHES_C
/*****************************************************************************
Internal:
Performance Statistics are as follows:
(Given in instructions per block = 512 bits = 64 bytes)
MD5 SHA1
C18 23k instr/block 50k instr/block
Hi-Tech C 19k instr/block 50k instr/block
C30 21k instr/block 17k instr/block
***************************************************************************/
#include "TCPIP Stack/TCPIP.h"
/****************************************************************************
Section:
Functions and variables required for both hash types
***************************************************************************/
#if defined(STACK_USE_MD5) || defined(STACK_USE_SHA1)
// Stores a copy of the last block with the required padding
BYTE lastBlock[64];
/*****************************************************************************
Function:
void HashAddData(HASH_SUM* theSum, BYTE* data, WORD len)
Description:
Adds data to the hash sum.
Precondition:
The hash sum has already been initialized
Parameters:
theSum - hash context state
data - the data to be added to the hash sum
len - length of data
Returns:
None
Remarks:
This function calls the appropriate hashing function based on the
hash typed defined in theSum.
***************************************************************************/
void HashAddData(HASH_SUM* theSum, BYTE* data, WORD len)
{
#if defined(STACK_USE_MD5)
if(theSum->hashType == HASH_MD5)
MD5AddData(theSum, data, len);
#endif
#if defined(STACK_USE_SHA1)
if(theSum->hashType == HASH_SHA1)
SHA1AddData(theSum, data, len);
#endif
}
/*****************************************************************************
Function:
void HashAddROMData(HASH_SUM* theSum, ROM BYTE* data, WORD len)
Description:
Adds data to the hash sum.
Precondition:
The hash sum has already been initialized
Parameters:
theSum - hash context state
data - the data to be added to the hash sum
len - length of data
Returns:
None
Remarks:
This function calls the appropriate hashing function based on the
hash typed defined in theSum.
This function is aliased to HashAddData on non-PIC18 platforms.
***************************************************************************/
#if defined(__18CXX)
void HashAddROMData(HASH_SUM* theSum, ROM BYTE* data, WORD len)
{
#if defined(STACK_USE_MD5)
if(theSum->hashType == HASH_MD5)
MD5AddROMData(theSum, data, len);
#endif
#if defined(STACK_USE_SHA1)
if(theSum->hashType == HASH_SHA1)
SHA1AddROMData(theSum, data, len);
#endif
}
#endif
#endif
/****************************************************************************
Section:
Functions and variables required for MD5
***************************************************************************/
#if defined(STACK_USE_MD5)
// Array of pre-defined R vales for MD5
static ROM BYTE _MD5_r[64] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
// Array of pre-defined K values for MD5
static ROM DWORD _MD5_k[64] = { 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391 };
static void MD5HashBlock(BYTE* data, DWORD* h0, DWORD* h1, DWORD* h2, DWORD* h3);
/*****************************************************************************
Function:
void MD5Initialize(HASH_SUM* theSum)
Description:
Initializes a new MD5 hash.
Precondition:
None
Parameters:
theSum - pointer to the allocated HASH_SUM object to initialize as MD5
Returns:
None
***************************************************************************/
void MD5Initialize(HASH_SUM* theSum)
{
theSum->h0 = 0x67452301;
theSum->h1 = 0xefcdab89;
theSum->h2 = 0x98badcfe;
theSum->h3 = 0x10325476;
theSum->bytesSoFar = 0;
theSum->hashType = HASH_MD5;
}
/*****************************************************************************
Function:
void MD5AddData(HASH_SUM* theSum, BYTE* data, WORD len)
Description:
Adds data to an MD5 hash calculation.
Precondition:
The hash context has already been initialized.
Parameters:
theSum - a pointer to the hash context structure
data - the data to add to the hash
len - the length of the data to add
Returns:
None
***************************************************************************/
void MD5AddData(HASH_SUM* theSum, BYTE* data, WORD len)
{
BYTE *blockPtr;
// Seek to the first free byte
blockPtr = theSum->partialBlock + ( theSum->bytesSoFar & 0x3f );
// Update the total number of bytes
theSum->bytesSoFar += len;
// Copy data into the partial block
while(len != 0u)
{
*blockPtr++ = *data++;
// If the partial block is full, hash the data and start over
if(blockPtr == theSum->partialBlock + 64)
{
MD5HashBlock(theSum->partialBlock, &theSum->h0, &theSum->h1, &theSum->h2, &theSum->h3);
blockPtr = theSum->partialBlock;
}
len--;
}
}
/*****************************************************************************
Function:
void MD5AddROMData(HASH_SUM* theSum, ROM BYTE* data, WORD len)
Description:
Adds data to an MD5 hash calculation.
Precondition:
The hash context has already been initialized.
Parameters:
theSum - a pointer to the hash context structure
data - the data to add to the hash
len - the length of the data to add
Returns:
None
Remarks:
This function is aliased to MD5AddData on non-PIC18 platforms.
***************************************************************************/
#if defined(__18CXX)
void MD5AddROMData(HASH_SUM* theSum, ROM BYTE* data, WORD len)
{
BYTE *blockPtr;
// Seek to the first free byte
blockPtr = theSum->partialBlock + ( theSum->bytesSoFar & 0x3f );
// Update the total number of bytes
theSum->bytesSoFar += len;
// Copy data into the partial block
while(len != 0u)
{
*blockPtr++ = *data++;
// If the partial block is full, hash the data and start over
if(blockPtr == theSum->partialBlock + 64)
{
MD5HashBlock(theSum->partialBlock, &theSum->h0, &theSum->h1, &theSum->h2, &theSum->h3);
blockPtr = theSum->partialBlock;
}
len--;
}
}
#endif
/*****************************************************************************
Function:
static void MD5HashBlock(BYTE* data, DWORD* h0, DWORD* h1,
DWORD* h2, DWORD* h3)
Summary:
Calculates the MD5 hash sum of a block.
Description:
This function calculates the MD5 hash sum over a block and updates
the values of h0-h3 with the next context.
Precondition:
The data pointer must be WORD aligned on 16-bit parts and DWORD
aligned on 32-bit PICs. If alignment is not correct, a memory alignment
exception will occur.
Parameters:
data - The block of 64 bytes to hash
h0 - the current hash context h0 value
h1 - the current hash context h1 value
h2 - the current hash context h2 value
h3 - the current hash context h3 value
Returns:
None
Internal:
TODO convert data to a DWORD* or read from the pointer using byte
accesses only to avoid any accidental alignment errors
***************************************************************************/
static void MD5HashBlock(BYTE* data, DWORD* h0, DWORD* h1, DWORD* h2, DWORD* h3)
{
DWORD a, b, c, d, f, temp;
BYTE i, j;
// Set up a, b, c, d
a = *h0;
b = *h1;
c = *h2;
d = *h3;
// Main mixer loop for 64 operations
for(i = 0; i < 64u; i++)
{
if(i <= 15u)
{
f = (b & c) | ((~b) & d);
j = i;
}
else if(i > 15u && i <= 31u)
{
f = (d & b) | ((~d) & c);
j = (5 * i + 1) & 0x0f;
}
else if(i > 31u && i <= 47u)
{
f = (b ^ c ^ d);
j = (3 * i + 5) & 0x0f;
}
else
{
f = c ^ (b | (~d));
j = (7 * i) & 0x0f;
}
// Calculate the new mixer values
temp = d;
d = c;
c = b;
j *= 4;
b = leftRotateDWORD(a+f+_MD5_k[i]+(*(DWORD*)&data[j]),_MD5_r[i]) + b;
a = temp;
}
// Add the new hash to the sum
*h0 += a;
*h1 += b;
*h2 += c;
*h3 += d;
}
/*****************************************************************************
Function:
void MD5Calculate(HASH_SUM* theSum, BYTE* result)
Summary:
Calculates an MD5 hash
Description:
This function calculates the hash sum of all input data so far. It is
non-destructive to the hash context, so more data may be added after
this function is called.
Precondition:
The hash context has been properly initialized.
Parameters:
theSum - the current hash context
result - 16 byte array in which to store the resulting hash
Returns:
None
***************************************************************************/
void MD5Calculate(HASH_SUM* theSum, BYTE* result)
{
DWORD h0, h1, h2, h3;
BYTE i, *partPtr, *endPtr;
// Initialize the hash variables
h0 = theSum->h0;
h1 = theSum->h1;
h2 = theSum->h2;
h3 = theSum->h3;
// Find out how far along we are in the partial block and copy to last block
partPtr = theSum->partialBlock;
endPtr = partPtr + ( theSum->bytesSoFar & 0x3f );
for(i = 0; partPtr != endPtr; i++)
{
lastBlock[i] = *partPtr++;
}
// Add one more 1 bit and 7 zeros
lastBlock[i++] = 0x80;
// If there's 8 or more bytes left to 64, then this is the last block
if(i > 56u)
{// If there's not enough space, then zero fill this and add a new block
// Zero pad the remainder
for( ; i < 64u; lastBlock[i++] = 0x00);
// Calculate a hash on this block and add it to the sum
MD5HashBlock(lastBlock, &h0, &h1, &h2, &h3);
// Create a new block for the size
i = 0;
}
// Zero fill the rest of the block
for( ; i < 56u; lastBlock[i++] = 0x00);
// Fill in the size, in bits, in little-endian
lastBlock[56] = theSum->bytesSoFar << 3;
lastBlock[57] = theSum->bytesSoFar >> 5;
lastBlock[58] = theSum->bytesSoFar >> 13;
lastBlock[59] = theSum->bytesSoFar >> 21;
lastBlock[60] = theSum->bytesSoFar >> 29;
lastBlock[61] = 0;
lastBlock[62] = 0;
lastBlock[63] = 0;
// Calculate a hash on this final block and add it to the sum
MD5HashBlock(lastBlock, &h0, &h1, &h2, &h3);
// Format the result in little-endian format
memcpy((void*)result,(void*)&h0,4);
memcpy((void*)&result[4],(void*)&h1,4);
memcpy((void*)&result[8],(void*)&h2,4);
memcpy((void*)&result[12],(void*)&h3,4);
}
#endif //ends MD5
/****************************************************************************
Section:
Functions and variables required for SHA-1
***************************************************************************/
#if defined(STACK_USE_SHA1)
static void SHA1HashBlock(BYTE* data, DWORD* h0, DWORD* h1, DWORD* h2, DWORD* h3, DWORD* h4);
/*****************************************************************************
Function:
void SHA1Initialize(HASH_SUM* theSum)
Description:
Initializes a new SHA-1 hash.
Precondition:
None
Parameters:
theSum - pointer to the allocated HASH_SUM object to initialize as SHA-1
Returns:
None
***************************************************************************/
void SHA1Initialize(HASH_SUM* theSum)
{
theSum->h0 = 0x67452301;
theSum->h1 = 0xEFCDAB89;
theSum->h2 = 0x98BADCFE;
theSum->h3 = 0x10325476;
theSum->h4 = 0xC3D2E1F0;
theSum->bytesSoFar = 0;
theSum->hashType = HASH_SHA1;
}
/*****************************************************************************
Function:
void SHA1AddData(HASH_SUM* theSum, BYTE* data, WORD len)
Description:
Adds data to a SHA-1 hash calculation.
Precondition:
The hash context has already been initialized.
Parameters:
theSum - a pointer to the hash context structure
data - the data to add to the hash
len - the length of the data to add
Returns:
None
***************************************************************************/
void SHA1AddData(HASH_SUM* theSum, BYTE* data, WORD len)
{
BYTE *blockPtr;
// Seek to the first free byte
blockPtr = theSum->partialBlock + ( theSum->bytesSoFar & 0x3f );
// Update the total number of bytes
theSum->bytesSoFar += len;
// Copy data into the partial block
while(len != 0u)
{
*blockPtr++ = *data++;
// If the partial block is full, hash the data and start over
if(blockPtr == theSum->partialBlock + 64)
{
SHA1HashBlock(theSum->partialBlock, &theSum->h0, &theSum->h1,
&theSum->h2, &theSum->h3, &theSum->h4);
blockPtr = theSum->partialBlock;
}
len--;
}
}
/*****************************************************************************
Function:
void SHA1AddROMData(HASH_SUM* theSum, ROM BYTE* data, WORD len)
Description:
Adds data to a SHA-1 hash calculation.
Precondition:
The hash context has already been initialized.
Parameters:
theSum - a pointer to the hash context structure
data - the data to add to the hash
len - the length of the data to add
Returns:
None
Remarks:
This function is aliased to SHA1AddData on non-PIC18 platforms.
***************************************************************************/
#if defined(__18CXX)
void SHA1AddROMData(HASH_SUM* theSum, ROM BYTE* data, WORD len)
{
BYTE *blockPtr;
// Seek to the first free byte
blockPtr = theSum->partialBlock + ( theSum->bytesSoFar & 0x3f );
// Update the total number of bytes
theSum->bytesSoFar += len;
// Copy data into the partial block
while(len != 0u)
{
*blockPtr++ = *data++;
// If the partial block is full, hash the data and start over
if(blockPtr == theSum->partialBlock + 64)
{
SHA1HashBlock(theSum->partialBlock, &theSum->h0, &theSum->h1,
&theSum->h2, &theSum->h3, &theSum->h4);
blockPtr = theSum->partialBlock;
}
len--;
}
}
#endif
/*****************************************************************************
Function:
static void SHA1HashBlock(BYTE* data, DWORD* h0, DWORD* h1,
DWORD* h2, DWORD* h3, DWORD* h4)
Summary:
Calculates the SHA-1 hash sum of a block.
Description:
This function calculates the SHA-1 hash sum over a block and updates
the values of h0-h3 with the next context.
Precondition:
The data pointer must be WORD aligned on 16-bit parts and DWORD
aligned on 32-bit PICs. If alignment is not correct, a memory alignment
exception will occur.
Parameters:
data - The block of 64 bytes to hash
h0 - the current hash context h0 value
h1 - the current hash context h1 value
h2 - the current hash context h2 value
h3 - the current hash context h3 value
h4 - the current hash context h4 value
Returns:
None
Internal:
TODO convert data to a DWORD* or read from the pointer using byte
accesses only to avoid any accidental alignment errors
***************************************************************************/
static void SHA1HashBlock(BYTE* data, DWORD* h0, DWORD* h1, DWORD* h2,
DWORD* h3, DWORD* h4)
{
DWORD a, b, c, d, e, f, k, temp;
DWORD_VAL *w = (DWORD_VAL*)lastBlock;
BYTE i, back3, back8, back14;
// Set up a, b, c, d, e
a = *h0;
b = *h1;
c = *h2;
d = *h3;
e = *h4;
// Set up the w[] vector
if(lastBlock == data)
{// If they're the same, just swap endian-ness
for(i = 0; i < 16u; i++)
{
back3 = data[3];
data[3] = data[0];
data[0] = back3;
back3 = data[1];
data[1] = data[2];
data[2] = back3;
data += 4;
}
}
else
{// Otherwise, copy values in swaping endian-ness as we go
for(i = 0; i < 16u; i++)
{
w[i].v[3] = *data++;
w[i].v[2] = *data++;
w[i].v[1] = *data++;
w[i].v[0] = *data++;
}
}
back3 = 13;
back8 = 8;
back14 = 2;
// Main mixer loop for 80 operations
for(i = 0; i < 80u; i++)
{
if(i <= 19u)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(i >= 20u && i <= 39u)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(i >= 40u && i <= 59u)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
// Calculate the w[] value and store it in the array for future use
if(i >= 16u)
{
#if defined(HI_TECH_C)
// This section is unrolled for HI_TECH_C because it cannot parse
// the expression used by the other compilers
DWORD temp2;
temp = w[back3].Val;
temp2 = w[back8].Val;
temp ^= temp2;
temp2 = w[back14].Val;
temp ^= temp2;
temp2 = w[i&0x0f].Val;
temp ^= temp2;
w[i&0x0f].Val = leftRotateDWORD(temp, 1);
#else
w[i&0x0f].Val = leftRotateDWORD( ( w[back3].Val ^ w[back8].Val ^
w[back14].Val ^ w[i&0x0f].Val), 1);
#endif
back3 += 1;
back8 += 1;
back14 += 1;
back3 &= 0x0f;
back8 &= 0x0f;
back14 &= 0x0f;
}
// Calculate the new mixers
temp = leftRotateDWORD(a, 5) + f + e + k + w[i & 0x0f].Val;
e = d;
d = c;
c = leftRotateDWORD(b, 30);
b = a;
a = temp;
}
// Add the new hash to the sum
*h0 += a;
*h1 += b;
*h2 += c;
*h3 += d;
*h4 += e;
}
/*****************************************************************************
Function:
void MD5Calculate(HASH_SUM* theSum, BYTE* result)
Summary:
Calculates a SHA-1 hash
Description:
This function calculates the hash sum of all input data so far. It is
non-destructive to the hash context, so more data may be added after
this function is called.
Precondition:
The hash context has been properly initialized.
Parameters:
theSum - the current hash context
result - 20 byte array in which to store the resulting hash
Returns:
None
***************************************************************************/
void SHA1Calculate(HASH_SUM* theSum, BYTE* result)
{
DWORD h0, h1, h2, h3, h4;
BYTE i, *partPtr, *endPtr;
// Initialize the hash variables
h0 = theSum->h0;
h1 = theSum->h1;
h2 = theSum->h2;
h3 = theSum->h3;
h4 = theSum->h4;
// Find out how far along we are in the partial block and copy to last block
partPtr = theSum->partialBlock;
endPtr = partPtr + ( theSum->bytesSoFar & 0x3f );
for(i = 0; partPtr != endPtr; i++)
{
lastBlock[i] = *partPtr++;
}
// Add one more bit and 7 zeros
lastBlock[i++] = 0x80;
// If there's 8 or more bytes left to 64, then this is the last block
if(i > 56u)
{// If there's not enough space, then zero fill this and add a new block
// Zero pad the remainder
for( ; i < 64u; lastBlock[i++] = 0x00);
// Calculate a hash on this block and add it to the sum
SHA1HashBlock(lastBlock, &h0, &h1, &h2, &h3, &h4);
//create a new block for the size
i = 0;
}
// Zero fill the rest of the block
for( ; i < 56u; lastBlock[i++] = 0x00);
// Fill in the size, in bits, in big-endian
lastBlock[63] = theSum->bytesSoFar << 3;
lastBlock[62] = theSum->bytesSoFar >> 5;
lastBlock[61] = theSum->bytesSoFar >> 13;
lastBlock[60] = theSum->bytesSoFar >> 21;
lastBlock[59] = theSum->bytesSoFar >> 29;
lastBlock[58] = 0;
lastBlock[57] = 0;
lastBlock[56] = 0;
// Calculate a hash on this final block and add it to the sum
SHA1HashBlock(lastBlock, &h0, &h1, &h2, &h3, &h4);
// Format the result in big-endian format
*result++ = ((BYTE*)&h0)[3];
*result++ = ((BYTE*)&h0)[2];
*result++ = ((BYTE*)&h0)[1];
*result++ = ((BYTE*)&h0)[0];
*result++ = ((BYTE*)&h1)[3];
*result++ = ((BYTE*)&h1)[2];
*result++ = ((BYTE*)&h1)[1];
*result++ = ((BYTE*)&h1)[0];
*result++ = ((BYTE*)&h2)[3];
*result++ = ((BYTE*)&h2)[2];
*result++ = ((BYTE*)&h2)[1];
*result++ = ((BYTE*)&h2)[0];
*result++ = ((BYTE*)&h3)[3];
*result++ = ((BYTE*)&h3)[2];
*result++ = ((BYTE*)&h3)[1];
*result++ = ((BYTE*)&h3)[0];
*result++ = ((BYTE*)&h4)[3];
*result++ = ((BYTE*)&h4)[2];
*result++ = ((BYTE*)&h4)[1];
*result++ = ((BYTE*)&h4)[0];
}
#endif //#end SHA-1
|