如何将PCLCrypto PEM公钥加密代码迁移到.NET Standard 2.0?
没问题!我来帮你把这段代码移植到.NET Standard 2.0环境,分别用System.Security.Cryptography(原生类库)和Portable.BouncyCastle(第三方加密库)两种方案实现,密钥依然保留你现在用的PEM字符串格式。
方案一:使用System.Security.Cryptography(原生库)
.NET Standard 2.0的原生加密库没有直接提供PEM解析方法,但我们可以保留原有的PEM解析逻辑并优化健壮性,再用RSA类完成加密操作。下面是重写后的完整代码:
using System; using System.IO; using System.Text; using System.Security.Cryptography; public sealed class Pem { private string _type; private string _base64Encoded; private const string PemStart = "-----BEGIN "; private const string PemEnd = "-----END "; private const string PemEndOfLine = "-----"; public Pem(string content) { if (string.IsNullOrWhiteSpace(content)) throw new ArgumentNullException(nameof(content)); _base64Encoded = string.Empty; using (var reader = new StringReader(content.Trim())) { string line; while ((line = reader.ReadLine()) != null) { if (line.StartsWith(PemStart) && line.EndsWith(PemEndOfLine)) { // 提取PEM类型(比如"PUBLIC KEY") _type = line.Substring(PemStart.Length, line.Length - PemStart.Length - PemEndOfLine.Length).Trim(); } else if (line.StartsWith(PemEnd)) { // 忽略结束行 continue; } else if (!string.IsNullOrWhiteSpace(line)) { // 拼接Base64内容,跳过空行 _base64Encoded += line.Trim(); } } } if (string.IsNullOrWhiteSpace(_base64Encoded)) throw new InvalidOperationException("PEM内容中未找到有效的Base64编码数据"); } public string Type => _type; public byte[] Decoded => Convert.FromBase64String(_base64Encoded); } public interface IEncryption { string Encrypt(string target); } public class EncryptionService : IEncryption { public string Encrypt(string target) { if (string.IsNullOrWhiteSpace(target)) throw new ArgumentNullException(nameof(target)); var publicKeyPem = "-----BEGIN PUBLIC KEY-----\nXXXXKEYMATERIALREMOVEDXXXX\n-----END PUBLIC KEY-----"; var pem = new Pem(publicKeyPem); byte[] keyMaterial = pem.Decoded; // 导入公钥到RSA实例 using (var rsa = RSA.Create()) { // 导入PKCS#8格式的公钥(对应PEM的"PUBLIC KEY"类型) rsa.ImportSubjectPublicKeyInfo(keyMaterial, out _); byte[] data = Encoding.UTF8.GetBytes(target); // 使用PKCS#1填充模式加密,和原代码逻辑一致 byte[] cipherText = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1); return Convert.ToBase64String(cipherText); } } }
关键点说明:
- 保留了原有的PEM解析逻辑,新增了空值检查和空行过滤,让代码更健壮。
- 原生
RSA类的ImportSubjectPublicKeyInfo方法专门用于导入PKCS#8格式的公钥,和你当前PEM的"PUBLIC KEY"类型完全匹配。 - 加密时使用
RSAEncryptionPadding.Pkcs1,和原代码中PCLCrypto.AsymmetricAlgorithm.RsaPkcs1的填充模式完全一致。
方案二:使用Portable.BouncyCastle(第三方库)
如果你不想自己维护PEM解析逻辑,可以用Portable.BouncyCastle库,它提供了现成的PEM解析工具,能省不少代码。
第一步:安装NuGet包
首先在项目中安装Portable.BouncyCastle:
Install-Package Portable.BouncyCastle
重写后的代码:
using System; using System.IO; using System.Text; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Security; public sealed class Pem { private readonly AsymmetricKeyParameter _keyParameter; public Pem(string content) { if (string.IsNullOrWhiteSpace(content)) throw new ArgumentNullException(nameof(content)); using (var reader = new StringReader(content)) { var pemReader = new PemReader(reader); var obj = pemReader.ReadObject(); _keyParameter = obj as AsymmetricKeyParameter; if (_keyParameter == null) throw new InvalidOperationException("无法从PEM内容中解析出有效的非对称密钥"); } } public AsymmetricKeyParameter KeyParameter => _keyParameter; } public interface IEncryption { string Encrypt(string target); } public class EncryptionService : IEncryption { public string Encrypt(string target) { if (string.IsNullOrWhiteSpace(target)) throw new ArgumentNullException(nameof(target)); var publicKeyPem = "-----BEGIN PUBLIC KEY-----\nXXXXKEYMATERIALREMOVEDXXXX\n-----END PUBLIC KEY-----"; var pem = new Pem(publicKeyPem); var publicKey = (RsaKeyParameters)pem.KeyParameter; // 创建RSA加密引擎,使用PKCS#1填充 var engine = new RsaEngine(); engine.Init(true, publicKey); // true表示加密模式 byte[] data = Encoding.UTF8.GetBytes(target); // BouncyCastle的RsaEngine需要手动处理分块(RSA加密有长度限制) byte[] cipherText = ProcessBlock(engine, data); return Convert.ToBase64String(cipherText); } private byte[] ProcessBlock(IAsymmetricBlockCipher engine, byte[] input) { int inputLength = input.Length; int blockSize = engine.GetInputBlockSize(); var output = new byte[0]; for (int i = 0; i < inputLength; i += blockSize) { int chunkSize = Math.Min(blockSize, inputLength - i); byte[] chunk = new byte[chunkSize]; Array.Copy(input, i, chunk, 0, chunkSize); byte[] encryptedChunk = engine.ProcessBlock(chunk, 0, chunkSize); Array.Resize(ref output, output.Length + encryptedChunk.Length); Array.Copy(encryptedChunk, 0, output, output.Length - encryptedChunk.Length, encryptedChunk.Length); } return output; } }
关键点说明:
- BouncyCastle的
PemReader可以直接解析PEM格式的密钥,不需要我们手动拼接Base64,代码更简洁。 - 因为BouncyCastle的
RsaEngine不自动处理分块加密(原生RSA类会自动处理),所以我们需要自己实现分块逻辑,ProcessBlock方法就是干这个的。 - 加密模式下初始化引擎时传入
true,默认填充模式就是PKCS#1,和原代码逻辑一致。
内容的提问来源于stack exchange,提问作者WickedW




