【C#】RSAとSHA256によるデジタル署名の生成

目次

概要

RSA秘密鍵を使用して、任意のデータに対するデジタル署名(電子署名)を作成する実装です。 デジタル署名を付与することで、データの送信者が本人であること(真正性)と、データが途中で改ざんされていないこと(完全性)を保証できます。 .NETの現代的な実装では、古い AsymmetricSignatureFormatter を使用せず、RSA クラスの SignData メソッドでハッシュ計算から署名生成までを一括で行うのが一般的です。

仕様(入出力)

  • 入力:
    • 署名対象のテキストデータ
    • RSA秘密鍵
  • 出力: 生成されたデジタル署名(Base64文字列)
  • プロセス: 対象データをSHA256でハッシュ化し、そのハッシュ値をRSA秘密鍵で暗号化して署名を生成します。

基本の使い方

C#

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

var data = Encoding.UTF8.GetBytes("重要な契約書データ");

using var rsa = RSA.Create();
rsa.ImportFromPem(privateKeyPem); // 秘密鍵の読み込み

// ハッシュ計算と署名を一発で実行
// (パディングは互換性の高いPKCS1、またはより堅牢なPssを選択)
byte[] signature = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

コード全文

このコードは、鍵ペアの生成から署名の作成、そして検証(署名が正しいことの確認)までの一連の流れを示したコンソールアプリケーションです。

C#

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

class Program
{
    static void Main()
    {
        // 1. 署名対象のメッセージ
        string contractText = "Author: John Doe, Date: 2025-01-01, Content: Approved";
        Console.WriteLine($"[Document] {contractText}");

        // 2. RSAキーの準備(本来は保存された鍵を読み込みます)
        using var rsa = RSA.Create(2048);
        
        // 秘密鍵(署名作成に使用)
        // 実際にはAzure Key Vaultや安全なストレージから取得します
        string privateKeyPem = rsa.ExportRSAPrivateKeyPem();

        // 公開鍵(検証に使用)
        // 受信者に渡す鍵です
        string publicKeyPem = rsa.ExportSubjectPublicKeyPem();

        // 3. デジタル署名の生成
        try
        {
            string signatureBase64 = GenerateDigitalSignature(contractText, privateKeyPem);

            Console.WriteLine("\n[Signature Generated]");
            Console.WriteLine(signatureBase64);

            // 4. (参考) 生成された署名の検証
            // 別途検証ロジックで「データ」と「署名」と「公開鍵」から正当性を確認します
            bool isValid = VerifySignature(contractText, signatureBase64, publicKeyPem);
            Console.WriteLine($"\n[Verification Result] {isValid}");
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }

    /// <summary>
    /// メッセージと秘密鍵を受け取り、デジタル署名(Base64)を返します
    /// </summary>
    static string GenerateDigitalSignature(string message, string privateKeyPem)
    {
        // データのバイト配列化
        byte[] dataBytes = Encoding.UTF8.GetBytes(message);

        using var rsa = RSA.Create();
        rsa.ImportFromPem(privateKeyPem);

        // SignDataメソッド: ハッシュ化と署名を内部でまとめて実行します
        // 第2引数: ハッシュアルゴリズム (SHA256推奨)
        // 第3引数: パディングモード (Pkcs1 または Pss)
        byte[] signatureBytes = rsa.SignData(
            dataBytes, 
            HashAlgorithmName.SHA256, 
            RSASignaturePadding.Pkcs1);

        return Convert.ToBase64String(signatureBytes);
    }

    /// <summary>
    /// 参考用の検証メソッド
    /// </summary>
    static bool VerifySignature(string message, string signatureBase64, string publicKeyPem)
    {
        byte[] dataBytes = Encoding.UTF8.GetBytes(message);
        byte[] signatureBytes = Convert.FromBase64String(signatureBase64);

        using var rsa = RSA.Create();
        rsa.ImportFromPem(publicKeyPem);

        return rsa.VerifyData(
            dataBytes, 
            signatureBytes, 
            HashAlgorithmName.SHA256, 
            RSASignaturePadding.Pkcs1);
    }
}

カスタムポイント

  • パディングモード: コード例では互換性が高い RSASignaturePadding.Pkcs1 を使用していますが、新規システムの構築で互換性を気にする必要がない場合は、よりセキュリティ強度の高い RSASignaturePadding.Pss の使用を検討してください。
  • ハッシュアルゴリズム: HashAlgorithmName.SHA256 が現在の標準ですが、より高いセキュリティレベルが必要な場合は SHA384SHA512 に変更可能です。署名側と検証側で必ず一致させる必要があります。

注意点

  1. 秘密鍵の漏洩: 署名を作成できるのは秘密鍵の所有者だけです。秘密鍵が流出すると、第三者が本人になりすまして署名を作成できてしまうため、厳重な管理が必要です。
  2. 検証側の設定一致: 署名を検証する際は、「元のデータ」「ハッシュアルゴリズム(SHA256等)」「パディング(PKCS1等)」がすべて生成時と一致している必要があります。
  3. レガシー実装の回避: RSAPKCS1SignatureFormatterSHA256Managed は古いAPIであり、クロスプラットフォーム対応やパフォーマンスの観点から推奨されません。RSA クラスのメソッドを使用してください。

応用

ハッシュ値から署名を作成する場合 (SignHash)

すでにデータ全体のハッシュ値(ダイジェスト)だけ手元にある場合の実装です。大きなファイルをストリームで読み込み、ハッシュだけ先に計算した際などに使用します。

C#

static byte[] SignHashDirectly(byte[] hashDigest, string privateKeyPem)
{
    using var rsa = RSA.Create();
    rsa.ImportFromPem(privateKeyPem);

    // SignDataではなくSignHashを使用する
    // ハッシュアルゴリズム名は、渡されたハッシュ値の生成に使ったものを指定する
    return rsa.SignHash(hashDigest, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

まとめ

.NETにおけるデジタル署名の作成は RSA.SignData メソッドを使用することで、ハッシュ計算と署名生成を安全かつ簡潔に実装できます。署名方式(パディングやハッシュアルゴリズム)はシステムのセキュリティ要件と互換性要件に基づいて選択し、署名の信頼性の根幹である秘密鍵の管理には最善の策を講じることが重要です。

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

この記事を書いた人

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

目次