场景
1.MD5是比较简单的文件ID, 大部分情况在安全系数要求不高时可以用它来校验文件唯一性. 比如下载文件后进行 md5计算看文件是否完整.
2.对字符串进行md5也是一样的.
例子
1.下边是使用系统自带的库或API来完成计算文件的md5, 第3方库 libgcrypt也可以做到, 就是编译比较麻烦.
Windows
#include <Wincrypt.h>
std::string AssUtil::CalcFileMD5(const char* path)
{
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";
wchar_t* filename = BASUtilityString::ConvertUtf8ToUnicode(path);
BASWrapMalloc wm(filename);
// 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();
printf("Error opening file %s\nError: %d\n", filename,
dwStatus);
return "";
}
BASWrapHandle<CloseHandle> wh_file(hFile);
// Get handle to the crypto provider
if (!CryptAcquireContext(&hProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
return "";
}
auto my_hProv = [](HCRYPTPROV* hProv1){CryptReleaseContext(*hProv1, 0);};
std::unique_ptr<HCRYPTPROV,decltype(my_hProv)> p1(&hProv,my_hProv);
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
return "";
}
auto my_hHash = [](HCRYPTHASH* hHash){CryptDestroyHash(*hHash);};
std::unique_ptr<HCRYPTHASH,decltype(my_hHash)> p2(&hHash,my_hHash);
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);
return "";
}
}
if (!bResult)
{
dwStatus = GetLastError();
printf("ReadFile failed: %d\n", dwStatus);
return "";
}
cbHash = MD5LEN;
std::string result;
if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
{
printf("MD5 hash of file %s is: ", filename);
for (DWORD i = 0; i < cbHash; i++)
{
printf("%c%c", rgbDigits[rgbHash[i] >> 4],rgbDigits[rgbHash[i] & 0xf]);
result.append(1,rgbDigits[rgbHash[i] >> 4]);
result.append(1,rgbDigits[rgbHash[i] & 0xf]);
}
printf("\n");
}
else
{
dwStatus = GetLastError();
printf("CryptGetHashParam failed: %d\n", dwStatus);
}
return result;
}
macOS
#include <CommonCrypto/CommonDigest.h>
std::string AssUtil::CalcFileMD5(const char* path)
{
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5_CTX ctx;
CC_MD5_Init(&ctx);
char buf[1024];
FILE* file = fopen(path, "rb");
while (!feof(file)) {
auto readed = fread(buf, 1, 1024, file);
CC_MD5_Update(&ctx,buf,(CC_LONG)readed);
}
fclose(file);
CC_MD5_Final(digest,&ctx);
std::string result;
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++){
android::base::StringAppendF(&result,"%02x", digest[i]);
}
//std::cout << result << std::endl;
return result;
}