如何使用C#实现双证书文件加密(对应指定OpenSSL命令)
Hey there! Let's break down how to match the behavior of your OpenSSL command in C#. The original command:
openssl smime -encrypt -binary -aes256 -in file.cfg -out file.cfg.enc -outform der cert1 cert2
does three core things: encrypts raw binary content with AES-256, wraps that encrypted content in an S/MIME envelope using two recipient certificates, and outputs the result in DER format. Here's a practical, step-by-step breakdown with code:
Key Concepts to Align with OpenSSL
First, let's map each OpenSSL flag to its C# equivalent:
-binary: Treat input as raw binary (no text encoding/decoding) → Read the file as bytes directly.-aes256: Use AES-256-CBC for symmetric encryption (OpenSSL's default mode for this command) → Specify the AES-256-CBC algorithm via its OID.-outform der: Output the S/MIME message in DER (binary) format → Use theEnvelopedCms.Encode()method, which natively produces DER.cert1 cert2: Encrypt for two recipients → Add both certificates to the S/MIME recipient collection.
Step-by-Step Implementation
We'll use the System.Security.Cryptography.Pkcs namespace (built into .NET) which handles S/MIME operations natively.
1. Load Recipient Certificates
First, load the two public certificates (they don't need private keys for encryption). C# supports loading both PEM and DER formatted certificates directly.
2. Encrypt Content & Package into S/MIME Envelope
The EnvelopedCms class manages the entire S/MIME encryption workflow: it generates a random AES key, encrypts your content with it, then encrypts that AES key with each recipient's public key.
Full Code Example
using System; using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; public class SmimeFileEncryptor { public static void EncryptFile(string inputPath, string outputPath, string certPath1, string certPath2) { try { // Load the two recipient certificates var cert1 = new X509Certificate2(certPath1); var cert2 = new X509Certificate2(certPath2); // Read input file as raw binary (matches -binary flag) byte[] rawContent = File.ReadAllBytes(inputPath); // Initialize EnvelopedCms with the content to encrypt var envelopedCms = new EnvelopedCms(new ContentInfo(rawContent)); // Add both certificates as recipients var recipients = new CmsRecipientCollection(SubjectIdentifierType.IssuerAndSerialNumber); recipients.Add(new CmsRecipient(cert1)); recipients.Add(new CmsRecipient(cert2)); // Specify AES-256-CBC as the encryption algorithm (matches -aes256) // OID for AES-256-CBC: 2.16.840.1.101.3.4.1.42 var aes256Algorithm = new AlgorithmIdentifier(new Oid("2.16.840.1.101.3.4.1.42")); envelopedCms.Encrypt(recipients, aes256Algorithm); // Export the encrypted message in DER format (matches -outform der) byte[] derEncryptedData = envelopedCms.Encode(); // Write the result to the output file File.WriteAllBytes(outputPath, derEncryptedData); Console.WriteLine("Encryption completed successfully!"); } catch (Exception ex) { Console.WriteLine($"Error during encryption: {ex.Message}"); throw; } } // Example usage public static void Main(string[] args) { EncryptFile("file.cfg", "file.cfg.enc", "cert1.pem", "cert2.pem"); } }
Important Notes
- Certificate Formats: If your certificates are PEM files with headers (
-----BEGIN CERTIFICATE-----),X509Certificate2can load them directly in .NET Core 3.0+ and .NET 5+. For older frameworks, you may need to convert PEM to DER first, or use a helper to parse the PEM content. - Algorithm Compatibility: The OID
2.16.840.1.101.3.4.1.42explicitly specifies AES-256-CBC, which matches OpenSSL's default behavior for the-aes256flag. - Error Handling: The example includes basic error handling, but you'll want to expand this for production use (e.g., checking if files exist, validating certificates).
内容的提问来源于stack exchange,提问作者Andreas Krieger

