【C#】RSA公開鍵を使用したデータの暗号化

目次

概要

XML形式の公開鍵を使用して、機密性の高いテキストデータを暗号化する実装です。 最新の.NET環境では、RSACryptoServiceProviderではなく抽象クラスRSAのファクトリメソッドを使用し、よりセキュアなパディングモード(OAEP)を明示的に指定する方法が推奨されます。

仕様(入出力)

  • 入力:
    • 暗号化したい文字列(UTF-8)
    • RSA公開鍵(XML形式文字列)
  • 出力: 暗号化されたデータのBase64文字列
  • 制約: RSAで直接暗号化できるデータサイズは、キー長とパディング方式に依存して制限されます(長いデータには向きません)。

基本の使い方

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

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

var data = Encoding.UTF8.GetBytes("Secret Message");

// 暗号化(OAEP SHA256パディング推奨)
var encrypted = rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);

コード全文

このコードは、鍵の生成から暗号化までの流れを1つのファイルで動作確認できるように構成しています。

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

class Program
{
    static void Main()
    {
        // 1. メッセージの準備
        var originalMessage = "これはあなただけに話す秘密の話です。";
        Console.WriteLine($"[Original] {originalMessage}");

        // 2. RSAキーの準備
        // 動作確認のため、ここで一時的に新しいキーペアを生成して公開鍵を取得します。
        // 実際には、通信相手から受け取った公開鍵文字列を使用してください。
        string publicKeyXml = GenerateSamplePublicKey();
        
        // 3. 暗号化処理
        try
        {
            string encryptedBase64 = EncryptString(originalMessage, publicKeyXml);

            Console.WriteLine("\n[Encrypted] (Base64)");
            Console.WriteLine(encryptedBase64);
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }

    /// <summary>
    /// 文字列をRSA公開鍵で暗号化し、Base64文字列として返します。
    /// </summary>
    static string EncryptString(string text, string publicKeyXml)
    {
        // クロスプラットフォーム対応のRSAインスタンスを作成
        using var rsa = RSA.Create();

        // XML形式の公開鍵を読み込み
        rsa.FromXmlString(publicKeyXml);

        // 文字列をバイト配列に変換
        byte[] dataBytes = Encoding.UTF8.GetBytes(text);

        // 暗号化を実行
        // モダンな実装では、従来の PKCS#1 v1.5 よりも OAEP (Optimal Asymmetric Encryption Padding) が推奨されます
        // RSAEncryptionPadding.OaepSHA256 を指定します
        byte[] encryptedBytes = rsa.Encrypt(dataBytes, RSAEncryptionPadding.OaepSHA256);

        // 結果をBase64文字列に変換
        return Convert.ToBase64String(encryptedBytes);
    }

    /// <summary>
    /// テスト用にRSAキーペアを作成し、公開鍵のXMLのみを返します。
    /// </summary>
    static string GenerateSamplePublicKey()
    {
        using var rsa = RSA.Create(2048);
        // includePrivateParameters: false で公開鍵のみ抽出
        return rsa.ToXmlString(includePrivateParameters: false);
    }
}

カスタムポイント

  • パディングモードの選択: RSAEncryptionPadding.OaepSHA256 はセキュリティ強度が高く推奨されますが、古いシステムとの互換性が必要な場合は RSAEncryptionPadding.Pkcs1 に変更する必要があるかもしれません。
  • 入力データのエンコーディング: コード内では UTF-8 を使用していますが、要件に応じて Shift-JIS など適切なエンコーディングに変更してください。
  • 公開鍵のソース: サンプルではその場で生成していますが、実際にはファイルやデータベース、APIレスポンスから取得したXML文字列を publicKeyXml 変数に代入してください。

注意点

  1. データサイズの制限: RSAは「鍵そのもの」や「ハッシュ値」のような短いデータの暗号化に適しています。2048ビットのキーでOAEP(SHA256)を使用する場合、暗号化できる最大サイズは190バイト程度です。長い文章やファイル全体を暗号化する場合は、AESなどの共通鍵暗号を使用し、その「共通鍵」をRSAで暗号化する「ハイブリッド暗号」方式を採用してください。
  2. 秘密鍵の不在: このコードで行えるのは「暗号化」のみです。復号には対となる「秘密鍵」が必要であり、公開鍵しか持たないこのプログラム上では元の文章に戻すことはできません。
  3. 例外処理: 不正なフォーマットのXMLキーや、サイズ超過のデータを渡すと CryptographicException が発生します。必ず try-catch で捕捉してください。

応用

古いAPI (RSACryptoServiceProvider) との互換性

古い形式のコード(bool fOAEP 引数を取るもの)を移植する場合の対応例です。

// 古い書き方: rsa.Encrypt(bytes, true); // true は OAEP SHA1 を意味することが多い
// ↓
// 現代の書き方 (等価な動作):
var output = rsa.Encrypt(bytes, RSAEncryptionPadding.OaepSHA1);

まとめ

RSAによる暗号化は、抽象クラスである RSA と列挙型 RSAEncryptionPadding を組み合わせることで、プラットフォームに依存しないセキュアな実装が可能です。入力データのサイズ制限に最も注意が必要であり、大きなデータを扱う際はハイブリッド暗号方式への切り替えを検討する必要があります。また、XML形式のキーは.NET特有の文化であるため、他言語と連携する場合はPEM形式への移行も視野に入れてください。

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

この記事を書いた人

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

目次