You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

.NET 6转.NET 4.8:C#中ImportRSAPrivateKey方法替代方案求助

解决.NET 4.8中替换ImportRSAPrivateKey方法的问题

核心问题说明

.NET Framework 4.8的RSACryptoServiceProvider类确实没有ImportRSAPrivateKeyExportRSAPrivateKey方法,这两个是.NET Core/.NET 5+引入的API。同时你当前的ReadPKCS8PrivateKey方法并未实际导入私钥,只是创建了空的RSA实例,这也是迁移失败的原因之一。

下面提供两种可行的解决方案:


方案一:使用BouncyCastle库(推荐)

BouncyCastle是.NET生态中常用的加密库,完美支持.NET 4.8,能轻松解析PEM格式的RSA私钥。

步骤1:安装NuGet包

在项目中安装BouncyCastle包:

Install-Package Org.BouncyCastle

如果使用System.Text.Json(你的代码中用到了),还需要安装对应NuGet包:

Install-Package System.Text.Json

步骤2:修改代码

替换ReadPKCS8PrivateKey方法,并调整签名逻辑:

using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;

namespace toto.Auth
{
    public class AuthRequestService
    {
        private const string DATE_PATTERN = "yyyy-MM-ddTHH:mm:ss.fffK";
        private const string ODC_AUTH_URL = "https://myurl/auth";

        private FileInfo certFile;
        private string partnerId;
        private RSAParameters privateKeyParams;

        private JsonSerializerOptions jsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };

        public AuthRequestService(string certFilePath, string partnerId)
        {
            this.certFile = new FileInfo(certFilePath);
            this.privateKeyParams = ReadRsaPrivateKey(certFile);
            this.partnerId = partnerId;
        }

        public string GetTokenForRPPS(string rpps)
        {
            var timeStamp = DateTime.UtcNow.ToString(DATE_PATTERN);
            var body = new AuthRequestDTO(partnerId, rpps, timeStamp);
            string result = string.Empty;

            try
            {
                using (var rsa = new RSACryptoServiceProvider())
                {
                    rsa.ImportParameters(privateKeyParams);

                    Console.WriteLine("unsigned json:");
                    var unsignedJson = JsonSerializer.Serialize(body, jsonOptions);
                    Console.WriteLine(unsignedJson);

                    // .NET 4.8的SignData重载使用字符串指定哈希算法
                    var signatureBytes = rsa.SignData(Encoding.UTF8.GetBytes(unsignedJson), "SHA512", RSASignaturePadding.Pkcs1);
                    string signB64 = Convert.ToBase64String(signatureBytes);
                    body.Signature = signB64;

                    string signedPayload = JsonSerializer.Serialize(body, jsonOptions);
                    Console.WriteLine("signed json:");
                    Console.WriteLine(signedPayload);

                    using (HttpClient httpClient = new HttpClient())
                    {
                        var httpRequest = new HttpRequestMessage(HttpMethod.Post, ODC_AUTH_URL)
                        {
                            Content = new StringContent(signedPayload, Encoding.UTF8, "application/json")
                        };

                        var response = httpClient.SendAsync(httpRequest).Result;
                        result = response.Content.ReadAsStringAsync().Result;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            return result;
        }

        protected RSAParameters ReadRsaPrivateKey(FileInfo file)
        {
            using (var reader = new StreamReader(file.FullName))
            {
                var pemReader = new PemReader(reader);
                var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
                return DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)keyPair.Private);
            }
        }
    }

    // 确保AuthRequestDTO类存在且属性匹配序列化要求
    public class AuthRequestDTO
    {
        public string PartnerId { get; set; }
        public string Rpps { get; set; }
        public string TimeStamp { get; set; }
        public string Signature { get; set; }

        public AuthRequestDTO(string partnerId, string rpps, string timeStamp)
        {
            PartnerId = partnerId;
            Rpps = rpps;
            TimeStamp = timeStamp;
        }
    }
}

关键修改点

  1. 用BouncyCastle的PemReader读取PEM私钥,转换成.NET原生的RSAParameters
  2. 直接使用RSACryptoServiceProvider.ImportParameters导入密钥,替代原有的ImportRSAPrivateKey
  3. 调整SignData参数:.NET 4.8不支持HashAlgorithmName枚举,改用字符串指定哈希算法(如"SHA512"

方案二:手动解析PKCS#1私钥(不推荐)

如果不想引入第三方库,可以手动解析PKCS#1格式的私钥(你的PEM头是-----BEGIN RSA PRIVATE KEY-----,属于PKCS#1),转换成RSAParameters后导入。这种方式需要处理ASN.1编码,容易出错,仅适合简单场景。

示例解析方法

protected RSAParameters ReadPkcs1PrivateKey(byte[] privateKeyBytes)
{
    var rsaParams = new RSAParameters();
    using (var ms = new MemoryStream(privateKeyBytes))
    using (var reader = new BinaryReader(ms))
    {
        // 跳过ASN.1固定头
        reader.ReadInt32();
        reader.ReadByte();
        reader.ReadByte();
        reader.ReadInt32();

        rsaParams.Modulus = reader.ReadBytes(GetIntegerLength(reader));
        rsaParams.Exponent = reader.ReadBytes(GetIntegerLength(reader));
        rsaParams.D = reader.ReadBytes(GetIntegerLength(reader));
        rsaParams.P = reader.ReadBytes(GetIntegerLength(reader));
        rsaParams.Q = reader.ReadBytes(GetIntegerLength(reader));
        rsaParams.DP = reader.ReadBytes(GetIntegerLength(reader));
        rsaParams.DQ = reader.ReadBytes(GetIntegerLength(reader));
        rsaParams.InverseQ = reader.ReadBytes(GetIntegerLength(reader));
    }
    return rsaParams;
}

private int GetIntegerLength(BinaryReader reader)
{
    byte byteValue = reader.ReadByte();
    int length = byteValue;
    if (byteValue > 0x80)
    {
        length = byteValue & 0x7F;
        for (int i = 0; i < length; i++)
        {
            byteValue = reader.ReadByte();
        }
        length = byteValue;
    }
    return length;
}

使用方式

修改ReadRsaPrivateKey方法,去除PEM头后调用上述解析方法:

protected RSAParameters ReadRsaPrivateKey(FileInfo file)
{
    string key = File.ReadAllText(file.FullName);
    string privateKeyPEM = key
        .Replace("-----BEGIN RSA PRIVATE KEY-----", "")
        .Replace(Environment.NewLine, "")
        .Replace("-----END RSA PRIVATE KEY-----", "");

    byte[] encoded = Convert.FromBase64String(privateKeyPEM);
    return ReadPkcs1PrivateKey(encoded);
}

内容的提问来源于stack exchange,提问作者Totoblo

火山引擎 最新活动