Java RSA加密解密.NET

9

我将使用RSA算法在JAVA中进行加密,并尝试使用.NET进行解密。为了寻求帮助,我将提供我的JAVA代码和.NET代码。

JAVA代码:

byte[] modulusBytes = Base64.decode("xTSiS4+I/x9awUXcF66Ffw7tracsQfGCn6g6k/hGkLquHYMFTCYk4mOB5NwLwqczwvl8HkQfDShGcvrm47XHKUzA8iadWdA5n4toBECzRxiCWCHm1KEg59LUD3fxTG5ogGiNxDj9wSguCIzFdUxBYq5ot2J4iLgGu0qShml5vwk=");
byte[] exponentBytes = Base64.decode("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);

RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);

Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);

byte[] plainBytes = new String("big kitty dancing").getBytes("UTF-8");
byte[] cipherData = cipher.doFinal( plainBytes );
String encryptedString = Base64.encodeBytes(cipherData);

我使用这段JAVA代码获得了加密字符串的结果:

FoP4+AAIH6hcabXnrvNG5YUk/nBv9n9HU0CAgZjkIWQIDjbOpSwoPVBFERrZ6641x2QaoJw5yv18XAay+0WrCaSw4sveRX+hmPm5qeVUPcjoR4slsVZ/hBFJtAHj9tva4hOugWDZa9s3RVJlxkNfE+u+Kt/YKLOi2EYbH05HjeM=

现在,我要尝试使用以下.NET代码进行解密:

const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";

CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>xTSiS4+I/x9awUXcF66Ffw7tracsQfGCn6g6k/hGkLquHYMFTCYk4mOB5NwLwqczwvl8HkQfDShGcvrm47XHKUzA8iadWdA5n4toBECzRxiCWCHm1KEg59LUD3fxTG5ogGiNxDj9wSguCIzFdUxBYq5ot2J4iLgGu0qShml5vwk=</Modulus><Exponent>AQAB</Exponent><P>+lXMCEwIN/7+eMpBrq87kQppxu3jJBTwztGTfXNaPUTx+A6uqRwug5oHBbSpYXKNDNCBzVm/0VxB3bo4FJx+ZQ==</P><Q>yasOGaJaE9xlF9T2xRuKeG9ZxCiyjhYaYB/mbtL+SIbtkRLi/AxaU4g2Il/UxhxhSXArKxIzV28zktispPJx1Q==</Q><DP>ueRgQIEFUV+fY979a1RgrVHIPpqEI1URhOMH3Q59oiXCcOumM5njyIHmWQxRAzXnG+7xlKXi1PrnRll0L4oOKQ==</DP><DQ>dfEMNgG1HJhwpxdtmqkYuoakwQvsIRzcIAuIAJh1DoWaupWJGk8/JEstHb1d+t7uJrzrAi2KyT/HscH2diE0YQ==</DQ><InverseQ>YoYF9PF6FiC0YngVeaC/eqt/ea8wMYNN3YO1LuzWpcy2exPRj2U0ZbWMvHXMUb4ea2qmhZGx1QlK4ULAuWKpXQ==</InverseQ><D>g1WAWI4pEK9TA7CA2Yyy/2FzzNiu0uQCuE2TZYRNiomo96KQXpxwqAzZLw+VDXfJMypwDMAVZe/SqzSJnFEtZxjdxaEo3VLcZ1mnbIL0vS7D6iFeYutF9kF231165qGd3k2tgymNMMpY7oYKjS11Y6JqWDU0WE5hjS2X35iG6mE=</D></RSAKeyValue>");

string data2Decrypt =    "FoP4+AAIH6hcabXnrvNG5YUk/nBv9n9HU0CAgZjkIWQIDjbOpSwoPVBFERrZ6641x2QaoJw5yv18XAay+0WrCaSw4sveRX+hmPm5qeVUPcjoR4slsVZ/hBFJtAHj9tva4hOugWDZa9s3RVJlxkNfE+u+Kt/YKLOi2EYbH05HjeM=";

byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt);  

byte[] plain = rsa1.Decrypt(encyrptedBytes, false);
string decryptedString = System.Text.Encoding.UTF8.GetString(plain);

哦,我收到的错误是“坏数据”。 - badMonkey
嗨@badMonkey,我有一个问题。你从哪里得到了XML?我不理解那一部分,它有很多参数(Q、P、DP、DQ、InverseQ、D)。我的Java伙伴正在加密一个文本,而C#开发人员即我应该对其进行解密。他给了我模数和指数,我如何只使用模数和指数来解密加密字符串? - Mahdi Tahsildari
我不是非常确定哪一个是哪一个,但我非常确定这位绅士的这个漂亮的说明性视频 https://youtu.be/oOcTVTpUsPQ 解释了我在之前评论中提出的那些问题。祝你好运。 - Mahdi Tahsildari
1个回答

7
在Java端,您需要使用"RSA/ECB/PKCS1Padding"作为算法名称。使用纯粹的"RSA"名称,Java不会添加C#实现所期望的PKCS#1填充,因此会出现“坏数据”的情况。
填充是将输入数据(编码后的字符串)转换为略大于RSA模数(这里为128个字节)的字符串。它对安全性很重要,并注入了一些随机性(相同的输入字符串每次都不会产生相同的加密字符串;但解密过程会消除该随机性并恢复正确的字符串)。

在Java中,始终明确定义模式和填充,因为当您不这样做时,无法保证将使用什么。我想知道C#/.NET是否有类似的功能? - laz
Thomas,我希望在我遇到加密问题时你总是在身边!那绝对解决了问题。laz - RSACryptoServiceProvider.KeyExchangeAlgorithm 是你需要设置的属性。默认值(正如Thomas Pornin所指出的)为“RSA-PKCS1-KeyEx”。 - badMonkey
不,如果你指定Cipher.getInstance("RSA"),那么你得到的是"RSA/ECB/PKCS1Padding"。 - President James K. Polk
Greg,我没有看到那种情况。当我实现了Thomas建议的单一更改后,在.NET端数据可以成功解密。 "RSA-PKCS1-KeyEx"是.NET端的算法名称。 - badMonkey

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