
MD5をだしてみる
もう3週間ぐらい前の話ですが。
ファイルの改ざんをチェックする方法としてMD5を算出して、オリジナルのファイルとの相違がないことを調べるという方法があります。余談ですが、Winnyで特定のファイルを示すためのハッシュもファイルのMD5らしいですね。
というわけで、ちょっとファイルの改ざんチェックをしようと思ってMD5を算出してみようと思ったのですが、MD5ってどうやって算出するんだろうなぁ、というか、Windowsにファイルハンドル渡したらMD5がぽんと出てくるようなAPIは用意されていないのか!
…用意されてなかったようですが、某所で聞いたらWinNT系で使えるCryptAPIでMD5を算出することができるらしいので、これでやってみることに。ということで、「ファイルハンドルを渡したらぽんっとMD5が出てくるようなAPI」をここに書いておきます。
#include <windows.h>
#include <wincrypt.h>
char* CalcMD5(HANDLE hFile, char* szBuf){
*szBuf=NULL;
if(hFile==INVALID_HANDLE_VALUE){ // fail to open
return NULL;
}
// calc MD5
HCRYPTPROV hCryptProv=NULL;
HCRYPTHASH hHash;
// PROV_RSA_FULL support MD5 hash
if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)){
return NULL;
}
// create empty md5 hash
if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash)){
return NULL;
}
// read file and add to hashdata
BYTE tmpBuf[4096];
DWORD dwRead;
while(ReadFile(hFile, tmpBuf, 4096, &dwRead, NULL) && dwRead){
if(!CryptHashData(hHash, tmpBuf, dwRead, 0)){ // add hash
return NULL;
}
}
// calculate hash
DWORD dwHashLen;
BYTE *pbHash;
if(!CryptGetHashParam(hHash, HP_HASHVAL, NULL, &dwHashLen, NULL)){ // get hash size
return NULL;
}
if(!(pbHash=new BYTE[dwHashLen])){
return NULL;
}
if(!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, NULL)){ // get hash
delete [] pbHash;
return NULL;
}
// print hash
char tmp[16];
*szBuf=NULL;
for(DWORD i=0;i<dwHashLen; i++){
sprintf(tmp, _t("%2.2x"), pbHash[i]);
strcat(szBuf, tmp);
}
// destroy
delete [] pbHash;
return szBuf;
}
まぁ、たぶんこんな感じで動くと思います。MD5を格納するのに十分な配列(基本的には32バイトぐらいは必要?)と、Read可能なファイルハンドルをわたすと、配列にMD5を突っ込んでくれます。算出に失敗したときはNULL、成功したときは配列の先頭を返します。
…こんな関数を書かなくても、本気になればRFC1321よめばちゃんとCのサンプルコードも載ってるのでそっち使った方が早かったり…とか言っちゃダメですよ。