C# 将C RsacCryptoServiceProvider转换为JAVA代码

C# 将C RsacCryptoServiceProvider转换为JAVA代码,c#,java,security,encryption,rsa,C#,Java,Security,Encryption,Rsa,web服务团队为我编写了这段C代码,它公开了我计划使用的一些web服务。我的密码需要使用此代码加密,以便web服务知道如何在其端对其进行解密 using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.FromXmlString(publicKey); byte[] plainBytes = Encoding.Unicode.GetBytes(clearText); byte[] e

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-更新

我正在阅读,我意识到我的模数值和公共指数值不是十六进制的。因此,我稍微修改了我的代码,并尝试使用@Dev提到的RSA/ECB/PKCS1PADDING

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

// these are the actual values I get from the web service team
String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";

Base64 base64Encoder = new Base64();

String modulusHex = new String(Hex.encodeHex(modulusString.getBytes("UTF-8")));
String publicExponentHex = new String(Hex.encodeHex(publicExponentString.getBytes("UTF-8")));

BigInteger modulus = new BigInteger(modulusHex, 16);
BigInteger publicExponent = new BigInteger(publicExponentHex);

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

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

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

String encodedEncryptedPassword = new String(base64Encoder.encode(cipher.doFinal(clearTextPassword.getBytes("UTF-8"))));
当我点击webservice时,我得到了一个错误:要解密的数据超过了128字节模的最大值。似乎明文密码仍然没有正确加密

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

2013-08-09-解决方案

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

根据上的MSDN文档,当第二个参数为false时,密码使用PKCS1 v1.5填充。所以,你的密码规格一下子就不正确了

请尝试RSA/ECB/PKCS1P添加

在第二个代码示例中,您正在将密钥材料转换为很多内容,并且您破坏了它,这导致密码认为您拥有的密钥材料比实际拥有的多,并使消息过长,从而触发错误,另一端的解密密码无法理解。直接转换为字节数组并将其传递给BigInteger

找到了解决办法

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);
使用RSA/ECB/OAEPTHHA-1和MGF1填充似乎是解决此问题的方法

别忘了这些替代品

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

将+替换为-和/或。示例:Foo+bar/==变成Foo-bar

将字符串末尾的任意数量的=替换为一个整数,表示它们的数量。示例:Foo-bar_u===变为Foo-bar_3

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

替换-为+和u.by/。示例:Foo-bar_===变成Foo+bar/==


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

我尝试了RSA/ECB/PKCS1PADDING,也尝试了RSA密码。两个都失败了。@limc您使用的是谁的Base64类?我目前使用的是Commons编解码器。我最初使用Spring的编解码器,然后我认为这将是问题所在,所以我切换到Commons编解码器。。。但是它们会产生相同的结果。@limc我会检查以确保你输入的代码中的mod和index与C代码中的mod和index匹配。我更新了我的帖子。如果你从中发现任何明显的问题,请告诉我。顺便说一句,我会投票支持你的建议。我有一种感觉,这最终会成为一个登录协议问题,而不是密码问题。我们几乎涵盖了其他一切。很高兴你找到了答案。当我看到Encoding.Unicode.GetBytesString时,我想到的是UTF-8,而不是UTF-16LE,显然是错误的假设,所以你的理解很好。谢谢-解决了我的问题。看起来.NET中的人经常使用编码。UndoDe.GETByo/EnCODIN。UnoDe.GETSHIPE没有意识到它不是UTF 8。如果它对你有用,请考虑将其进行投票,以确保将来有类似问题的用户注意到这个解决方案。我不能在C代码中看到MuleSuthSub和PultPosithStand字符串。我可以知道它是如何在你的c代码中使用这2个值的吗?
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);