使用RSA公钥加密时触发‘Bad Version of provider’错误的解决方法咨询
解决RSA公钥导入时的"Bad Version of provider"异常
咱们先把问题根源拎清楚:你手里的公钥是PEM格式(带-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----头尾标记),但你用的ImportCspBlob和ImportRSAPublicKey都不直接支持这种格式,这就是触发异常的核心原因。
具体问题拆解
ImportCspBlob要求输入的是Windows CSP专属的二进制Blob格式,和PEM完全不兼容,直接传入PEM字节肯定报错。ImportRSAPublicKey需要的是DER编码的PKCS#1/PKCS#8公钥,但你给的是带Base64编码和注释头尾的PEM文本,自然无法解析。
解决方案
下面提供两种实用的解决方式,按需选择:
方式1:手动处理PEM格式(无需第三方库,.NET 5+友好)
先清理PEM的头尾标记,解码Base64内容,再导入公钥:
public static string EncryptFromPublicKey(string kwypath, string data) { try { // 读取并处理PEM公钥文本 var pemContent = File.ReadAllText(kwypath); // 移除头尾标记和换行符,提取纯Base64内容 var base64Key = pemContent .Replace("-----BEGIN PUBLIC KEY-----", "") .Replace("-----END PUBLIC KEY-----", "") .Replace("\r", "") .Replace("\n", ""); // Base64解码为DER格式字节 var publicKeyBytes = Convert.FromBase64String(base64Key); // 初始化RSA实例,导入公钥 using var rsa = RSA.Create(); // .NET 5+可直接用ImportFromPem,一步到位 // rsa.ImportFromPem(pemContent); // 兼容旧版本用ImportSubjectPublicKeyInfo解析DER rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _); // 执行加密:注意ASCII编码仅适用于纯ASCII文本,建议非ASCII场景用UTF8 var dataToEncrypt = Encoding.ASCII.GetBytes(data); // PKCS1Padding对应参数RSAEncryptionPadding.Pkcs1 var encryptedByteArray = rsa.Encrypt(dataToEncrypt, RSAEncryptionPadding.Pkcs1); // 转换为逗号分隔的字符串(和原逻辑保持一致) var sb = new StringBuilder(); for (int i = 0; i < encryptedByteArray.Length; i++) { sb.Append(encryptedByteArray[i]); if (i < encryptedByteArray.Length - 1) sb.Append(","); } return sb.ToString(); } catch (Exception e) { Console.WriteLine(e); throw; } }
方式2:使用BouncyCastle库(兼容.NET Framework)
如果你的项目是.NET Framework,或需要更灵活的加密操作,可以借助BouncyCastle处理PEM:
- 先通过NuGet安装
BouncyCastle包 - 修改代码如下:
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Security; public static string EncryptFromPublicKey(string kwypath, string data) { try { // 读取PEM公钥 using var reader = File.OpenText(kwypath); var pemReader = new PemReader(reader); var publicKeyParam = (RsaKeyParameters)pemReader.ReadObject(); // 转换为.NET兼容的RSA实例 var rsa = (RSACryptoServiceProvider)DotNetUtilities.ToRSA(publicKeyParam); var dataToEncrypt = Encoding.ASCII.GetBytes(data); // false参数对应PKCS1Padding填充方式 var encryptedByteArray = rsa.Encrypt(dataToEncrypt, false); var sb = new StringBuilder(); for (int i = 0; i < encryptedByteArray.Length; i++) { sb.Append(encryptedByteArray[i]); if (i < encryptedByteArray.Length - 1) sb.Append(","); } return sb.ToString(); } catch (Exception e) { Console.WriteLine(e); throw; } }
额外提醒
- 推荐用
RSA.Create()替代旧的RSACryptoServiceProvider,它会自动适配系统加密提供者,减少版本兼容性问题。 - 若文本包含非ASCII字符,
Encoding.ASCII会导致数据丢失,建议替换为Encoding.UTF8。
内容的提问来源于stack exchange,提问作者Simone Spagna
相关产品推荐
相关产品推荐

