【C#】ハッシュ値を用いたデータの整合性検証

目次

概要

データが通信や保存の過程で改ざん・破損していないかを検証する実装です。 元のデータから算出されたハッシュ値(ダイジェスト)と、検証対象データのハッシュ値を比較することで、1ビットでも差異があれば不正とみなす厳密なチェックを行います。

仕様(入出力)

  • 入力:
    • 検証したい文字列データ
    • 正解となる期待ハッシュ値(バイト配列)
  • 出力: 一致しているかどうかの真偽値(bool
  • 動作: 入力データから再度ハッシュを計算し、期待値と突き合わせを行います。

基本の使い方

using System.Security.Cryptography;
using System.Text;

// 比較対象のデータ
var commands = "Execute_System_Update";
var validHash = GetHash(commands); // 本来はDB等から取得

// 検証
if (VerifyIntegrity(commands, validHash))
{
    Console.WriteLine("データは正当です。");
}

コード全文

このコードは、ハッシュ生成とバイト配列の比較ロジックを含むコンソールアプリケーションです。

using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

class Program
{
    static void Main()
    {
        // 1. テストデータの準備
        // サーバーの設定ファイルや、重要なトランザクションデータを想定
        string criticalData = "ConfigVersion=2.5;Mode=Secure;";
        
        Console.WriteLine($"[Target Data] {criticalData}");

        // 2. 正解データのハッシュ値を生成
        // 実運用では、このハッシュ値は信頼できる場所(DBや別経路)から取得します
        byte[] trustedHash = ComputeSha256Hash(criticalData);
        Console.WriteLine($"[Trusted Hash] {Convert.ToBase64String(trustedHash)}\n");

        // 3. 正常なデータでの検証(Trueになるべき)
        string incomingData1 = "ConfigVersion=2.5;Mode=Secure;";
        bool isSafe1 = ValidateHash(incomingData1, trustedHash);
        Console.WriteLine($"Check 1 (Valid):   {isSafe1}");

        // 4. 改ざんされたデータでの検証(Falseになるべき)
        string incomingData2 = "ConfigVersion=2.5;Mode=Insecure;"; // 一部書き換え
        bool isSafe2 = ValidateHash(incomingData2, trustedHash);
        Console.WriteLine($"Check 2 (Invalid): {isSafe2}");
    }

    /// <summary>
    /// 文字列からSHA256ハッシュを計算して返します
    /// </summary>
    static byte[] ComputeSha256Hash(string input)
    {
        // エンコーディングはUTF-8で統一するのが一般的です
        byte[] buffer = Encoding.UTF8.GetBytes(input);

        // SHA256インスタンス生成(Create推奨)
        using var algorithm = SHA256.Create();
        return algorithm.ComputeHash(buffer);
    }

    /// <summary>
    /// データが期待するハッシュ値と一致するか検証します
    /// </summary>
    static bool ValidateHash(string input, byte[] expectedHash)
    {
        // 検証対象データのハッシュを計算
        byte[] actualHash = ComputeSha256Hash(input);

        // 配列の中身を比較
        // SequenceEqualはLINQに含まれます
        return actualHash.SequenceEqual(expectedHash);
    }
}

カスタムポイント

  • 比較アルゴリズムの変更: セキュリティ強度を最大化する場合、通常の SequenceEqual ではなく System.Security.Cryptography.CryptographicOperations.FixedTimeEquals を使用してください。処理時間を一定にすることで、計算時間から正解を推測される「タイミング攻撃」を防ぐことができます。
  • アルゴリズムの強度: ここでは標準的な SHA256 を使用していますが、より高速性を重視するなら SHA1(非推奨)、より強度を重視するなら SHA512Create メソッドを変更するだけで対応できます。

注意点

  1. エンコーディングの不一致: ハッシュ値はバイト配列に対して計算されます。同じ文字列でも UTF-8Shift-JIS では全く異なるハッシュ値になるため、システム全体でエンコーディングを厳密に統一してください。
  2. 不可逆性: ハッシュ値から元のデータを復元することは不可能です。データのバックアップ目的には使えません。
  3. アルゴリズムの寿命: MD5SHA1 は既に衝突耐性が破られているため、セキュリティ目的(改ざん検知やパスワード検証)では使用せず、必ず SHA256 以上を選択してください。

応用

タイミング攻撃に強い比較メソッド

パスワードハッシュや認証トークンの検証に適した実装です。

static bool ValidateSecurely(string input, byte[] expectedHash)
{
    byte[] actualHash = ComputeSha256Hash(input);
    
    // データ長や内容に関わらず一定時間で比較を行う
    return CryptographicOperations.FixedTimeEquals(actualHash, expectedHash);
}

まとめ

データの整合性検証は、入力データを同じアルゴリズムでハッシュ化し、期待値とバイナリレベルで比較することで実現します。実装時はシステム全体でのエンコーディング統一が必須であり、セキュリティが関わる認証機能などで利用する場合は、比較処理自体もタイミング攻撃への対策を講じたメソッドを使用する必要があります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次