ハッシュ値計算を途中経過取得可能な様に記述する
.NETで用意されているクラスを利用する事により、ハッシュ値の取得は簡単です。
例えばSHA-1なら、以下の記述で充分です。
/// <summary>
/// 指定ファイルのSHA1ハッシュ値を取得する。
/// </summary>
/// <param name="fileName">ハッシュ値を求めるファイルのパス</param>
/// <returns>SHA1ハッシュ値</returns>
public static byte[] SHA1(string file)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
sha1.ComputeHash(fs);
return sha1.Hash;
}
}
ただ、これだと計算途中に処理を中断出来ません。また、計算途中の進捗状況を表示したいといった場合とかでも、これでは対処出来ません。
こんなときは、TransformBlock / TransformFinalBlock を使用します。これを使用して記述すると、以下の様な記述となります。
/// <summary>
/// 指定ファイルのSHA1ハッシュ値を取得する。
/// </summary>
/// <param name="fileName">ハッシュ値を求めるファイルのパス</param>
/// <returns>SHA1ハッシュ値</returns>
public static byte[] SHA1(string file)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
SHA1Managed sha1 = new SHA1Managed();
byte[] buffer = new Byte[4096];
int len = fs.Read(buffer, 0, buffer.Length);
while (fs.Position < fs.Length)
{
sha1.TransformBlock(buffer, 0, len, buffer, 0);
len = fs.Read(buffer, 0, buffer.Length);
}
sha1.TransformFinalBlock(buffer, 0, len);
return sha1.Hash;
}
}
余談ですが、最初 TransformBlock の引数指定でなぜ outputBuffer, outputOffset の指定がいるのか理解に苦しみました。どうやら暗号化クラスで使用している ICryptoTransform インターフェイスを使いまわしているだけの様です。実際使用してみると、outputBuffer は使用してないらしく、MSDNのサンプルの様に inputBuffer と同じバイト配列を指定して問題ない様です(バイト配列は書き換えられない)。