[C#]How to Decrypt Data Using RSA Private Keys

目次

Overview

This implementation restores data encrypted via the RSA method to its original text using a corresponding private key in XML format. It utilizes the version-independent RSA abstract class in .NET and specifies high-security padding for safe data recovery.

Specifications (Input/Output)

  • Input:
    • Encrypted data (Base64 string).
    • RSA private key (XML string).
  • Output: Decrypted plaintext (UTF-8 string).
  • Prerequisite: The padding mode used during encryption (e.g., OAEP SHA256) must be known.

Basic Usage

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

// Create an RSA instance
using var rsa = RSA.Create();
rsa.FromXmlString(privateKeyXml);

// Convert Base64 back to a byte array
byte[] encryptedBytes = Convert.FromBase64String(encryptedBase64String);

// Decrypt (Specify the same padding as encryption: OAEP SHA256 here)
byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);

// Convert to string
string originalMessage = Encoding.UTF8.GetString(decryptedBytes);

Full Code Example

The following code demonstrates a self-contained process. It generates a temporary key pair and performs encryption before executing the decryption logic.

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

class Program
{
    static void Main()
    {
        // --- Preparation Phase (Data would normally come from an external source) ---
        
        // 1. Generate a test RSA key pair (2048-bit)
        using var setupRsa = RSA.Create(2048);
        
        // Retrieve private key (needed for decryption)
        string privateKeyXml = setupRsa.ToXmlString(includePrivateParameters: true);
        
        // Retrieve public key (needed for encryption)
        string publicKeyXml = setupRsa.ToXmlString(includePrivateParameters: false);

        // 2. Create encrypted data for testing (using the public key)
        string originalSecret = "This is a top secret message.";
        string encryptedBase64 = PerformEncryptionForTest(originalSecret, publicKeyXml);

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


        // --- Implementation Phase (Core Decryption Process) ---

        try
        {
            // 3. Execute decryption using the private key
            string decryptedMessage = DecryptString(encryptedBase64, privateKeyXml);

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

    /// <summary>
    /// Decrypts an encrypted Base64 string using an RSA private key.
    /// </summary>
    static string DecryptString(string base64Data, string privateKeyXml)
    {
        // Create RSA instance
        using var rsa = RSA.Create();

        // Import private key (XML format)
        // Note: Passing an XML without private parameters will cause an error during decryption.
        rsa.FromXmlString(privateKeyXml);

        // Convert Base64 string to byte array
        byte[] encryptedBytes = Convert.FromBase64String(base64Data);

        // Execute decryption
        // Critical: You must specify the exact same padding mode used by the encryptor.
        // Recommended mode OAEP SHA256 is used here.
        byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);

        // Convert byte array back to UTF-8 string
        return Encoding.UTF8.GetString(decryptedBytes);
    }

    /// <summary>
    /// Helper method to create test data (Encryption)
    /// </summary>
    static string PerformEncryptionForTest(string plainText, string publicKeyXml)
    {
        using var rsa = RSA.Create();
        rsa.FromXmlString(publicKeyXml);
        byte[] data = Encoding.UTF8.GetBytes(plainText);
        // Use the same OAEP SHA256 during encryption
        byte[] encrypted = rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
        return Convert.ToBase64String(encrypted);
    }
}

Customization Points

  • Padding Mode Consistency: The RSAEncryptionPadding.OaepSHA256 setting in the code must perfectly match the setting used by the party that encrypted the data. If you are decrypting data from older systems, you might need to use RSAEncryptionPadding.Pkcs1 or RSAEncryptionPadding.OaepSHA1. Check the specific technical requirements.
  • Key Storage: In a production environment, avoid hard-coding the privateKeyXml. Load it from a secure location such as Azure Key Vault, environment variables, or encrypted configuration files.

Important Notes

  • Private Key Requirement: The XML string passed to FromXmlString must contain private parameters like <D>, <P>, and <Q>. If you pass an XML containing only the public key (only <Modulus> and <Exponent>), it will not throw an error during the import, but a CryptographicException will occur when the Decrypt method is called.
  • Exception Handling: Scenarios such as “incorrect private key,” “mismatched padding mode,” or “tampered data” will all throw a CryptographicException. For security reasons, use comprehensive error handling so that detailed reasons (like “padding mismatch”) are not exposed to external users.
  • Avoid Legacy Methods: Older coding styles such as RSACryptoServiceProvider.Decrypt(bytes, true) depend heavily on the Windows OS (CAPI) and may not work in Linux environments. Always use the cross-platform APIs starting with RSA.Create().

Advanced Usage

Using Private Keys in PEM Format

If you need to use a private key in PEM format (starting with -----BEGIN PRIVATE KEY-----) generated by OpenSSL instead of XML, follow this pattern:

// Load PEM string instead of XML
// Use this instead of rsa.FromXmlString(xmlKey);
rsa.ImportFromPem(pemPrivateKeyString);

// The subsequent decryption process remains the same
byte[] decrypted = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);

Conclusion

The most critical factors in RSA decryption are specifying the “padding mode” that exactly matches the encryption process and managing the “private key” securely. By using the RSA class in .NET, you can write code that operates stably across environments other than Windows. If decryption fails, investigate potential Base64 corruption during transmission or mismatched padding settings first.

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

この記事を書いた人

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

目次