You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#生成RSA密钥,JS加密后C#解密报数据长度无效异常求助

问题原因及解决方案

核心问题分析

  1. 密钥格式不兼容:C#导出的RSAPublicKey是原始PKCS#1公钥(无PEM标识头),而cryptico/jsencrypt需要识别带格式标识的公钥,直接传入原始Base64字符串会导致加密逻辑异常。
  2. 解密字节转换错误:前端加密后的cipher是Base64编码字符串,服务端用ASCII.GetBytes转换会破坏加密数据结构,需用Base64解析方式还原字节。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:15:41