You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何将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

火山引擎 最新活动