目次
概要
受信したデータとデジタル署名、そして送信者の公開鍵を使用して、データが改ざんされていないこと(完全性)と、正しい送信者から送られたこと(真正性)を検証する実装です。 .NETのモダンな実装では、古い RSAPKCS1SignatureDeformatter クラスではなく、RSA クラスの VerifyData メソッドを使用してシンプルかつ安全に判定を行います。
仕様(入出力)
- 入力:
- 検証対象のテキストデータ(UTF-8)
- デジタル署名(Base64文字列)
- 送信者のRSA公開鍵(XML形式文字列)
- 出力: 検証結果(
bool: 改ざんがなければtrue、不整合ならfalse) - 前提: 署名作成時と同じハッシュアルゴリズム(例: SHA256)とパディングモード(例: PKCS#1)を使用すること。
基本の使い方
using System.Security.Cryptography;
using System.Text;
// 署名検証用のメソッド呼び出し
bool isValid = ValidateSignature(originalData, signatureBase64, publicKeyXml);
if (isValid)
{
Console.WriteLine("署名は有効です。信頼できるデータです。");
}
else
{
Console.WriteLine("警告:署名が無効、またはデータが改ざんされています。");
}
コード全文
署名の検証ロジックと、動作確認用のテストコードを含んだコンソールアプリケーションです。
using System;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main()
{
// 1. テストデータの準備
// 本来はネットワーク経由などで受け取ったデータと署名を使用します
string receivedMessage = "OrderConfirmed: ID-998877";
// テスト用に、この場限りのキーペアと署名を生成します(本来は不要な処理)
GenerateTestEnvironment(receivedMessage, out string publicKeyXml, out string validSignature);
Console.WriteLine($"[Received Message] {receivedMessage}");
Console.WriteLine($"[Public Key] Found XML key info.");
Console.WriteLine($"[Signature] {validSignature.Substring(0, 20)}...");
// 2. 正常な署名の検証
Console.WriteLine("\n--- Test 1: Valid Signature ---");
bool result1 = VerifyDigitalSignature(receivedMessage, validSignature, publicKeyXml);
Console.WriteLine($"Verification Result: {(result1 ? "OK (Trusted)" : "NG (Tampered)")}");
// 3. 改ざんされたデータの検証
Console.WriteLine("\n--- Test 2: Tampered Data ---");
string tamperedMessage = "OrderConfirmed: ID-000000"; // IDを書き換え
bool result2 = VerifyDigitalSignature(tamperedMessage, validSignature, publicKeyXml);
Console.WriteLine($"Verification Result: {(result2 ? "OK (Trusted)" : "NG (Tampered)")}");
}
/// <summary>
/// メッセージ、署名、公開鍵を受け取り、正当性を検証します
/// </summary>
/// <param name="data">検証対象の元データ</param>
/// <param name="signatureBase64">Base64形式の署名</param>
/// <param name="publicKeyXml">XML形式のRSA公開鍵</param>
/// <returns>署名が有効ならtrue</returns>
static bool VerifyDigitalSignature(string data, string signatureBase64, string publicKeyXml)
{
try
{
// データのバイト配列化
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
// 署名のバイト配列化
byte[] signatureBytes = Convert.FromBase64String(signatureBase64);
// RSAインスタンスの作成
using var rsa = RSA.Create();
// 公開鍵の読み込み
// ※XML形式以外(PEM等)の場合は ImportFromPem を使用してください
rsa.FromXmlString(publicKeyXml);
// 検証の実行
// 重要: 署名作成時と同じ「ハッシュアルゴリズム」と「パディング」を指定する必要があります
return rsa.VerifyData(
dataBytes,
signatureBytes,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
}
catch (FormatException)
{
Console.WriteLine("Error: Invalid Base64 signature format.");
return false;
}
catch (CryptographicException ex)
{
Console.WriteLine($"Error: {ex.Message}");
return false;
}
}
// テスト用の署名生成ヘルパー(署名作成側のロジック)
static void GenerateTestEnvironment(string msg, out string pubKey, out string sig)
{
using var rsa = RSA.Create(2048);
pubKey = rsa.ToXmlString(false);
byte[] data = Encoding.UTF8.GetBytes(msg);
byte[] sigBytes = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
sig = Convert.ToBase64String(sigBytes);
}
}
カスタムポイント
- ハッシュアルゴリズムの整合性:
HashAlgorithmName.SHA256は署名作成側と完全に一致している必要があります。もし署名側がSHA1やSHA512を使用している場合は、ここを変更してください。 - パディングモード:
RSASignaturePadding.Pkcs1は最も一般的ですが、新しいシステムではより堅牢なPssが使われることがあります。仕様書を確認して選択してください。 - 公開鍵の形式: 入力例に合わせて
FromXmlStringを使用していますが、OpenSSL系で生成されたキーを使用する場合はImportFromPemやImportSubjectPublicKeyInfoを使用する実装に切り替えてください。
注意点
- 検証の失敗要因:
VerifyDataがfalseを返す場合、データが改ざんされている以外にも、「公開鍵が違う」「ハッシュアルゴリズムが不一致」「エンコーディング(UTF-8/Shift-JIS)が違う」といった原因が考えられます。 - 古いAPIの利用:
RSAPKCS1SignatureDeformatterクラスを使用するコードは、現代の .NET 環境では冗長であり推奨されません。RSAクラスに統合されたメソッドを使用することで、簡潔かつクロスプラットフォームなコードになります。 - 例外処理: Base64文字列が壊れている場合や、XMLキーの形式が不正な場合は例外が発生します。検証メソッド内ではこれらを適切にキャッチし、システムのクラッシュを防ぐ必要があります。
応用
ハッシュ値(ダイジェスト)を直接検証する場合
データ全体ではなく、計算済みのハッシュ値だけを受け取って検証する場合の実装です。
static bool VerifyHashDirectly(byte[] hashDigest, byte[] signature, string publicKeyXml)
{
using var rsa = RSA.Create();
rsa.FromXmlString(publicKeyXml);
// VerifyDataではなくVerifyHashを使用
return rsa.VerifyHash(
hashDigest,
signature,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
}
まとめ
デジタル署名の検証は、RSA.VerifyData メソッド一つで完結します。重要なのは、署名作成時と「ハッシュアルゴリズム」「パディング方式」を完全に一致させることです。これらが食い違っていると、正しいデータであっても検証は必ず失敗します。XML形式のキーは.NET特有の形式であるため、外部システムと連携する際はPEM形式への対応も視野に入れた設計を行うと柔軟性が向上します。
