In my previous blog post on ‘Generating MD5 Hash’,  I wrote code example on creating MD5 hash.  Today I will be presenting the direct code sample for generating SHA1 hash using Windows Cryptography functions. Due to various collision problems with MD5 Hash, now a days SHA256 hash is used more extensively for unique identification.

The code presented below is almost similar to MD5 Hash generation with changes in the specification of algorithm code.

.

//
//  Compute the SHA1 checksum for input buffer
//
BOOL GetSHA1Hash(char *buffer,             //input buffer
                 DWORD dwBufferSize,       //input buffer size
                 BYTE *byteFinalHash,      //ouput hash buffer
                 DWORD *dwFinalHashSize    //input/output final buffer size
)
{
 DWORD dwStatus = 0;
 BOOL bResult = FALSE;
 HCRYPTPROV hProv = 0;
 HCRYPTHASH hHash = 0;
 //BYTE *byteHash;
 DWORD cbHashSize = 0;

 // Get handle to the crypto provider
 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
 {
 printf("\nCryptAcquireContext failed, Error=0x%.8x", GetLastError());
 return FALSE;
 }

 //Specify the Hash Algorithm here
 if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
 {
 printf("\nCryptCreateHash failed,  Error=0x%.8x", GetLastError());
 goto EndHash;
 }

 //Create the hash with input buffer
 if (!CryptHashData(hHash, (const BYTE*) buffer, dwBufferSize, 0))
 {
 printf("\nCryptHashData failed,  Error=0x%.8x", GetLastError());
 goto EndHash;
 }

 //Get the final hash size 
 DWORD dwCount = sizeof(DWORD);
 if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize, &dwCount, 0)) 
 {
 printf("\nCryptGetHashParam failed, Error=0x%.8x", GetLastError());
 goto EndHash;
 }

 //check if the output buffer is enough to copy the hash data
 if( *dwFinalHashSize < cbHashSize )
 {
 printf("\nOutput buffer (%d) is not sufficient, Required Size = %d",
                        *dwFinalHashSize, cbHashSize);
 goto EndHash;
 }

 //Now get the computed hash 
 if (CryptGetHashParam(hHash, HP_HASHVAL, byteFinalHash, dwFinalHashSize, 0))
 {
 printf("\n********** Hash Computed successfully ");
 bResult = TRUE; 
 }
 else
 {
 printf("\nCryptGetHashParam failed,  Error=0x%.8x", GetLastError());
 }



EndHash:

 if( hHash )
 CryptDestroyHash(hHash);

 if( hProv )
 CryptReleaseContext(hProv, 0);

 return bResult; 
}   

.

You can put the above function anywhere in your code and then call it using below code snippet,

BYTE byteHashbuffer[256];
DWORD dwFinalHashSize= 256;

GetSHA1Hash("test", 4, byteHashbuffer, &dwFinalHashSize);.

.

In the above code example, we use CryptCreateHash function specifying the algorithm CALG_SHA1. You can also specify CALG_SHA256 or CALG_SHA512 for later versions of same Hash family. Next we hash the input buffer CryptHashData to generate the MD5 hash. Once hash is generated we can get its length through CryptGetHashParam function by specifying flag as HP_HASHSIZE. This can be used for verification of buffer size or allocate fresh buffer. Next we call CryptGetHashParam again with flag as HP_HASHVAL to get the final MD5 hash data.

.

Note that you will get the error such as ‘Invalid Algorithm Specified’ (Error Code: 0x80090008) when you try to replace the algorithm with CALG_SHA256, CALG_SHA384  or CALG_SHA512. Because these algorithms are not supported by Microsoft Base Cryptography Provider ( PROV_RSA_FULL ).   To fix this problem you need to use the provider as PROV_RSA_AES (Microsoft Enhanced RSA and AES Cryptographic Provider) in the  CryptAcquireContext function instead of PROV_RSA_FULL.

.

So if you would like to generate hash for another family, you can just replace the Algorithm ID in the CryptCreateHash function.  Here is the list of Algorithm IDs that can be used to generate hash for most popular algorithms.

.

In the next blog post, I will be writing about various encryption/decryption examples !

.

See Also

CryptoCode: Index of All Crypto Articles