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

如何将Java的X509EncodedKeySpec/RSA加密转为.NET 4.8的C#代码?

如何将指定Java RSA加密代码转换为.NET Framework 4.8的C#代码?

问题背景

需要将以下Java RSA加密代码转换为适用于.NET Framework 4.8的C#代码,已尝试两种BouncyCastle实现但无法通过单元测试。

原Java代码

private static String getBearerToken(String publicKeyBase64, String apiKey)
{
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    Cipher cipher = Cipher.getInstance("RSA");
    byte[] encodedPublicKey = Base64.decodeBase64(publicKeyBase64);
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
    PublicKey pk = keyFactory.generatePublic(publicKeySpec);

    cipher.init(Cipher.ENCRYPT_MODE, pk);

    byte[] encryptedApiKey = Base64.encodeBase64(cipher.doFinal(apiKey.getBytes("UTF-8")));

    return new String(encryptedApiKey, "UTF-8");
}

未通过测试的C#尝试

第一种尝试(未完成):

public static string GetBearerToken(string publicKeyBase64, string apiKey)
{
    var key = Convert.FromBase64String(publicKeyBase64);
    var info = SubjectPublicKeyInfo.GetInstance(key);
    var pk = PublicKeyFactory.CreateKey(info);
    var x = ???(pk);

    using (var rsa = new RSACryptoServiceProvider(???))
    {
        var parameters = new RSAParameters()
        {
            Modulus = x.???,
            Exponent = x.???
        };

        rsa.ImportParameters(parameters);

        var data = Encoding.UTF8.GetBytes(apiKey);
        var encryptedBytes = rsa.Encrypt(data, true);

        return Convert.ToBase64String(encryptedBytes);
    }
}

第二种尝试(可运行但不通过测试):

public static string GetBearerToken(string publicKeyBase64, string apiKey)
{
    var keyBytes = Convert.FromBase64String(publicKeyBase64);
    var info = SubjectPublicKeyInfo.GetInstance(keyBytes);
    var keyParameter = PublicKeyFactory.CreateKey(info);

    var encryptEngine = new RsaEngine();

    encryptEngine.Init(true, keyParameter);

    var dataToEncrypt = Encoding.UTF8.GetBytes(apiKey);
    var encryptedBytes = encryptEngine.ProcessBlock(dataToEncrypt, 0, dataToEncrypt.Length);

    return Convert.ToBase64String(encryptedBytes);
}

单元测试用例

[TestMethod]
public void Utils_GetBearerToken()
{
    var publicKey = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAszE+xAKVB9HRarr6/uHYYAX/RdD6KGVIGlHv98QKDIH26ldYJQ7zOuo9qEscO0M1psSPe/67AWYLEXh13fbtcSKGP6WFjT9OY6uV5ykw9508x1sW8UQ4ZhTRNrlNsKizE/glkBfcF2lwDXJGQennwgickWz7VN+AP/1c4DnMDfcl8iVIDlsbudFoXQh5aLCYl+XOMt/vls5a479PLMkPcZPOgMTCYTCE6ReX3KD2aGQ62uiu2T4mK+7Z6yvKvhPRF2fTKI+zOFWly//IYlyB+sde42cIU/588msUmgr3G9FYyN2vKPVy/MhIZpiFyVc3vuAAJ/mzue5p/G329wzgcz0ztyluMNAGUL9A4ZiFcKOebT6y6IgIMBeEkTwyhsxRHMFXlQRgTAufaO5hiR/usBMkoazJ6XrGJB8UadjH2m2+kdJIieI4FbjzCiDWKmuM58rllNWdBZK0XVHNsxmBy7yhYw3aAIhFS0fNEuSmKTfFpJFMBzIQYbdTgI28rZPAxVEDdRaypUqBMCq4OstCxgGvR3Dy1eJDjlkuiWK9Y9RGKF8HOI5a4ruHyLheddZxsUihziPF9jKTknsTZtF99eKTIjhV7qfTzxXq+8GGoCEABIyu26LZuL8X12bFqtwLAcjfjoB7HlRHtPszv6PJ0482ofWmeH0BE8om7VrSGxsCAwEAAQ==";
    var apiKey = "aaaab09uz9f3asdcjyk7els777ihmwv8";
    var expectedToken = "rfNjFso4uJbzhwl8E9vizqmHEuD7XDmPqfsRx1L62UoTmURGGLAGgJSl9lCPbgy03Q7NwozFYD4r9BFQY5QpvErHximBDU8HE25urVahm0HnB8VyCIobs684XGSN4GjdequePDrG6xUAxxpvmhqZRlGt1tUjUBeBg6kYqp4EnKHsiaBtvd0THGLZbefpT6UaShASQWYNiEPwEon5wtUMaDwnyQEazDu1H2ieN3r8cCVM3hsak59J/1MP07FQjdFbxdCLfA0DuxgpeKpvLs7WrA767WJSB1QZy7hcP1igSGRfd7Zrp6E7gIukdpC0DApqPKa4XsNTo2AMpG4AwiET2WeKvHn539gbwREXf79kZlYdFDCgTc0Zs7OfDx5ZXMCBKHOS/H3tVFJqXTfEfIF5LOzrFU5pPE0HeNBV0Q2vm8qRwQX0RijnvMOGpdcmXb0qoph4oy8Mj+vjRfFRboMAafttDozBhRmWEmeBB3EjYASm1fToQp5ey6ltCiEt8rjL5PlexxB0u3u2LVJQcDzMVNiiq10t1xyw8qtc6BMOyrKVlIANWglRYOKr9saVBVvDFUcCfsghMjUTDeAwHom4A3cSDWmVlNF9Vs/WqCoUzjQCV0BFPDzeAUbQqt7h7OgFno/+D9n5j1eMro0aXbbHNx71u8YmgPJhdixzFhxM1Pw=";

    var token = Utils.GetBearerToken(publicKey, apiKey);

    Assert.AreEqual(expectedToken, token, "GetBearerToken");
}

正确实现方案

关键点说明

Java中Cipher.getInstance("RSA")默认使用RSA/ECB/PKCS1Padding填充模式,之前的C#代码使用RsaEngine时未指定填充,导致结果不匹配。需要明确指定PKCS1填充才能和Java代码行为一致。

方案1:使用BouncyCastle的PaddedBufferedBlockCipher

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Text;

public static string GetBearerToken(string publicKeyBase64, string apiKey)
{
    var keyBytes = Convert.FromBase64String(publicKeyBase64);
    var publicKeyInfo = SubjectPublicKeyInfo.GetInstance(keyBytes);
    var rsaPublicKey = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyInfo);

    // 指定PKCS1填充,匹配Java默认的RSA/ECB/PKCS1Padding
    var cipher = new PaddedBufferedBlockCipher(new RsaEngine(), new Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding());
    cipher.Init(true, rsaPublicKey);

    var dataBytes = Encoding.UTF8.GetBytes(apiKey);
    var encryptedBytes = new byte[cipher.GetOutputSize(dataBytes.Length)];
    var length = cipher.ProcessBytes(dataBytes, 0, dataBytes.Length, encryptedBytes, 0);
    cipher.DoFinal(encryptedBytes, length);

    return Convert.ToBase64String(encryptedBytes);
}

方案2:使用.NET自带的RSACryptoServiceProvider结合BouncyCastle解析公钥

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Security.Cryptography;
using System.Text;

public static string GetBearerToken(string publicKeyBase64, string apiKey)
{
    var keyBytes = Convert.FromBase64String(publicKeyBase64);
    var publicKeyInfo = SubjectPublicKeyInfo.GetInstance(keyBytes);
    var rsaParams = (RsaKeyParameters)PublicKeyFactory.CreateKey(publicKeyInfo);

    // 将BouncyCastle的RsaKeyParameters转换为.NET的RSAParameters
    var dotNetParams = new RSAParameters
    {
        Modulus = rsaParams.Modulus.ToByteArrayUnsigned(),
        Exponent = rsaParams.Exponent.ToByteArrayUnsigned()
    };

    using (var rsa = new RSACryptoServiceProvider())
    {
        rsa.ImportParameters(dotNetParams);
        // false对应PKCS1填充,匹配Java默认行为
        var encryptedBytes = rsa.Encrypt(Encoding.UTF8.GetBytes(apiKey), false);
        return Convert.ToBase64String(encryptedBytes);
    }
}

失败原因分析

  • 第一种未完成代码:未掌握BouncyCastle密钥到.NET密钥的转换逻辑,需先将AsymmetricKeyParameter强制转换为RsaKeyParameters,再提取Modulus和Exponent。
  • 第二种代码:使用RsaEngine时未添加PKCS1填充,与Java默认填充模式不匹配,导致加密结果不一致。

内容的提问来源于stack exchange,提问作者Etherman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:45:14