目次
概要
「—–BEGIN RSA PUBLIC KEY—–」で始まるPKCS#1形式のPEMファイルを読み込み、その公開鍵を使用してデータを暗号化する実装です。 .NET Core 3.0以降で追加された ImportRSAPublicKey メソッドを使用し、Base64デコードされたバイナリデータ(DER)からキー情報を復元します。
仕様(入出力)
- 入力:
- RSA公開鍵ファイル(PKCS#1形式 PEM:
publickey.pem) - 暗号化対象の文字列
- RSA公開鍵ファイル(PKCS#1形式 PEM:
- 出力: 暗号化されたBase64文字列
- ファイル形式: ヘッダーが
-----BEGIN RSA PUBLIC KEY-----であること(BEGIN PUBLIC KEYの場合は扱いが異なります)。
基本の使い方
using System.Security.Cryptography;
using System.Text;
// ファイルからPEM文字列を読み込み、ヘッダー・フッター・改行を除去してバイナリ化
var pemStr = File.ReadAllText("publickey.pem");
var base64 = pemStr.Replace("-----BEGIN RSA PUBLIC KEY-----", "")
.Replace("-----END RSA PUBLIC KEY-----", "")
.Replace("\r", "").Replace("\n", "");
var keyBytes = Convert.FromBase64String(base64);
using var rsa = RSA.Create();
rsa.ImportRSAPublicKey(keyBytes, out _);
// 暗号化
var data = Encoding.UTF8.GetBytes("Secret");
var encrypted = rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
コード全文
.NET 6以降の環境で動作するコンソールアプリケーション形式です。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main()
{
// 1. PKCS#1形式の公開鍵ファイルを読み込む
// ファイルが存在しない場合はダミー作成する処理を入れています
string pemFilePath = "publickey.pem";
EnsureDummyKeyFileExists(pemFilePath);
try
{
// 2. PEMファイルの解析(ヘッダー削除とBase64デコード)
// ImportRSAPublicKey はバイナリデータ(DER)を要求するため、
// テキスト装飾(ヘッダー、フッター、改行)を全て削除する必要があります。
string pemContent = File.ReadAllText(pemFilePath);
string publicKeyBase64 = pemContent
.Replace("-----BEGIN RSA PUBLIC KEY-----", "")
.Replace("-----END RSA PUBLIC KEY-----", "")
.Replace("\r", "") // Windowsの改行対策
.Replace("\n", "") // Linux/Macの改行対策
.Trim();
byte[] publicKeyBytes = Convert.FromBase64String(publicKeyBase64);
// 3. RSAインスタンスの生成とキーのインポート
using var rsa = RSA.Create();
// PKCS#1形式(RSAPublicKey)としてインポート
rsa.ImportRSAPublicKey(publicKeyBytes, out int bytesRead);
Console.WriteLine($"Key imported successfully. Read {bytesRead} bytes.");
// 4. 暗号化処理
string message = "これは秘密です。";
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
// OAEP SHA256パディングを使用して暗号化
byte[] encryptedBytes = rsa.Encrypt(messageBytes, RSAEncryptionPadding.OaepSHA256);
// 5. 結果の出力
string outputBase64 = Convert.ToBase64String(encryptedBytes);
Console.WriteLine("\n[Encrypted Output (Base64)]");
Console.WriteLine(outputBase64);
// 参考: 読み込んだキーをXML形式で確認(必要であれば)
// Console.WriteLine(rsa.ToXmlString(false));
}
catch (FormatException)
{
Console.WriteLine("Error: Invalid Base64 format in PEM file.");
}
catch (CryptographicException ex)
{
Console.WriteLine($"Crypto Error: {ex.Message}");
Console.WriteLine("Check if the key is actually PKCS#1 (BEGIN RSA PUBLIC KEY).");
}
}
/// <summary>
/// 動作確認用にPKCS#1形式の公開鍵ファイルを生成します
/// </summary>
static void EnsureDummyKeyFileExists(string path)
{
if (!File.Exists(path))
{
using var rsa = RSA.Create(2048);
// PKCS#1形式のバイト配列を取得
byte[] keyBytes = rsa.ExportRSAPublicKey();
// 手動でPEM形式に整形
var sb = new StringBuilder();
sb.AppendLine("-----BEGIN RSA PUBLIC KEY-----");
sb.AppendLine(Convert.ToBase64String(keyBytes, Base64FormattingOptions.InsertLineBreaks));
sb.AppendLine("-----END RSA PUBLIC KEY-----");
File.WriteAllText(path, sb.ToString());
Console.WriteLine($"[Setup] Generated dummy key file: {path}");
}
}
}
カスタムポイント
- PEM解析の簡略化: .NET 5以降を使用している場合、
rsa.ImportFromPem(File.ReadAllText(path))というメソッドを使用すれば、ヘッダーの削除やBase64デコードを自前で行う必要がなくなり、コードが劇的に短くなります。 - 鍵形式の判別: もしヘッダーが
-----BEGIN PUBLIC KEY-----(RSAが付かない)の場合は、PKCS#8(SubjectPublicKeyInfo)形式です。その場合はImportSubjectPublicKeyInfoメソッドを使用するか、前述のImportFromPem(形式を自動判別)を使用してください。
注意点
- ヘッダーの厳密な一致: コード内の
Replace文字列は、ファイル内のヘッダーと完全に一致している必要があります。スペースの数などが異なると置換に失敗し、FormatExceptionになります。 - パディングモード: 入力コードにあった
fOAEP: true(OAEP SHA1)に相当するRSAEncryptionPadding.OaepSHA1よりも、現在はRSAEncryptionPadding.OaepSHA256が推奨されます。復号側と設定を合わせることを忘れないでください。
応用
.NET 5以降でのモダンな実装(ImportFromPem)
手動の文字列操作を排除した推奨実装です。
using var rsa = RSA.Create();
string pemStr = File.ReadAllText("publickey.pem");
// ヘッダーを見て自動的に形式(PKCS#1 or PKCS#8)を判断して読み込む
rsa.ImportFromPem(pemStr);
// 以降の暗号化処理は同じ
まとめ
外部ファイルからRSA公開鍵を読み込む際は、そのファイルが「PKCS#1形式」なのか「PKCS#8/SPKI形式」なのかをヘッダーで区別する必要があります。ImportRSAPublicKey メソッドはバイト配列を受け取るため、事前にBase64デコードが必要ですが、モダンな .NET 環境では ImportFromPem を使用することでこれらの煩雑な手順を省略できます。
