.NET 6转.NET 4.8:C#中ImportRSAPrivateKey方法替代方案求助
解决.NET 4.8中替换
ImportRSAPrivateKey方法的问题 核心问题说明
.NET Framework 4.8的RSACryptoServiceProvider类确实没有ImportRSAPrivateKey和ExportRSAPrivateKey方法,这两个是.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; } } }
关键修改点
- 用BouncyCastle的
PemReader读取PEM私钥,转换成.NET原生的RSAParameters - 直接使用
RSACryptoServiceProvider.ImportParameters导入密钥,替代原有的ImportRSAPrivateKey - 调整
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




