异常场景:
前端使用:jsencrypt.js 进行RSA加密
后端使用C#(System.Security.Cryptography.Algorithms或System.Security.Cryptography.Csp)进行解密
出现小概率解密失败的情况
异常提示:
System.Security.Cryptography.CryptographicException: 資料錯誤。
System.Security.Cryptography.Algorithms:The length of the data to decrypt is not valid for the size of this key.
异常原因:
版本:
jsencrypt 2.3.1 and 3.0.0-rc.1
问题:
JSEncrypt#encrypt有时会生成长度小于模数的密文,即,密文不会填充模数长度的前导0x00值。
根据RFC 8017, Section-7.2.2, 第1步,长度小于模数的密文是无效的。
JSEncrypt#decrypt似乎考虑到了这一点,因为它还会解密太短的密文 正确地。 当以其他语言(例如,C#)执行解密时,会出现问题。
这里 解密会中止,并显示一条错误消息,密码长度不正确,请参见此SO发行的 jsencryptjs-encrypt-but-python-cannot-decrypt.
以上为 travist/jsencrypt项目的Issues相关的译文 原文点击这里
总得来说就是jsencrypt.js在生成密文时可能会生成小于规定长度的密文,jsencrypt.js能够正确解密这种密文,但一些后台语言如C#,Python等在解密是就会出现异常
解决方案:
解决这个问题之前需要了解一下 密文长度,在不考虑切片加密的情况下,密文长度和秘钥长度一致。
例如我们选用1024bit的秘钥那么密文长度就应该是128B(1024/8)。
这里的密文长度指的是是Byte数组的长度,不是Base64字符串的长度,因为Base64有补全机制
那么我们以1024bit的秘钥为例解决方案如下:
方案一:前端处理(JS)
在使用jsencrypt.js加密后对异常密文进行补全处理。代码如下:
var RSAPublicKey = '1024bit公钥';
var encrypt = new JSEncrypt();
encrypt.setPublicKey(RSAPublicKey);
var ciphertext=encrypt.encrypt(content);
//对密码尝试进行补全
ciphertext=btoa(atob(ciphertext).padStart(128, "\0"));
方案二:后端处理(C#)
在解密前对密文尝试进行补全处理。代码如下
/// <summary>
/// 补全密文
/// </summary>
/// <param name="strCiphertext">密文</param>
/// <param name="keySize">秘钥长度</param>
/// <returns>补全后的密文</returns>
private static string CorrectionCiphertext(string strCiphertext, int keySize = 1024)
{
int ciphertextLength = keySize / 8;
byte[] data = Convert.FromBase64String(strCiphertext);
var newData = new List<byte>(data);
while (newData.Count < ciphertextLength)
{
newData.Insert(0, 0x00);
}
return Convert.ToBase64String(newData.ToArray());
}
以上就是 RSA Decrypt 异常的解决方案!