C# RSA解密报错:数据长度与密钥不匹配及公钥导入问题
RSA解密功能实现问题
场景说明
我正在尝试实现RSA加密消息的解密功能。
首先在C#中使用RSA算法完成了消息加密:开发了一款简易授权类Windows窗体应用,使用如下所示的RSAService类实现加密逻辑,将Encrypt方法返回的加密结果以.txt文件格式存储到其他项目路径下,同时将GetPublicKey方法返回的公钥存储至数据库。
加密端实现代码:
public class RSAService { private static RSACryptoServiceProvider cryptoServiceProvider = new RSACryptoServiceProvider(2048); private RSAParameters _privateKey; private RSAParameters _publicKey; public RSAService() { _privateKey = cryptoServiceProvider.ExportParameters(true); _publicKey = cryptoServiceProvider.ExportParameters(false); } public string GetPublicKey() { var stringWriter = new StringWriter(); var xmlSerializer = new XmlSerializer(typeof(RSAParameters)); xmlSerializer.Serialize(stringWriter, _publicKey); return stringWriter.ToString(); } public string Encrypt(string plainText) { cryptoServiceProvider = new RSACryptoServiceProvider(); cryptoServiceProvider.ImportParameters(_publicKey); var data = Encoding.Unicode.GetBytes(plainText); var cypher = cryptoServiceProvider.Encrypt(data, false); return Convert.ToBase64String(cypher); } }
后续需要在存储了.txt加密文件的主应用中解密上述加密消息,读取消息内容中包含的用户数量、用户名等参数,但目前解密失败,使用的解密相关实现代码如下:
public class RSAService : IRSAService { private static RSACryptoServiceProvider cryptoServiceProvider = new RSACryptoServiceProvider(2048); private readonly ICompanyService _companyService; private RSAParameters _publicKey; public RSAService(ICompanyService companyService) { _companyService = companyService; _publicKey = cryptoServiceProvider.ExportParameters(false); } public string GetPublicKey(string companyCode) => _companyService.GetCompanyLicenceKey(companyCode); public string Decrypt(string cypherText, string companyCode) { using (cryptoServiceProvider = new RSACryptoServiceProvider()) { var dataBytes = Convert.FromBase64String(cypherText); var publicKeyText = GetPublicKey(companyCode); cryptoServiceProvider.ImportParameters(????); var plainText = cryptoServiceProvider.Decrypt(dataBytes, false); return Encoding.Unicode.GetString(plainText); } } }
具体问题
- 已从.txt文件中读取密文作为
cypherText参数,但不清楚如何接入使用存储在数据库中的公钥数据,如何将publicKeyText变量加入解密流程,ImportParameters(????);位置应当传入什么参数? - 尝试在该位置传入
_privateKey时,系统抛出错误:The length of the data to decrypt is not valid for the size of this key。
问题原因与解决方案
核心错误点
- RSA算法的基本逻辑是公钥加密、私钥解密,你当前数据库中只存储了公钥,根本无法完成解密操作。
- 你在加密端生成RSA密钥对后,仅持久化存储了公钥,对应的私钥没有做任何持久化保存,解密端实例化时生成的新私钥和加密用的公钥完全不属于同一密钥对,这也是传入
_privateKey时报密钥长度不匹配错误的根本原因。 - 你从数据库读取的
publicKeyText是XML格式序列化后的字符串,无法直接传入ImportParameters方法,需要先反序列化为RSAParameters类型才能导入,且就算导入成功,公钥也不支持解密操作。
修复步骤
改造加密端,持久化存储私钥
给加密端的RSAService增加私钥序列化导出方法,生成密钥对后将私钥和公钥绑定对应公司标识,单独存储到安全的位置(比如权限严格管控的配置中心、密钥管理服务,禁止和加密文件、公钥存在同一公开可访问路径):public string GetPrivateKey() { var stringWriter = new StringWriter(); var xmlSerializer = new XmlSerializer(typeof(RSAParameters)); xmlSerializer.Serialize(stringWriter, _privateKey); return stringWriter.ToString(); }注意加密端不要在每次调用加密方法时重新生成密钥对,确保同一授权主体对应的公钥、私钥是匹配的一对。
改造解密端逻辑,导入匹配的私钥完成解密
删解密端构造函数中自行生成新RSA密钥对的无关逻辑,解密时先根据公司编码读取对应绑定的私钥XML字符串,反序列化为RSAParameters后导入RSA实例再执行解密:public string Decrypt(string cypherText, string companyCode) { using (var rsa = new RSACryptoServiceProvider(2048)) { var dataBytes = Convert.FromBase64String(cypherText); // 读取对应公司的私钥,而非公钥 var privateKeyXml = _companyService.GetCompanyPrivateLicenceKey(companyCode); // 反序列化XML为RSAParameters类型 var xmlSerializer = new XmlSerializer(typeof(RSAParameters)); using (var reader = new StringReader(privateKeyXml)) { var privateKeyParams = (RSAParameters)xmlSerializer.Deserialize(reader); rsa.ImportParameters(privateKeyParams); } var plainTextBytes = rsa.Decrypt(dataBytes, false); return Encoding.Unicode.GetString(plainTextBytes); } }
内容的提问来源于stack exchange,提问作者mordeby
相关产品推荐
相关产品推荐

