如何使用C#解码通过OpenSSL加密的PKCS7 SMIME数据?
Got it, you used OpenSSL to encrypt a JSON file into PKCS#7 SMIME format, and now you need to decrypt that data using C#. Let's break down exactly how to do this using .NET's built-in cryptography APIs—no third-party libraries required (though I'll mention an alternative if you need to handle raw PEM keys).
First, quick recap: your encrypted data is a PKCS#7 enveloped message, which means it was locked with the public key from certificate.pem. To unlock it, you’ll need the private key that pairs with that certificate—keep that in mind before diving into code.
Step 1: Prep Your Data and Certificate
First, strip off the MIME headers from your encrypted SMIME output. You only need the long base64 string that comes after Content-Transfer-Encoding: base64 (the part starting with MIIF6AYJKoZIhvcNAQcDoIIF2TCCBdUCAQAxggUeMI...).
Next, get your private key into a format .NET can read natively. If your private key is a PEM file (e.g., private-key.pem), convert it to a PFX/P12 file using OpenSSL:
openssl pkcs12 -export -out private-cert.pfx -inkey private-key.pem -in certificate.pem
You’ll be prompted to set a password for the PFX file—jot that down, you’ll need it in your code.
Step 2: C# Decryption Code
Here’s a complete, tested example that loads the PFX certificate, decodes the SMIME data, and outputs your original JSON:
using System; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; using System.Text; public class SmimeDecryptor { public static string DecryptSmime(string smimeBase64, X509Certificate2 decryptionCert) { // Convert the base64 SMIME data to a byte array byte[] smimeBytes = Convert.FromBase64String(smimeBase64); // Initialize the EnvelopedCms object (handles PKCS#7 enveloped data) var envelopedCms = new EnvelopedCms(); envelopedCms.Decode(smimeBytes); // Decrypt using the private key certificate envelopedCms.Decrypt(decryptionCert); // Convert the decrypted bytes back to the original JSON string return Encoding.UTF8.GetString(envelopedCms.ContentInfo.Content); } public static void Main() { // Replace with your stripped base64 SMIME data string smimeBase64 = "MIIF6AYJKoZIhvcNAQcDoIIF2TCCBdUCAQAxggUeMI..."; // Load your PFX certificate with private key var decryptionCert = new X509Certificate2( "path/to/your/private-cert.pfx", "your-pfx-password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); try { string originalJson = DecryptSmime(smimeBase64, decryptionCert); Console.WriteLine("Decrypted JSON Data:"); Console.WriteLine(originalJson); } catch (Exception ex) { Console.WriteLine($"Decryption failed: {ex.Message}"); } } }
Key Details to Avoid Headaches
- Certificate Loading Flags: The
X509KeyStorageFlagssettings help avoid permission issues, especially in server environments.MachineKeySetstores the certificate in the machine-wide store, andExportableensures the private key is accessible for decryption. - Handling Full SMIME with MIME Headers: If you don’t want to manually strip the MIME headers, use the MailKit library (for .NET Core/.NET 5+) to parse the full SMIME message. Install it via NuGet (
Install-Package MailKit), then use this snippet:using MailKit; using MailKit.Net.Mime; using System.IO; // Parse the full SMIME string (including headers) var mimeMessage = MimeMessage.Load(new StringReader(fullSmimeData)); var encryptedPart = (Pkcs7Mime)mimeMessage.Body; // Decrypt directly using the certificate var decryptedPart = encryptedPart.Decrypt(decryptionCert); string originalJson = decryptedPart.GetText(Encoding.UTF8); - Troubleshooting: If you get "No valid private key found", double-check that your PFX file includes the private key, the password is correct, and your app has permissions to access the key store.
内容的提问来源于stack exchange,提问作者Dave Gitenburgh

