[Windows编程笔记]HASH值的计算
2021-09-24 09:01 rnss 阅读(1164) 评论(0) 编辑 收藏 举报
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对象句柄。
小结