将C#RSACryptoServiceProvider代码转换为Java

我需要为项目相关的目的加密String,并由供应商给出相同的代码。

public static string EncryptString(string StringToEncrypt) { RSACryptoServiceProvider provider = new RSACryptoServiceProvider(); string xmlString = "qqoWhMwGrrEBRr92VYud3j+iIEm7652Fs20HvNckH3tRDJIL465TLy7Cil8VYxJre69zwny1aUAPYItybg5pSbSORmP+hMp6Jhs+mg3qRPvHfNIl23zynb4kAi4Mx/yEkGwsa6L946lZKY8f9UjDkLJY7yXevMML1LT+h/a0a38=AQAB

20PwC7nSsfrfA9pzwSOnRYdbhOYivFSuERxvXHvNjCll5XdmFYYp1d2evXcXbyj3E1k8azce1avQ9njH85NMNQ==

x0G0lWcQ13NDhEcWbA7R2W5LPUmRqcjQXo8qFIaHk7LZ7ps9fAk/kOxaCR6hvfczgut1xSpXv6rnQ5IGvxaHYw==lyybF2qSEvYVxvFZt8MeM/jkJ5gIQPLdZJzHRutwx39PastMjfCHbZW0OYsflBuZZjSzTHSfhNBGbXjO22gmNQ==NJVLYa4MTL83Tx4vdZ7HlFi99FOI5ESBcKLZWQdTmg+14XkIVcZfBxDIheWWi3pEFsWqk7ij5Ynlc/iCXUVFvw==X5Aw9YSQLSfTSXEykTt7QZe6SUA0QwGph3mUae6A2SaSTmIZTcmSUsJwhL7PLNZKbMKSWXfWoemj0EVUpZbZ3Q==jQL4lEUYCGNMUK6GEezIRgiB5vfFg8ql3DjsOcXxnOmBcEeD913kcYnLSBWEUFW55Xp0xW/RXOOHURgnNnRF3Ty5UR73jPN3/8QgMSxV8OXFo3+QvX+KHNHzf2cjKQDVObJTKxHsHKy+L2qjfULA4e+1cSDNn5zIln2ov51Ou3E="; provider.FromXmlString(xmlString); return Convert.ToBase64String(provider.Encrypt(Encoding.ASCII.GetBytes(StringToEncrypt), false)); }

但是我需要修改或翻译成JAVA。 为了同样的目的,我写了下面的方法。

 public static String EncryptString(String strToBeEncrypted) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException { String modulusString = "qqoWhMwGrrEBRr92VYud3j+iIEm7652Fs20HvNckH3tRDJIL465TLy7Cil8VYxJre69zwny1aUAPYItybg5pSbSORmP+hMp6Jhs+mg3qRPvHfNIl23zynb4kAi4Mx/yEkGwsa6L946lZKY8f9UjDkLJY7yXevMML1LT+h/a0a38="; 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 = strToBeEncrypted.getBytes("US-ASCII"); byte[] cipherData = cipher.doFinal(plainBytes); String encryptedStringBase64 = Base64.encodeBase64String(cipherData); return encryptedStringBase64; } 

但样本结果不匹配。

字符串是“4111111111111111”,加密结果应该是:

PfU31ai9dSwWX4Im19TlikfO9JetkJbUE + btuvpBuNHTnnfrt4XdM4PmGA19z8rF + lPUC / kcOEXciUSxFrAPyuRJHifIDqWFbbJvPhatbf269BXUiAW31UBX3X5bBOqNWjh4LDitYY0BtarlTU4xzOFyb7vLpLJe9aHGWhzs6q0 =

但是Java代码的结果是

Cxp5AIzTHEkrU6YWwYo5yYvpED2qg9IC / 0CT + tRgDZi9fJb8LAk + E1l9ljEt7MFQ2KB / exo4NYwijnBKYPeLStXyfVO1Bj6S76zMeKygAlCtDukq1UhJaJKaCXY94wi9Kel09VTmj + VByIYvAGUFqZGaK1CyLnd8QXMcdcWi3sA =

每个加密算法都需要随机化以提供语义安全性。 否则,攻击者可能会注意到您已经通过观察密文再次发送了相同的消息。 在对称密码中,这个属性是通过随机IV实现的。 在RSA中,这通过随机填充(PKCS#1 v1.5类型2和PKCS#1 v2.x OAEP随机化)来实现。

您可以通过使用相同的密钥和明文再次运行加密来检查填充是否随机化,并将密文与先前的密文进行比较。 如果执行之间的密文在C#或Java中发生变化,那么仅通过查看密文就无法判断加密是否兼容。

检查这个的正确方法是用一种语言加密某些东西,然后在另一种语言中解密。 为了完全兼容,您还应该尝试相反的方式。

查看代码,两者看起来都是等价的,因为false作为第二个参数传递到RSACryptoServiceProvider#Encrypt以使用PKCS#1 v1.5填充,而Cipher.getInstance("RSA/ECB/PKCS1PADDING")请求相同的填充。 输入/输出编码似乎也是等价的。 所以,是的,这段代码将是等效的。


现在不应该使用PKCS#1 v1.5填充,因为它很容易受到Bleichenbacher攻击( 参考 )。 您应该使用OAEP进行加密,使用PSS进行签名,这些都被认为是安全的。 C#和Java都支持OAEP,但是使用的默认哈希函数(哈希和MGF1)可能存在差异。