C#生成RSA密钥,JS加密后C#解密报数据长度无效异常求助
问题原因及解决方案
核心问题分析
- 密钥格式不兼容:C#导出的
RSAPublicKey是原始PKCS#1公钥(无PEM标识头),而cryptico/jsencrypt需要识别带格式标识的公钥,直接传入原始Base64字符串会导致加密逻辑异常。 - 解密字节转换错误:前端加密后的
cipher是Base64编码字符串,服务端用ASCII.GetBytes转换会破坏加密数据结构,需用Base64解析方式还原字节。 - Padding规则不一致:需确保前后端RSA加密使用相同的Padding标准(PKCS#1)。
解决方案一:改用jsencrypt(推荐,兼容性更好)
jsencrypt原生支持OpenSSL PEM格式密钥,与C# RSA适配性更强。
1. 服务端修改(生成PEM格式公钥)
调整OnGet方法,导出带PEM头的标准公钥:
public void OnGet() { using (RSA rsa = RSA.Create(1024)) { // 导出PKCS#1格式公钥并添加PEM标识 var publicKeyBytes = rsa.ExportRSAPublicKey(); publickey = $"-----BEGIN RSA PUBLIC KEY-----\n{Convert.ToBase64String(publicKeyBytes, Base64FormattingOptions.InsertLineBreaks)}\n-----END RSA PUBLIC KEY-----"; // 私钥保持原始Base64格式存储 HttpContext.Session.SetString("privatekey", Convert.ToBase64String(rsa.ExportRSAPrivateKey())); } }
2. 前端修改(替换为jsencrypt加密)
替换cryptico为jsencrypt,调整加密逻辑:
@section Scripts { <script src="jsencrypt.min.js"></script> <script type="text/javascript"> $(document).ready(function() { $("#form1").submit(function(e) { var encryptor = new JSEncrypt(); encryptor.setPublicKey($('#hdnKey').val()); var encryptedStr = encryptor.encrypt($('#email').val()); $('#email').val(encryptedStr); }); }); </script> }
3. 服务端解密修正(修复字节解析)
修改OnPost方法,用Base64解析加密数据:
public void OnPost(string emailaddress) { var key = HttpContext.Session.GetString("privatekey"); if (string.IsNullOrEmpty(key)) return; int totalRead = 0; using (var rsa = RSA.Create()) { rsa.ImportRSAPrivateKey(new ReadOnlySpan<byte>(Convert.FromBase64String(key)), out totalRead); // 从Base64字符串还原加密字节 var encryptedBytes = Convert.FromBase64String(emailaddress); var emailBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.Pkcs1); ViewData["Email"] = System.Text.Encoding.UTF8.GetString(emailBytes); } }
解决方案二:修复cryptico兼容问题
若坚持使用cryptico,需调整密钥格式和数据处理逻辑:
1. 服务端生成cryptico兼容公钥
cryptico需要特定格式的公钥字符串,可通过导出模数和指数构造:
public void OnGet() { using (RSA rsa = RSA.Create(1024)) { var parameters = rsa.ExportParameters(false); // 将模数和指数转为十六进制格式 string modulus = BitConverter.ToString(parameters.Modulus).Replace("-", "").ToLower(); string exponent = BitConverter.ToString(parameters.Exponent).Replace("-", "").ToLower(); // 构造cryptico识别的公钥字符串 publickey = $"rsa-{rsa.KeySize}-{modulus}-{exponent}"; HttpContext.Session.SetString("privatekey", Convert.ToBase64String(rsa.ExportRSAPrivateKey())); } }
2. 服务端解密修正
同样需用Base64解析加密数据:
public void OnPost(string emailaddress) { var key = HttpContext.Session.GetString("privatekey"); if (string.IsNullOrEmpty(key)) return; int totalRead = 0; using (var rsa = RSA.Create()) { rsa.ImportRSAPrivateKey(new ReadOnlySpan<byte>(Convert.FromBase64String(key)), out totalRead); var encryptedBytes = Convert.FromBase64String(emailaddress); var emailBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.Pkcs1); ViewData["Email"] = System.Text.Encoding.UTF8.GetString(emailBytes); } }
关键注意事项
- 密钥长度统一:前后端需使用相同密钥长度(如1024/2048位),1024位密钥的PKCS#1加密最大明文长度为117字节。
- 编码一致性:统一使用UTF-8编码处理字符串,避免ASCII编码丢失特殊字符或中文。
- 私钥安全:确保Session配置可靠,私钥仅存储在服务端,绝不泄露到前端。
内容的提问来源于stack exchange,提问作者Ajay Kelkar
相关产品推荐
相关产品推荐

