每天資訊基於win32的用C語言計算MD5的實現

菜單

基於win32的用C語言計算MD5的實現

想看演算法原理的不用看了。這裡直接用的現成的輪子。

基於win32的用C語言計算MD5的實現

正文開始之前,請容我先吐個槽。之前想比對我下載的一大堆影片,把重複的刪掉,所以需要計算檔案的MD5值。用Python的hashlib,我很快就寫出來幹活的指令碼。但是呢,我忽然覺得這不夠“優雅”——Windows畢竟不自帶Python。於是,我就想把它編譯成應用程式,至少是個命令列工具吧。

就這樣,我撿起許久不用的C。這玩意真的好坑啊,#include和import根本不是一回事……C語言設計之初就是為了解決跨平臺的問題,它的解決思路是由平臺提供編譯器。問題在於,VC++的庫和GCC的庫是一回事嗎?我感覺,還是一個平臺寫一套程式碼。

雖然Windows的文件一點都不好用,但是內容還是非常詳細的。下面的程式碼修改自文件中的一個C語言示例,原文連結:

https://docs。microsoft。com/en-us/windows/win32/seccrypto/example-c-program——creating-an-md-5-hash-from-file-content

程式碼(B站的程式碼塊功能簡直智*,請自行修改標頭檔案):

#include “stdio。h”

#include “windows。h”

#include “Wincrypt。h”

#include “wchar。h”

#define BUFSIZE 1024

#define MD5LEN 32

DWORD wmain(int argc, wchar_t *argv[])

{

DWORD dwStatus = 0;

BOOL bResult = FALSE;

HCRYPTPROV hProv = 0;

HCRYPTHASH hHash = 0;

HANDLE hFile = NULL;

BYTE rgbFile[BUFSIZE];

DWORD cbRead = 0;

BYTE rgbHash[MD5LEN];

DWORD cbHash = 0;

CHAR rgbDigits[] = “0123456789abcdef”;

LPCWSTR filename = argv[1];

// Logic to check usage goes here。

hFile = CreateFile(filename,

GENERIC_READ,

FILE_SHARE_READ,

NULL,

OPEN_EXISTING,

FILE_FLAG_SEQUENTIAL_SCAN,

NULL);

if (INVALID_HANDLE_VALUE == hFile)

{

dwStatus = GetLastError();

wprintf(L“Error opening file %ls\nError: %d\n”, filename,

dwStatus);

return dwStatus;

}

// Get handle to the crypto provider

if (!CryptAcquireContext(&hProv,

NULL,

NULL,

PROV_RSA_FULL,

CRYPT_VERIFYCONTEXT))

{

dwStatus = GetLastError();

printf(“CryptAcquireContext failed: %d\n”, dwStatus);

CloseHandle(hFile);

return dwStatus;

}

if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))

{

dwStatus = GetLastError();

printf(“CryptAcquireContext failed: %d\n”, dwStatus);

CloseHandle(hFile);

CryptReleaseContext(hProv, 0);

return dwStatus;

}

while (bResult = ReadFile(hFile, rgbFile, BUFSIZE,

&cbRead, NULL))

{

if (0 == cbRead)

{

break;

}

if (!CryptHashData(hHash, rgbFile, cbRead, 0))

{

dwStatus = GetLastError();

printf(“CryptHashData failed: %d\n”, dwStatus);

CryptReleaseContext(hProv, 0);

CryptDestroyHash(hHash);

CloseHandle(hFile);

return dwStatus;

}

}

if (!bResult)

{

dwStatus = GetLastError();

printf(“ReadFile failed: %d\n”, dwStatus);

CryptReleaseContext(hProv, 0);

CryptDestroyHash(hHash);

CloseHandle(hFile);

return dwStatus;

}

cbHash = MD5LEN;

if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))

{

for (DWORD i = 0; i < cbHash; i++)

{

printf(“%c%c”, rgbDigits[rgbHash[i] >> 4],

rgbDigits[rgbHash[i] & 0xf]);

}

wprintf(L“ %ls”, filename);

printf(“\n”);

}

else

{

dwStatus = GetLastError();

printf(“CryptGetHashParam failed: %d\n”, dwStatus);

}

CryptDestroyHash(hHash);

CryptReleaseContext(hProv, 0);

CloseHandle(hFile);

return dwStatus;

}

功能與Linux的md5sum命令基本一致,效果如下:

基於win32的用C語言計算MD5的實現

使用PowerShell的Get-FileHash命令進行驗算,結果如下:

基於win32的用C語言計算MD5的實現

已知Bug:非英文字元可能無法正確顯示,但是不影響MD5值的計算。