Windows 95 OSR2以降に対応するCryptHashDataを利用すると簡単にハッシュを求めれる。ここではこのAPIを利用して、メモリ上のデータ、ファイル、IStreamのデータのハッシュを求めるクラスを作成した。簡単に利用できるのはMD2、MD4、MD5、SHA-1ハッシュだが、SHA-256などほかのハッシュもdwFlagsに指定することで計算できる。
「DnpHashEx.h」として保存
#pragma once
#include <wincrypt.h>
#include "objidl.h"
//
//Crypt関連APIを利用してハッシュを計算する
//
//Windows95OSR2以降
//
class CDnpHashEx
{
public:
//
// MD2ハッシュ計算(128ビット)
//
bool GetMD2Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[16])
{
return GetHash(pData,dwLen,pcbHashData,16,CALG_MD2);
}
//
// MD4ハッシュ計算(128ビット)
//
bool GetMD4Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[16])
{
return GetHash(pData,dwLen,pcbHashData,16,CALG_MD4);
}
//
// MD5ハッシュ計算(128ビット)
//
bool GetMD5Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[16])
{
return GetHash(pData,dwLen,pcbHashData,16,CALG_MD5);
}
//
// SHA-1ハッシュ計算(160ビット)
//
bool GetSHA1Hash(const void* pData,DWORD dwLen,BYTE pcbHashData[20])
{
return GetHash(pData,dwLen,pcbHashData,20,CALG_SHA1);
}
//
// 各種ハッシュ計算
//
bool GetHash(const void* pData,DWORD dwLen,BYTE* pcbHashData,DWORD dwHashLen,DWORD dwFlags)
{
bool ret;
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
BYTE pbHash[0x7f];
::ZeroMemory(pcbHashData,dwHashLen);
if(pData == NULL || dwLen == 0 || dwHashLen == 0 || dwHashLen > 0x7f)
{
ATLASSERT(0);
return false;
}
hHash = NULL;
hCryptProv = NULL;
ret = false;
if(::CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))
{
if(::CryptCreateHash(hCryptProv,dwFlags,0,0,&hHash))
{
if(::CryptHashData(hHash,(BYTE*)pData,dwLen,0))
{
if(::CryptGetHashParam(hHash,HP_HASHVAL,pbHash,&dwHashLen,0))
{
::memcpy_s(pcbHashData,dwHashLen,pbHash,dwHashLen);
ret = true;
}
}
}
}
if(hHash)
::CryptDestroyHash(hHash);
if(hCryptProv)
::CryptReleaseContext(hCryptProv,0);
if(ret == false)
::ZeroMemory(pcbHashData,dwHashLen);
return ret;
}
//
// MD2ハッシュ計算(128ビット)
//
bool GetMD2FileHash(LPCTSTR pszFile,BYTE pcbHashData[16])
{
return GetFileHash(pszFile,pcbHashData,16,CALG_MD2);
}
//
// MD4ハッシュ計算(128ビット)
//
bool GetMD4FileHash(LPCTSTR pszFile,BYTE pcbHashData[16])
{
return GetFileHash(pszFile,pcbHashData,16,CALG_MD4);
}
//
// MD5ハッシュ計算(128ビット)
//
bool GetMD5FileHash(LPCTSTR pszFile,BYTE pcbHashData[16])
{
return GetFileHash(pszFile,pcbHashData,16,CALG_MD5);
}
//
// SHA-1ハッシュ計算(160ビット)
//
bool GetSHA1FileHash(LPCTSTR pszFile,BYTE pcbHashData[20])
{
return GetFileHash(pszFile,pcbHashData,20,CALG_SHA1);
}
//
// ファイルハッシュ計算
//
bool GetFileHash(LPCTSTR pszFile,BYTE* pcbHashData,DWORD dwHashLen,DWORD dwFlags)
{
bool ret;
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
BYTE pbHash[0x7f];
HANDLE hFile;
ULARGE_INTEGER lnSize;
::ZeroMemory(pcbHashData,dwHashLen);
if(pszFile == 0 || dwHashLen == 0 || dwHashLen > 0x7f)
return false;
hFile = ::CreateFile(pszFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == INVALID_HANDLE_VALUE)
return false;
//ファイルサイズ取得
lnSize.LowPart = ::GetFileSize(hFile,&lnSize.HighPart);
hHash = NULL;
hCryptProv = NULL;
ret = false;
if(::CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))
{
if(::CryptCreateHash(hCryptProv,dwFlags,0,0,&hHash))
{
BOOL bRet;
ULARGE_INTEGER lnPos;
DWORD dwRead;
BYTE pcbTmp[64000];
bRet = FALSE;
lnPos.QuadPart = 0;
while(1)
{
//64KBずつ処理
bRet = ::ReadFile(hFile,pcbTmp,64000,&dwRead,NULL);
if(bRet == FALSE)
break;
lnPos.QuadPart += dwRead;
//ハッシュ計算
bRet = ::CryptHashData(hHash,pcbTmp,dwRead,0);
if(bRet == FALSE)
break;
//処理バイト数とファイルサイズが一致したらbreak
if(lnPos.QuadPart == lnSize.QuadPart)
break;
}
//ハッシュ取得
if(bRet && ::CryptGetHashParam(hHash,HP_HASHVAL,pbHash,&dwHashLen,0))
{
::memcpy_s(pcbHashData,dwHashLen,pbHash,dwHashLen);
ret = true;
}
}
}
if(hHash)
::CryptDestroyHash(hHash);
if(hCryptProv)
::CryptReleaseContext(hCryptProv,0);
::CloseHandle(hFile);
if(ret == false)
::ZeroMemory(pcbHashData,dwHashLen);
return ret;
}
//
// MD2ハッシュ計算(128ビット)
//
bool GetMD2IStreamHash(IStream* pIStream,BYTE pcbHashData[16])
{
return GetIStreamHash(pIStream,pcbHashData,16,CALG_MD2);
}
//
// MD4ハッシュ計算(128ビット)
//
bool GetMD4IStreamHash(IStream* pIStream,BYTE pcbHashData[16])
{
return GetIStreamHash(pIStream,pcbHashData,16,CALG_MD4);
}
//
// MD5ハッシュ計算(128ビット)
//
bool GetMD5IStreamHash(IStream* pIStream,BYTE pcbHashData[16])
{
return GetIStreamHash(pIStream,pcbHashData,16,CALG_MD5);
}
//
// SHA-1ハッシュ計算(160ビット)
//
bool GetSHA1IStreamHash(IStream* pIStream,BYTE pcbHashData[20])
{
return GetIStreamHash(pIStream,pcbHashData,20,CALG_SHA1);
}
//
// IStreamからのハッシュ計算
//
bool GetIStreamHash(IStream* pIStream,BYTE* pcbHashData,DWORD dwHashLen,DWORD dwFlags)
{
bool ret;
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
BYTE pbHash[0x7f];
HRESULT hr;
LARGE_INTEGER lnPos;
STATSTG sStatstg;
::ZeroMemory(pcbHashData,dwHashLen);
if(pIStream == 0 || dwHashLen == 0 || dwHashLen > 0x7f)
return false;
//ファイル先頭へシーク
lnPos.QuadPart = 0;
hr = pIStream->Seek(lnPos,STREAM_SEEK_SET,NULL);
if(FAILED(hr))
return false;
//ファイルサイズ取得
::ZeroMemory(&sStatstg,sizeof(STATSTG));
hr = pIStream->Stat(&sStatstg,STATFLAG_DEFAULT);
if(FAILED(hr))
return false;
hHash = NULL;
hCryptProv = NULL;
ret = false;
if(::CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))
{
if(::CryptCreateHash(hCryptProv,dwFlags,0,0,&hHash))
{
BOOL bRet;
ULARGE_INTEGER lnPos;
ULONG nRead;
BYTE pcbTmp[64000];
bRet = FALSE;
lnPos.QuadPart = 0;
while(1)
{
//64KBずつ処理
hr = pIStream->Read(pcbTmp,64000,&nRead);
if(FAILED(hr))
break;
lnPos.QuadPart += nRead;
//ハッシュ計算
bRet = ::CryptHashData(hHash,pcbTmp,(DWORD)nRead,0);
if(bRet == FALSE)
break;
//処理バイト数とファイルサイズが一致したらbreak
if(lnPos.QuadPart == sStatstg.cbSize.QuadPart)
break;
}
//ハッシュ取得
if(bRet && ::CryptGetHashParam(hHash,HP_HASHVAL,pbHash,&dwHashLen,0))
{
::memcpy_s(pcbHashData,dwHashLen,pbHash,dwHashLen);
ret = true;
}
}
}
if(hHash)
::CryptDestroyHash(hHash);
if(hCryptProv)
::CryptReleaseContext(hCryptProv,0);
if(ret == false)
::ZeroMemory(pcbHashData,dwHashLen);
return ret;
}
};
依存環境:ATL
#include "atlstr.h"
#include "DnpHashEx.h"
//
// テスト用関数
//
void Test(void)
{
bool ret;
int i;
CAtlString strTmp;
CAtlString strMessage;
BYTE pcbData[20];
CDnpHashEx cHash;
//ファイルのSHA-1ハッシュを計算
ret = cHash.GetSHA1FileHash(_T("c:\\boot.ini"),pcbData);
if(ret == false)
{
::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);
return;
}
for(i = 0; i < 20; i++)
{
strTmp.Format(_T("%x"),pcbData[i]);
strMessage += strTmp;
}
::MessageBox(NULL,strMessage,_T(""),MB_OK);
}
プロジェクトファイルをダウンロード