[C#] How to Generate RSA Key Pairs and Convert to PEM Format

目次

Overview

In modern .NET environments, you can generate RSA key pairs (private and public keys) using only standard libraries and export them in the highly portable PEM format (Base64 strings). This approach replaces the legacy XML format (ToXmlString) with a standard text format that is highly compatible with OpenSSL and other platforms.

Specifications (Input/Output)

  • Input: Key size in bits (e.g., 2048, 4096).
  • Output:
    • Private key in PEM format (-----BEGIN PRIVATE KEY----- ...)
    • Public key in PEM format (-----BEGIN PUBLIC KEY----- ...)
  • Behavior: Generates the key in memory, displays it to the standard output, and verifies that the key information can be restored from the strings.

Basic Usage

using System.Security.Cryptography;

// Generate a key with 2048 bits
using var algorithm = RSA.Create(2048);

// Get the private key (PKCS#8) as a string
var privateKeyPem = algorithm.ExportRSAPrivateKeyPem();

// Get the public key (SPKI) as a string
var publicKeyPem = algorithm.ExportSubjectPublicKeyPem();

Full Code Example

This code is a console application designed for .NET 7 or later.

using System;
using System.Security.Cryptography;

class Program
{
    static void Main()
    {
        // 1. Instantiate RSA algorithm with a specific key size
        // Use the cross-platform 'RSA.Create' instead of the legacy 'RSACryptoServiceProvider'
        using var secureIdentity = RSA.Create(2048);
        
        Console.WriteLine($"[Key Generated] KeySize: {secureIdentity.KeySize} bits");

        // 2. Export Private Key (PEM format: PKCS#8)
        // This is sensitive information to be managed on the server side
        string secretToken = secureIdentity.ExportRSAPrivateKeyPem();
        Console.WriteLine("\n--- Exported Private Key (Keep Secret) ---");
        Console.WriteLine(secretToken);

        // 3. Export Public Key (PEM format: SubjectPublicKeyInfo)
        // This info can be distributed to clients for encryption
        string publicToken = secureIdentity.ExportSubjectPublicKeyPem();
        Console.WriteLine("\n--- Exported Public Key (Distribute) ---");
        Console.WriteLine(publicToken);

        // 4. Verify restoration from strings (Import)
        VerifyKeyImport(secretToken, publicToken);
    }

    /// <summary>
    /// Verifies if the RSA instance can be restored from the exported PEM strings.
    /// </summary>
    static void VerifyKeyImport(string privatePem, string publicPem)
    {
        Console.WriteLine("\n[Validation] Testing key import...");

        // Create a new instance for restoration
        using var validationRsa = RSA.Create();

        try
        {
            // Import including the private key (enables signing and decryption)
            validationRsa.ImportFromPem(privatePem);
            Console.WriteLine("- Private key import: Success");

            // Verify a separate instance can be initialized with only the public key
            using var publicOnlyRsa = RSA.Create();
            publicOnlyRsa.ImportFromPem(publicPem);
            Console.WriteLine("- Public key import: Success");
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine($"- Import Error: {ex.Message}");
        }
    }
}

Customization Points

  • Changing Key Size: You can change RSA.Create(2048) to 4096 to increase security strength, though this will decrease processing speed. Adjust based on your needs.
  • Changing Storage: While this example uses Console.WriteLine, in production, use System.IO.File.WriteAllText to save as .pem files or store them in secure vaults like Azure Key Vault.
  • Format Selection: If integrating with legacy systems like older Java versions, consider using ExportEncryptedPkcs8PrivateKeyPem to export with a password instead of ExportRSAPrivateKeyPem.

Important Notes

  • Strict Private Key Management: Never share the secretToken (private key) with third parties. Do not commit it to repositories like GitHub.
  • Avoid ToXmlString: The older ToXmlString method depends on Windows-specific implementations and may fail in Linux or Docker environments. Modern .NET development prefers PEM or DER (binary) formats.
  • Ephemeral Key Lifespan: Keys generated with RSA.Create() exist only in memory. They vanish when the application ends, so you must export and save them if persistence is required.

Advanced Usage

Creating Digital Signatures (Using Private Key)

This example shows how to use the generated key to create a digital signature for detecting data tampering.

using System.Text;

// ... (Assuming keys were generated as shown above) ...

var data = "Important Contract Data";
var dataBytes = Encoding.UTF8.GetBytes(data);

// Create signature using SHA256 hash
byte[] signature = secureIdentity.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

Console.WriteLine($"\nSignature generated: {BitConverter.ToString(signature).Replace("-", "")}");

Conclusion

Always manage private keys with extreme care and only perform export operations when necessary. Use RSA.Create() rather than RSACryptoServiceProvider for generating RSA keys. For converting keys to text, the modern standard is to use PEM format (Export...Pem) rather than the less compatible XML format.

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

この記事を書いた人

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

目次