从模数和指数生成RSA公钥:Java转C#实现遇阻求助
解决C#复刻Java RSA加密对接Clover支付API的问题
你的核心问题在于RSA密钥参数的字节序处理错误以及不必要的BigInteger转换导致的格式混乱,以下是修正后的实现步骤和代码:
关键问题分析
- 模数处理错误:你将模数转成
BigInteger再转回字节数组,会导致字节序从大端变为小端,而RSAParameters要求模数是大端字节数组(与Java的公钥规范一致)。 - 指数解析错误:硬编码指数不可靠,应从原始256字节中提取有效部分(去掉前导零),且
RSAParameters.Exponent需要指数的大端字节数组(无多余前导零)。 - BigInteger符号处理差异:Java的
BigInteger是有符号类型,需加0前缀避免负数;而C#的RSAParameters直接使用原始字节数组,无需额外处理符号。
修正后的C#代码
string taPublicKey = "vyYRQA3cS4wV9yk+6bFzA7KLDmE+D/SOP+Q5bNOPG9nUDkAPalRBz12KA5SDxTw2vO1BIeSFUQlYTpzEDb/XkfNNm5e6nqf12M4kdHP1F2EXW4WArilUZegAVw/Y7FvAkA8PQFbfgmBirSa5GS/fuAHjemqEf0DxIgq552IDeFw3nB0vccK6ePue5sVB9Sm2vWpKm/lj2UE4P6z2ngZr5V31cSAVN08USxHvz+MEnoUBKt6aKvfRUAp4iFyIpxlp4eylxY8zizPekS29lcRMsI9hGug2CoKFhhUJ1gD8G280zIoWCxysNvl40k/l8OTtPKrnlhAzQcIyy/RB0lwb6QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVTU="; byte[] publicKeyBytes = Convert.FromBase64String(taPublicKey); // 1. 提取模数:直接取前256字节(大端格式,与Java一致) byte[] modulus = new byte[256]; Array.Copy(publicKeyBytes, 0, modulus, 0, 256); // 2. 提取指数:从后256字节中去掉前导零,得到有效大端字节数组 byte[] exponentRaw = new byte[256]; Array.Copy(publicKeyBytes, 256, exponentRaw, 0, 256); // 找到第一个非零字节的位置(跳过前导零) int firstNonZeroIndex = Array.FindIndex(exponentRaw, b => b != 0); byte[] exponent = exponentRaw.Skip(firstNonZeroIndex).ToArray(); // 3. 配置RSA参数 RSAParameters rsaParams = new RSAParameters { Modulus = modulus, Exponent = exponent }; // 4. 加密银行卡数据(保持与Java一致的编码和填充方式) string cardToEncrypt = "00000000" + "6011361000006668"; string base64EncryptedCard = null; // 注意:若Java使用的是PKCS#1 v1.5填充,需将第二个参数改为false using (var rsa = new RSACryptoServiceProvider(2048)) { try { rsa.PersistKeyInCsp = false; rsa.ImportParameters(rsaParams); // 转换为UTF-8字节(与Java保持一致) byte[] cardBytes = Encoding.UTF8.GetBytes(cardToEncrypt); // 使用OAEP填充(若Java用PKCS#1则改为false) byte[] encryptedBytes = rsa.Encrypt(cardBytes, true); base64EncryptedCard = Convert.ToBase64String(encryptedBytes); } catch (Exception ex) { // 处理异常,比如日志记录 Console.WriteLine($"加密失败:{ex.Message}"); } finally { rsa.PersistKeyInCsp = false; } } return base64EncryptedCard;
额外注意事项
- 填充方式一致性:若Java示例中使用的是
RSA/ECB/PKCS1Padding(而非OAEP),需将rsa.Encrypt的第二个参数改为false。 - 字节编码验证:确认Java中是使用
UTF-8转换字符串为字节数组,若为其他编码(如ASCII),需同步修改C#中的Encoding类型。 - 密钥长度匹配:确保
RSACryptoServiceProvider的初始化长度(2048)与Clover提供的公钥长度一致。
内容的提问来源于stack exchange,提问作者ElkDev
相关产品推荐
相关产品推荐

