HASH就是把任意長度的輸入通過HASH算法變換成固定長度的輸出,該輸出就是HASH值。
函數介紹
// 用於獲取特定加密服務提供程序(CSP)內特定密鑰容器的句柄,返回的句柄使用選定CSP的CryptoAPI函數。 BOOL CryptAcquireContextA( HCRYPTPROV *phProv, // 指向CSP句柄的指針。當完成CSP時,通過調用CryptReleaseContext函數釋放句柄。 LPCSTR szContainer, // NULL LPCSTR szProvider, // NULL DWORD dwProvType, // PROV_RSA_AES表示支持RSA、AES、HASH算法 DWORD dwFlags // CRYPT_VERIFYCONTEXT表示程序不需要使用公鑰/私鑰對,例如只執行HASH和對稱加密 ); BOOL CryptCreateHash( HCRYPTPROV hProv, // CryptAcquireContextA創建的CSP句柄 ALG_ID Algid, // 要使用的HASH算法,由用戶傳入 HCRYPTKEY hKey, // NULL DWORD dwFlags, // NULL HCRYPTHASH *phHash // 新哈希對象的地址 ); BOOL CryptHashData( HCRYPTHASH hHash, // CryptCreateHash創建的哈希對象的句柄 const BYTE *pbData, // 指向要計算HASH的數據的指針 DWORD dwDataLen, // 要計算的數據的字節數 DWORD dwFlags // 0 ); BOOL CryptGetHashParam( HCRYPTHASH hHash, // CryptCreateHash創建的哈希對象的句柄 DWORD dwParam, // 查詢類型。可以選擇查詢HASH結果的大小或HASH值 BYTE *pbData, // 指向接收數據的緩沖區的指針 DWORD *pdwDataLen, // pbData的字節數 DWORD dwFlags // 0 );
編碼實現
代碼來自https://www.jb51.net/books/755116.html
// CryptoApi_Hash_Test.cpp : 定義控制台應用程序的入口點。 // #include <stdio.h> #include <Windows.h> #include <tchar.h> void ShowError(char *pszText) { char szErr[MAX_PATH] = { 0 }; ::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError()); #ifdef _DEBUG ::MessageBox(NULL, szErr, "ERROR", MB_OK | MB_ICONERROR); #endif } BOOL GetFileData(char *pszFilePath, BYTE **ppFileData, DWORD *pdwFileDataLength) { BOOL bRet = TRUE; BYTE *pFileData = NULL; DWORD dwFileDataLength = 0; HANDLE hFile = NULL; DWORD dwTemp = 0; do { hFile = ::CreateFile(pszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); if (INVALID_HANDLE_VALUE == hFile) { bRet = FALSE; ShowError("CreateFile"); break; } dwFileDataLength = ::GetFileSize(hFile, NULL); pFileData = new BYTE[dwFileDataLength]; if (NULL == pFileData) { bRet = FALSE; ShowError("new"); break; } ::RtlZeroMemory(pFileData, dwFileDataLength); ::ReadFile(hFile, pFileData, dwFileDataLength, &dwTemp, NULL); // 返回 *ppFileData = pFileData; *pdwFileDataLength = dwFileDataLength; } while (FALSE); if (hFile) { ::CloseHandle(hFile); } return bRet; } BOOL CalculateHash(BYTE *pData, DWORD dwDataLength, ALG_ID algHashType, BYTE **ppHashData, DWORD *pdwHashDataLength) { HCRYPTPROV hCryptProv = NULL; HCRYPTHASH hCryptHash = NULL; BYTE *pHashData = NULL; DWORD dwHashDataLength = 0; DWORD dwTemp = 0; BOOL bRet = FALSE; do { // 獲得指定CSP的密鑰容器的句柄 bRet = ::CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); if (FALSE == bRet) { ShowError("CryptAcquireContext"); break; } // 創建一個HASH對象, 指定HASH算法 bRet = ::CryptCreateHash(hCryptProv, algHashType, NULL, NULL, &hCryptHash); if (FALSE == bRet) { ShowError("CryptCreateHash"); break; } // 計算HASH數據 bRet = ::CryptHashData(hCryptHash, pData, dwDataLength, 0); if (FALSE == bRet) { ShowError("CryptHashData"); break; } // 獲取HASH結果的大小 dwTemp = sizeof(dwHashDataLength); bRet = ::CryptGetHashParam(hCryptHash, HP_HASHSIZE, (BYTE *)(&dwHashDataLength), &dwTemp, 0); if (FALSE == bRet) { ShowError("CryptGetHashParam"); break; } // 申請內存 pHashData = new BYTE[dwHashDataLength]; if (NULL == pHashData) { bRet = FALSE; ShowError("new"); break; } ::RtlZeroMemory(pHashData, dwHashDataLength); // 獲取HASH結果數據 bRet = ::CryptGetHashParam(hCryptHash, HP_HASHVAL, pHashData, &dwHashDataLength, 0); if (FALSE == bRet) { ShowError("CryptGetHashParam"); break; } // 返回數據 *ppHashData = pHashData; *pdwHashDataLength = dwHashDataLength; } while (FALSE); // 釋放關閉 if (FALSE == bRet) { if (pHashData) { delete[]pHashData; pHashData = NULL; } } if (hCryptHash) { ::CryptDestroyHash(hCryptHash); } if (hCryptProv) { ::CryptReleaseContext(hCryptProv, 0); } return bRet; } int _tmain(int argc, _TCHAR* argv[]) { BYTE *pData = NULL; DWORD dwDataLength = 0; DWORD i = 0; BYTE *pHashData = NULL; DWORD dwHashDataLength = 0; // 讀取文件數據 GetFileData("C:\\Users\\Administrator\\Desktop\\Project8.exe", &pData, &dwDataLength); // MD5 CalculateHash(pData, dwDataLength, CALG_MD5, &pHashData, &dwHashDataLength); printf("MD5[%d]\n", dwHashDataLength); for (i = 0; i < dwHashDataLength; i++) { printf("%x", pHashData[i]); } printf("\n\n", dwHashDataLength); if (pHashData) { delete[]pHashData; pHashData = NULL; } // SHA1 CalculateHash(pData, dwDataLength, CALG_SHA1, &pHashData, &dwHashDataLength); printf("SHA1[%d]\n", dwHashDataLength); for (i = 0; i < dwHashDataLength; i++) { printf("%x", pHashData[i]); } printf("\n\n", dwHashDataLength); if (pHashData) { delete[]pHashData; pHashData = NULL; } // SHA256 CalculateHash(pData, dwDataLength, CALG_SHA_256, &pHashData, &dwHashDataLength); printf("SHA256[%d]\n", dwHashDataLength); for (i = 0; i < dwHashDataLength; i++) { printf("%x", pHashData[i]); } printf("\n\n", dwHashDataLength); if (pHashData) { delete[]pHashData; pHashData = NULL; } system("pause"); return 0; }
實現過程
首先寫一個GetFileData函數來獲取文件數據,其中用了CreateFile函數來打開文件
HANDLE CreateFileA( LPCSTR lpFileName, // 文件路徑和文件名 DWORD dwDesiredAccess, // GENERIC_READ | GENERIC_WRITE表示讀寫權限 DWORD dwShareMode, // FILE_SHARE_READ | FILE_SHARE_WRITE表示共享讀寫權限 LPSECURITY_ATTRIBUTES lpSecurityAttributes, // NULL DWORD dwCreationDisposition, // OPEN_EXISTING表示僅當文件存在時打開文件 DWORD dwFlagsAndAttributes, // FILE_ATTRIBUTE_ARCHIVE表示標記要備份或刪除的文件 HANDLE hTemplateFile // NULL );
然后用GetFileSize函數來獲取文件長度
DWORD GetFileSize( HANDLE hFile, // 文件的句柄 LPDWORD lpFileSizeHigh // NULL );
然后用ReadFile函數將文件內容讀取到新的內存空間
BOOL ReadFile( HANDLE hFile, // 文件句柄 LPVOID lpBuffer, // 指向接收文件內容的緩沖區的指針 DWORD nNumberOfBytesToRead, // 讀取的最大字節數 LPDWORD lpNumberOfBytesRead, // 接收讀取的字節數 LPOVERLAPPED lpOverlapped // NULL );
GetFileData函數返回了文件內容和文件內容長度。
接着寫了CalculateHash函數來計算HASH值,整體上就是上面的4個API函數依次用。首先用CryptAcquireContextA函數獲取一個指向CSP句柄的指針,然后用CryptCreateHash函數在CSP中創建一個空的HASH對象並獲取對象句柄,並可以指定HASH算法,接着使用CryptHashData函數來計算數據的HASH值,結果存放在HASH對象中,最后使用CryptGetHashParam函數來獲取想要的數據,可以獲取的數據有三種:HASH算法、HASH值長度、HASH值。獲取完HASH值后使用CryptReleaseContext函數釋放CSP句柄,使用CryptDestroyHash函數來釋放HASH對象句柄。
小結