[C#]How to Read PKCS#1 Format RSA Public Key Files and Encrypt Data

目次

Overview

This implementation demonstrates how to read a PKCS#1 format PEM file starting with “—–BEGIN RSA PUBLIC KEY—–” and use that public key to encrypt data. By using the ImportRSAPublicKey method added in .NET Core 3.0, you can restore key information from Base64-decoded binary data (DER).

Specifications (Input/Output)

  • Input: – RSA public key file (PKCS#1 format PEM: publickey.pem).
    • String to be encrypted.
  • Output: Encrypted Base64 string.
  • File Format: The header must be -----BEGIN RSA PUBLIC KEY----- (note that BEGIN PUBLIC KEY is a different format).

Basic Usage

To use this, read the PEM string from the file, remove the headers, footers, and line breaks, and then convert it to binary.

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

// Read PEM string from file and remove headers/footers/line breaks to convert to binary
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 _);

// Encryption
var data = Encoding.UTF8.GetBytes("Secret");
var encrypted = rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);

Full Code Example

This is a console application designed for .NET 6 or later.

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

class Program
{
    static void Main()
    {
        // 1. Read the PKCS#1 format public key file
        // Includes logic to create a dummy file if it doesn't exist for testing
        string pemFilePath = "publickey.pem";
        EnsureDummyKeyFileExists(pemFilePath);

        try
        {
            // 2. Parse the PEM file (Header removal and Base64 decoding)
            // ImportRSAPublicKey requires binary data (DER), 
            // so all text decorations (headers, footers, line breaks) must be removed.
            string pemContent = File.ReadAllText(pemFilePath);
            
            string publicKeyBase64 = pemContent
                .Replace("-----BEGIN RSA PUBLIC KEY-----", "")
                .Replace("-----END RSA PUBLIC KEY-----", "")
                .Replace("\r", "") // For Windows line breaks
                .Replace("\n", "") // For Linux/Mac line breaks
                .Trim();

            byte[] publicKeyBytes = Convert.FromBase64String(publicKeyBase64);

            // 3. Instantiate RSA and import the key
            using var rsa = RSA.Create();
            
            // Import as PKCS#1 format (RSAPublicKey)
            rsa.ImportRSAPublicKey(publicKeyBytes, out int bytesRead);
            Console.WriteLine($"Key imported successfully. Read {bytesRead} bytes.");

            // 4. Encryption process
            string message = "This is a secret.";
            byte[] messageBytes = Encoding.UTF8.GetBytes(message);

            // Encrypt using OAEP SHA256 padding
            byte[] encryptedBytes = rsa.Encrypt(messageBytes, RSAEncryptionPadding.OaepSHA256);

            // 5. Output result
            string outputBase64 = Convert.ToBase64String(encryptedBytes);
            Console.WriteLine("\n[Encrypted Output (Base64)]");
            Console.WriteLine(outputBase64);
        }
        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>
    /// Generates a PKCS#1 format public key file for testing purposes
    /// </summary>
    static void EnsureDummyKeyFileExists(string path)
    {
        if (!File.Exists(path))
        {
            using var rsa = RSA.Create(2048);
            // Get PKCS#1 format byte array
            byte[] keyBytes = rsa.ExportRSAPublicKey();
            
            // Format manually into 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}");
        }
    }
}

Customization Points

  • Simplifying PEM Parsing: If you are using .NET 5 or later, you can use the rsa.ImportFromPem(File.ReadAllText(path)) method. This handles header removal and Base64 decoding automatically, drastically shortening your code.
  • Identifying Key Formats: If the header is -----BEGIN PUBLIC KEY----- (without “RSA”), it is in PKCS#8 (SubjectPublicKeyInfo) format. In that case, use the ImportSubjectPublicKeyInfo method or the previously mentioned ImportFromPem method, which automatically detects the format.

Important Notes

  • Strict Header Matching: The strings used in the Replace method must match the file headers exactly. Any difference, such as the number of spaces, will cause the replacement to fail and lead to a FormatException.
  • Padding Modes: While older code might use fOAEP: true (equivalent to OAEP SHA1), RSAEncryptionPadding.OaepSHA256 is now recommended for better security. Ensure the settings match the decryption side.

Advanced Usage

Modern Implementation in .NET 5+ (ImportFromPem)

This is the recommended implementation that eliminates manual string manipulation.

using var rsa = RSA.Create();
string pemStr = File.ReadAllText("publickey.pem");

// Automatically detects and imports format (PKCS#1 or PKCS#8) based on headers
rsa.ImportFromPem(pemStr);

// Encryption remains the same

Conclusion

When reading an RSA public key from an external file, you must identify whether the file is in “PKCS#1 format” or “PKCS#8/SPKI format” based on the headers. While the ImportRSAPublicKey method requires Base64 decoding of the byte array, modern .NET environments allow you to skip these cumbersome steps by using ImportFromPem.

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

この記事を書いた人

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

目次