将C#RSACryptoServiceProvider转换为JAVA代码

时间:2013-08-06 20:32:47

标签: c# java security encryption rsa

我获得了由Web服务团队编写的这个C#代码,该代码公开了我计划使用的一些Web服务。我的密码需要使用此代码加密,以便Web服务知道如何在最终解密它。

using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
    rsa.FromXmlString(publicKey);
    byte[] plainBytes = Encoding.Unicode.GetBytes(clearText);
    byte[] encryptedBytes = rsa.Encrypt(plainBytes, false);
    return Convert.ToBase64String(encryptedBytes);
}

我正在使用Java来使用这个Web服务,现在,我在将#C代码转换为Java代码时遇到了问题,因为该Web服务无法正确解密我的密码。

这是我目前失败的尝试: -

// my clear text password
String clearTextPassword = "XXXXX";

// these values are provided by the web service team
String modulusString = "...";
String publicExponentString = "...";

BigInteger modulus = new BigInteger(1, Base64.decodeBase64(modulusString.getBytes("UTF-8")));
BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(publicExponentString.getBytes("UTF-8")));

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);

String encodedEncryptedPassword = new String(Base64.encodeBase64(cipher.doFinal(clearTextPassword.getBytes("UTF-8"))));

我做错了什么?非常感谢。

2013-08-07 - 更新

我正在阅读this website,我意识到我的模数值和公共指数值不是十六进制。所以,我修改了我的代码并尝试使用{@ 1}},如@Dev。

所述
RSA/ECB/PKCS1PADDING

当我点击网络服务时,我收到此错误:“要解密的数据超过此模数128字节的最大值。”好像明文密码仍然没有加密得当。

非常感谢任何帮助或建议。感谢。

2013-08-09 - 解决方案

我在下面发布了最终的工作解决方案。

3 个答案:

答案 0 :(得分:11)

找到了解决方案。

String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";

byte[] modulusBytes = Base64.decodeBase64(modulusString);
byte[] exponentBytes = Base64.decodeBase64(publicExponentString);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger publicExponent = new BigInteger(1, exponentBytes);

RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);

byte[] plainBytes = clearTextPassword.getBytes("UTF-16LE");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedStringBase64 = Base64.encodeBase64String(cipherData);

答案 1 :(得分:1)

根据RSACryptoServiceProvider.Encrypt上的MSDN文档,当第二个参数为false时,密码使用PKCS#1 v1.5填充。所以,你的密码规范是不正确的。

请尝试RSA/ECB/PKCS1PADDING

您正在将您的密钥材料转换为第二个代码示例,并且您已将其损坏,最终使您的密码认为您拥有的密钥材料比您实际拥有的密钥材料更长,并且使您的邮件过长(这会触发您的错误)以及另一端的解密密码无法理解。直接转换为字节数组并将其传递给BigInteger

String modulusString = "...";
String publicExponentString = "...";

byte[] mod = Base64.decodeBase64(modulusString);
byte[] e = Base64.decodeBase64(publicExponentString);

BigInteger modulus = new BigInteger(1, mod);
BigInteger publicExponent = new BigInteger(1, e);

答案 2 :(得分:0)

使用RSA/ECB/OAEPWithSHA-1AndMGF1Padding似乎是解决此问题的方法。

别忘了这些替代品。

编码为Base64 使用System.Convert将输入转换为Base64。

用-和/替换+。示例:Foo+bar/=== becomes Foo-bar_===.

在字符串的末尾替换任意数量的=,并用整数表示它们的数量。例如:Foo-bar _ ===变为Foo-bar_3。

从Base64解码 用相同数量的=符号替换字符串末尾的数字。示例:Foo-bar_3 becomes Foo-bar_===.

用+代替-,用/代替_。示例:Foo-bar_=== becomes Foo+bar/===.

使用System.Convert解码来自Base64的预处理输入。