【C#】RSA秘密鍵を使用した暗号化データの復号

目次

概要

RSA暗号化方式で暗号化されたデータを、対となる秘密鍵(XML形式)を使用して元のテキストに戻す(復号する)実装です。 .NETのバージョンに依存しない抽象クラス RSA を使用し、セキュリティ強度の高いパディング方式を指定して安全にデータを復号します。

仕様(入出力)

  • 入力:
    • 暗号化されたデータ(Base64形式の文字列)
    • RSA秘密鍵(XML形式の文字列)
  • 出力: 復号された平文(UTF-8文字列)
  • 前提: 暗号化時に使用されたパディングモード(OAEP SHA256等)が判明していること。

基本の使い方

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

// RSAインスタンスの生成
using var rsa = RSA.Create();
rsa.FromXmlString(privateKeyXml);

// Base64からバイト配列へ戻す
byte[] encryptedBytes = Convert.FromBase64String(encryptedBase64String);

// 復号(暗号化時と同じパディングを指定:ここではOAEP SHA256)
byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);

// 文字列へ変換
string originalMessage = Encoding.UTF8.GetString(decryptedBytes);

コード全文

このコードは、自己完結して動作確認ができるよう、内部で一時的なキー生成と暗号化を行ってから、復号処理の実演を行います。

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

class Program
{
    static void Main()
    {
        // --- 準備フェーズ(通常は外部からデータを受け取ります) ---
        
        // 1. テスト用のRSAキーペア(2048ビット)を生成
        using var setupRsa = RSA.Create(2048);
        
        // 秘密鍵の取得(復号に必要)
        string privateKeyXml = setupRsa.ToXmlString(includePrivateParameters: true);
        
        // 公開鍵の取得(暗号化に必要)
        string publicKeyXml = setupRsa.ToXmlString(includePrivateParameters: false);

        // 2. 復号対象となる暗号化データを作成(公開鍵を使用)
        string originalSecret = "This is a top secret message.";
        string encryptedBase64 = PerformEncryptionForTest(originalSecret, publicKeyXml);

        Console.WriteLine($"[Encrypted Data]\n{encryptedBase64}\n");


        // --- 実装フェーズ(ここからが本題の復号処理です) ---

        try
        {
            // 3. 秘密鍵を使って復号を実行
            string decryptedMessage = DecryptString(encryptedBase64, privateKeyXml);

            Console.WriteLine("[Decrypted Message]");
            Console.WriteLine(decryptedMessage);
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine($"Decryption failed: {ex.Message}");
        }
    }

    /// <summary>
    /// 暗号化されたBase64文字列を、RSA秘密鍵で復号します。
    /// </summary>
    static string DecryptString(string base64Data, string privateKeyXml)
    {
        // RSAインスタンス作成
        using var rsa = RSA.Create();

        // 秘密鍵をインポート(XML形式)
        // ※秘密鍵が含まれていないXMLを渡すと、復号時にエラーになります
        rsa.FromXmlString(privateKeyXml);

        // Base64文字列をバイト配列に変換
        byte[] encryptedBytes = Convert.FromBase64String(base64Data);

        // 復号実行
        // 重要: 暗号化側と全く同じパディングモードを指定する必要があります。
        // ここでは推奨される OAEP SHA256 を使用します。
        byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);

        // バイト配列を文字列(UTF-8)に戻す
        return Encoding.UTF8.GetString(decryptedBytes);
    }

    /// <summary>
    /// テストデータ作成用のヘルパーメソッド(暗号化)
    /// </summary>
    static string PerformEncryptionForTest(string plainText, string publicKeyXml)
    {
        using var rsa = RSA.Create();
        rsa.FromXmlString(publicKeyXml);
        byte[] data = Encoding.UTF8.GetBytes(plainText);
        // 暗号化時も同じ OAEP SHA256 を使用
        byte[] encrypted = rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
        return Convert.ToBase64String(encrypted);
    }
}

カスタムポイント

  • パディングモードの整合性: コード内の RSAEncryptionPadding.OaepSHA256 は、暗号化側で使用した設定と完全に一致させる必要があります。古いシステムからのデータを復号する場合は、RSAEncryptionPadding.Pkcs1RSAEncryptionPadding.OaepSHA1 が使われている可能性があるため、仕様を確認して変更してください。
  • キーの読み込み元: 実運用では privateKeyXml はコードに直書きせず、Azure Key Vault、環境変数、または暗号化された設定ファイルから読み込むように実装を変更してください。

注意点

  1. 秘密鍵の必須性: FromXmlString に渡すXMLには <D>, <P>, <Q> などの秘密パラメータが含まれている必要があります。公開鍵のみ(<Modulus><Exponent>のみ)のXMLを渡してもエラーにはなりませんが、Decrypt メソッド実行時に CryptographicException が発生します。
  2. 例外ハンドリング: 「秘密鍵が間違っている」「パディングモードが一致しない」「データが改ざんされている」といったケースではすべて CryptographicException がスローされます。セキュリティ上の理由から、詳細なエラー原因(「パディングがおかしい」など)を外部に漏らさないよう、包括的なエラー処理を行ってください。
  3. レガシーメソッドの回避: RSACryptoServiceProvider.Decrypt(bytes, true) のような古い書き方は、OS(Windows CAPI)への依存度が高く、Linux環境などで動作しない場合があります。必ず RSA.Create() から始まるクロスプラットフォーム対応のAPIを使用してください。

応用

PEM形式の秘密鍵を使用する場合

XMLではなく、OpenSSLなどで生成されたPEM形式(-----BEGIN PRIVATE KEY-----)の文字列を使用する場合の例です。

// XMLの代わりにPEM文字列を読み込む場合
// rsa.FromXmlString(xmlKey); の代わりに使用
rsa.ImportFromPem(pemPrivateKeyString);

// 以降の復号処理は同じ
byte[] decrypted = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);

まとめ

RSA復号処理において最も重要なのは、暗号化時と完全に一致する「パディングモード」の指定と、正しい「秘密鍵」の管理です。.NETRSA クラスを利用することで、Windows以外の環境でも安定して動作するコードを記述できます。復号に失敗する場合は、データ転送時のBase64破損やパディング設定の不一致を疑うのが解決への近道です。

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

この記事を書いた人

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

目次