はじめに
ファイル転送やバックアップ、ログ保管――データが壊れていないかを確実に判定 するしくみは、あらゆるシステムで欠かせません。
そこで登場するのが チェックサム や ハッシュ関数 。しかし名前が似ていても 目的・性能・安全性 は大きく異なります。
そこで... C#(.NET 8 以降) で扱える代表的アルゴリズムを整理し、目的別の最適解 を整理してみました。これは自分メモも兼ねています。
チェックサム vs. 暗号学的ハッシュ
まずは、チェックサムと暗号学的ハッシュの違いを再確認してみます。
種類 | 主目的 | 改ざん検知 | 衝突耐性 | 代表例 |
---|---|---|---|---|
チェックサム | 偶発的エラー検出 | ✖ | △ | CRC32、CRC64 |
暗号学的ハッシュ | 意図的改ざん検知 | ✔ | ◎ | SHA-256、BLAKE3 |
ポイントはここ!
- チェックサムはビット反転・ノイズ混入など偶発エラーを高効率で検知
- 暗号学的ハッシュは衝突計算が事実上不可能な構造で、意図的改ざんまで発見
利用シーン
それぞれの利用シーンをまとめてみました。
代表アルゴリズムと C# 実装
CRC32 ― 転送エラー検出の定番
using System.IO.Hashing;
using System.Text;
byte[] data = Encoding.UTF8.GetBytes("Hello World");
uint crc = Crc32.HashToUInt32(data);
Console.WriteLine($"CRC32 : {crc:X8}");
- 32 bit 出力・超高速・意図的改ざんには弱い
- .NET 8 以降は System.IO.Hashing 標準
MD5 / SHA-1 ― レガシー互換のみ
アルゴリズム | 出力長 | 現状 |
---|---|---|
MD5 | 128 bit | 衝突コスト ≈ 数千ドル※1―新規開発非推奨 |
SHA-1 | 160 bit | 2017 年 Google が衝突実証―段階的廃止 |
AWS/GCP の GPU で衝突が実用的に生成可能
SHA-256 ― 現行スタンダード
using var sha256 = SHA256.Create();
string hex = Convert.ToHexString(sha256.ComputeHash(data));
- 256 bit・高い安全性
- HMACSHA256 で共有鍵を混ぜると改ざん+なりすましを同時に防止
byte[] tag = new HMACSHA256(secretKey).ComputeHash(data);
SHA-3 ― 次世代標準(普及途上)
NISTが2015年にSHA-3を標準化したものの、まだ普及度は低く、多くのシステムではSHA-2系(SHA-256等)が主流です。C#でも .NET標準ライブラリには含まれておらず、サードパーティライブラリが必要です。
using SHA3.Net;
byte[] hash = Sha3.Sha3256().ComputeHash(data);
string hex = Convert.ToHexString(hash);
XXH3 ― CRC 並の速度+そこそこの衝突耐性
using System.IO.Hashing;
ulong xxh = XxHash64.HashToUInt64(data); // .NET 8 標準
- ファイル重複検出・キャッシュキー向け
- ⚠️ 重要:セキュリティ目的には絶対に使用しない(暗号学的強度なし)
BLAKE3 ― 高速 & セキュア & 並列化
using Blake3;
string hex = Hasher.Hash(data).ToHex();
- SHA-256 の 2〜10 倍速 (CPU に依存)
- NuGet
Isopoh.Cryptography.Blake3
等を利用(メンテナンス継続中の実装を選択) - 並列ストリーム API があり巨大ファイルで真価
- 注意:公式にFIPS認定はまだ(企業環境では要確認)
速度 vs セキュリティ強度マップ
図は「速度とセキュリティ強度の相対的な目安」です。
XXH3/CRC32 は高速ですが暗号学的強度がないため、改ざん検知用途には使用できません。
アルゴリズム選択マトリクス
速度 | 衝突耐性 | 改ざん検知 | 主用途 | |
---|---|---|---|---|
CRC32 | ★★★★★ | ★★ | ✖ | 転送エラー検出 |
XXH3 | ★★★★★ | ★★★ | ✖ | 重複検出/キャッシュキー |
SHA-256 | ★★ | ★★★★★ | ✔ | 改ざん検知・署名 |
BLAKE3 | ★★★★ | ★★★★★ | ✔ | 巨大ファイル/高速改ざん検知 |
用途別 C# サンプル
用途別のサンプルをいくつか置いておきます。
ファイル転送の破損検知 (CRC32)
ネットワーク転送やファイルコピー時の偶発的なビット反転を検出するシンプルな例です。送信側で計算したCRC32値と受信側で再計算した値を比較します。
uint expected = 0x4A17B156;
bool ok = Crc32.HashToUInt32(File.ReadAllBytes(path)) == expected;
ソフトウェア配布の署名検証 (SHA-256)
ダウンロードサイトで提供される公式ハッシュ値と実際のファイルを照合し、改ざんされていないことを確認します。
// ダウンロードファイルの整合性検証例
string downloadedFile = "setup.exe";
string expectedHash = "A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3";
using var sha256 = SHA256.Create();
byte[] fileHash = sha256.ComputeHash(File.ReadAllBytes(downloadedFile));
string actualHash = Convert.ToHexString(fileHash);
bool isValid = string.Equals(expectedHash, actualHash, StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"ファイル検証: {(isValid ? "OK" : "NG")}");
ログ改ざん検知 (HMAC-SHA256)
アプリケーションログが後から書き換えられていないかを検証します。秘密鍵を使ったHMACにより、内容の完全性と真正性を同時に担保できます。
// ログファイルの改ざん検知システム例
string logContent = File.ReadAllText("app.log");
byte[] secretKey = Convert.FromBase64String("your-secret-key");
// ハッシュ生成
byte[] hash = new HMACSHA256(secretKey)
.ComputeHash(Encoding.UTF8.GetBytes(logContent));
string hashHex = Convert.ToHexString(hash);
// 検証
bool isValid = new HMACSHA256(secretKey)
.ComputeHash(Encoding.UTF8.GetBytes(logContent))
.SequenceEqual(Convert.FromHexString(storedHashHex));
重複ファイル削除ツール (XXH3)
大量のファイルから重複を高速検出する際に活用します。暗号学的強度は不要で、速度重視のため非暗号ハッシュXXH3が最適です。
// 高速な重複ファイル検出
var fileHashes = new Dictionary<ulong, List<string>>();
foreach (string file in Directory.EnumerateFiles(targetDir, "*", SearchOption.AllDirectories))
{
ulong hash = XxHash64.HashToUInt64(File.ReadAllBytes(file));
if (!fileHashes.ContainsKey(hash))
fileHashes[hash] = new List<string>();
fileHashes[hash].Add(file);
}
// 重複ファイル表示
foreach (var (hash, files) in fileHashes.Where(kv => kv.Value.Count > 1))
{
Console.WriteLine($"重複グループ (Hash: {hash:X16}):");
foreach (string file in files)
Console.WriteLine($" {file}");
}
実装時の落とし穴
-
Dispose 忘れ
HashAlgorithm
はusing
で確実に解放。 -
大小文字比較
StringComparison.OrdinalIgnoreCase
を必ず指定。 -
I/O と CPU の分離
await file.CopyToAsync()
など I/O 非同期を優先、Task.Run
連発は避ける。 -
平文ハッシュの過信
ハッシュ値をそのまま公開するとリプレイ攻撃の温床。秘密鍵入り HMAC か署名を。 -
XXH3 の誤用
高速だがセキュリティ強度なし。改ざん検知には使用禁止。
選択フロー(まとめ)
参考資料
- Microsoft Docs – System.IO.Hashing, System.Security.Cryptography
- NIST SP 800-107 – Recommendation for Applications Using Approved Hash Algorithms (Rev.1, 2012)
- Google Research Blog – "SHA-1 is a Shambles" (2017)
- BLAKE3 white-paper – "BLAKE3: One Function, Fast Everywhere" (2020)
おわりに
「早い=安全」ではありません。 目的に合ったアルゴリズムを選び、必要なら HMAC やデジタル署名を組み合わせてこそ、パフォーマンスと信頼性の両立が実現できます。