如何在C#中解密使用Java加密的字符串?

4
我有一个字符串,使用Java进行加密。现在我需要在C#中对其进行解密。
我在C#和Java中使用相同的公钥/私钥的RSA算法。
但是在C#中解密时出现了“Bad Data”错误。
值得注意的是:我可以在Java中解密此字符串!而且我可以使用C#进行加密并使用C#进行解密!!但是,当我尝试使用其中之一(C#或Java)进行加密,并尝试使用另一个进行解密时,会引发错误!
这是我的C#代码:
string privateKey = "<RSAKeyValue><Modulus>rFsMn+idg8jmVMk249DzJc7AFft3+/jcnYDTh9wHee3tgFu1gBRh7e+ao+MWq7NEN0N7kUHa7O4c/ND2Ahcx/h4mXD5KDoixFRBUsxYqCJVA68qYJ7vozVPMjNr4jeOo1xt+oevO5+mUWtcaib5Iw51u1Jq/6qCqLsm8Eq3cnsE=</Modulus><Exponent>AQAB</Exponent><P>5aqTyz3GH655H+vO/BzJvFzpILpxLwXZEvqp3l3NYXKqP0tdkY1g36o6M9YodI3h8ho4VFYofIqA1+V0qPkuDQ==</P><Q>wB45uljBS8Z+WGRE1cRdpZb5aKUv76uLlCp6agtPBBhjXNIQrN8MpOCTvZM2cOsuYpYhDtnwsTY9KKXdBmv6hQ==</Q><DP>KB474uzPhwk7L1BJv9BnjPfN4WGwE765xI70zVslXThidNv9ZEeF/IwHzrZCKtn99gSOgmzqdZbcGtqCHmIooQ==</DP><DQ>eLnFrvsdJJ/sP2Fq/CX0bx0rR34eXG6hPI9g84h9s+YbcnWy8t8LVASn8oYyvMydDminB20e2k1qK0PnW6S4/Q==</DQ><InverseQ>rlPpLse8LJ0KRglnu2D1xzJT90QqzS3o80P0WTpUvm95mF5d8YaVj/d9W7FBdgZ98y6Q7of+wLCmYGKLg56wYQ==</InverseQ><D>Gs8mzZDPP3p2aWXLBfCwgYcBVeoBpc318wHg5VcSSqL5uGeLedqxyOLmOOvP0PFXgQkcJWIK/aOkGqcePQECo3TNiK+uLSwc97V3spZah70FFJVyh23Y+o0wlRGHAm5Nj9QieHlVwhgJPkNUJYgH9qkwB9aCpl+rdAG3da2fQ2E=</D></RSAKeyValue>";
string publicKey = "<RSAKeyValue><Modulus>rFsMn+idg8jmVMk249DzJc7AFft3+/jcnYDTh9wHee3tgFu1gBRh7e+ao+MWq7NEN0N7kUHa7O4c/ND2Ahcx/h4mXD5KDoixFRBUsxYqCJVA68qYJ7vozVPMjNr4jeOo1xt+oevO5+mUWtcaib5Iw51u1Jq/6qCqLsm8Eq3cnsE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";



public string EncryptData(string data2Encrypt )
{
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    rsa.FromXmlString(publicKey);
    byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
    byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
    return Convert.ToBase64String(cipherbytes);
}

public string DecryptData(string data2Decrypt)
{
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    rsa.FromXmlString(privateKey);
    byte[] plainbytes = rsa.Decrypt(Convert.FromBase64String(data2Decrypt), false);
    return System.Text.Encoding.UTF8.GetString(plainbytes);
}

我的Java代码如下:

byte[] expBytes = Base64.decode("AQAB".getBytes("UTF-8"), Base64.DEFAULT);
byte[] modBytes = Base64.decode("rFsMn+idg8jmVMk249DzJc7AFft3+/jcnYDTh9wHee3tgFu1gBRh7e+ao+MWq7NEN0N7kUHa7O4c/ND2Ahcx/h4mXD5KDoixFRBUsxYqCJVA68qYJ7vozVPMjNr4jeOo1xt+oevO5+mUWtcaib5Iw51u1Jq/6qCqLsm8Eq3cnsE=".getBytes("UTF-8"), Base64.DEFAULT);
byte[] dBytes = Base64.decode("Gs8mzZDPP3p2aWXLBfCwgYcBVeoBpc318wHg5VcSSqL5uGeLedqxyOLmOOvP0PFXgQkcJWIK/aOkGqcePQECo3TNiK+uLSwc97V3spZah70FFJVyh23Y+o0wlRGHAm5Nj9QieHlVwhgJPkNUJYgH9qkwB9aCpl+rdAG3da2fQ2E=".getBytes("UTF-8"), Base64.DEFAULT);

BigInteger modules = new BigInteger(1, modBytes);
BigInteger exponent = new BigInteger(1, expBytes);
BigInteger d = new BigInteger(1, dBytes);

KeyFactory factory = KeyFactory.getInstance("RSA");
Cipher cipher = Cipher.getInstance("RSA");
String input = "test";

RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(modules, exponent);
PublicKey pubKey = factory.generatePublic(pubSpec);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encrypted = cipher.doFinal(input.getBytes());

String strEncrypted = Base64.encodeToString(encrypted, Base64.DEFAULT);

我无法在c#中解密strEncrypted的值。

而且,即使使用相同的密钥、算法和数据,在java中加密的值也与c#中不同!!!


1
首先,您是否在调试器中验证了从Base64方法获取的相同byte[]值?这是Java中的哪个Base64 - chrylis -cautiouslyoptimistic-
你如何将密文从一个系统传输到另一个系统?你的密文有多大? - Maarten Bodewes
@chrylis 实际上我正在使用 android.util.Base64 - Mehdi
加密的结果应该对于每个加密操作都不同(想象一下如果您多次向同一个接收者发送“是”或“否”会发生什么)。RSA加密使用安全的随机填充值。唯一测试的方法是解密。 - Maarten Bodewes
在C#中,每次调用加密方法都会得到一个不同的字符串。但是在Java中并非如此!每次都会得到相同的字符串!!!我感到头晕 :( - Mehdi
2个回答

3
< p > RSACryptoServiceProvider.Encrypt(plainbytes, false)的第二个参数表示使用PKCS#1填充。 true是OAEP填充。

在Java中,您使用的安全提供程序将"RSA"映射到"RSA/ECB/NoPadding",即仅进行加密而没有任何填充,因此加密结果始终相同。 因此需要指定"RSA/ECB/PKCS1Padding"以匹配C#行为。

您应始终指定模式和填充,否则安全提供程序将选择自己的默认值 - 并且每个提供程序的默认值可能不同。


1
我找到了它:

:)

我改变了这行:

Cipher cipher = Cipher.getInstance("RSA");

发送至:

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");

它运行良好。但谁知道这些之间的区别?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接