将C#rsa CryptoServiceProvider代码转换为Java

将C#rsa CryptoServiceProvider代码转换为Java,java,c#,encryption,rsa,rsacryptoserviceprovider,Java,C#,Encryption,Rsa,Rsacryptoserviceprovider,我需要加密项目相关的目的字符串,并提供了以下代码相同的供应商 public static string EncryptString(string StringToEncrypt) { RSACryptoServiceProvider provider = new RSACryptoServiceProvider(); string xmlString = "<RSAKeyValue><Modulus>qqoWhMwGrrEBRr92VYud3j+iIEm7

我需要加密项目相关的目的字符串,并提供了以下代码相同的供应商

public static string EncryptString(string StringToEncrypt)
{
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
    string xmlString = "<RSAKeyValue><Modulus>qqoWhMwGrrEBRr92VYud3j+iIEm7652Fs20HvNckH3tRDJIL465TLy7Cil8VYxJre69zwny1aUAPYItybg5pSbSORmP+hMp6Jhs+mg3qRPvHfNIl23zynb4kAi4Mx/yEkGwsa6L946lZKY8f9UjDkLJY7yXevMML1LT+h/a0a38=</Modulus><Exponent>AQAB</Exponent><P>20PwC7nSsfrfA9pzwSOnRYdbhOYivFSuERxvXHvNjCll5XdmFYYp1d2evXcXbyj3E1k8azce1avQ9njH85NMNQ==</P><Q>x0G0lWcQ13NDhEcWbA7R2W5LPUmRqcjQXo8qFIaHk7LZ7ps9fAk/kOxaCR6hvfczgut1xSpXv6rnQ5IGvxaHYw==</Q><DP>lyybF2qSEvYVxvFZt8MeM/jkJ5gIQPLdZJzHRutwx39PastMjfCHbZW0OYsflBuZZjSzTHSfhNBGbXjO22gmNQ==</DP><DQ>NJVLYa4MTL83Tx4vdZ7HlFi99FOI5ESBcKLZWQdTmg+14XkIVcZfBxDIheWWi3pEFsWqk7ij5Ynlc/iCXUVFvw==</DQ><InverseQ>X5Aw9YSQLSfTSXEykTt7QZe6SUA0QwGph3mUae6A2SaSTmIZTcmSUsJwhL7PLNZKbMKSWXfWoemj0EVUpZbZ3Q==</InverseQ><D>jQL4lEUYCGNMUK6GEezIRgiB5vfFg8ql3DjsOcXxnOmBcEeD913kcYnLSBWEUFW55Xp0xW/RXOOHURgnNnRF3Ty5UR73jPN3/8QgMSxV8OXFo3+QvX+KHNHzf2cjKQDVObJTKxHsHKy+L2qjfULA4e+1cSDNn5zIln2ov51Ou3E=</D></RSAKeyValue>";
    provider.FromXmlString(xmlString);
    return Convert.ToBase64String(provider.Encrypt(Encoding.ASCII.GetBytes(StringToEncrypt), false));
}
但样本结果不匹配

字符串为“4111111111”,加密结果应为:

PfU31ai9dSwWX4Im19TlikfO9JetkJbUE+BTUVPBUNHTNFRT4XDM4PMGA19Z8RF+lPUC/KCOEXCIUXCFRAPYURJHIFIDQWFBBJVPHATBF269BXUIAW31UBX5BBOKNWJH4LDITY0BTARLTU4XDM4PMGA19Z8RF+lPUC/KCOEXCIUXCFRAPYURJHIFIDQWFBBJVPHATBF269BXU1UBX5BX5BX5BX5=

但是Java代码的结果是

Cxp5AIzTHEkrU6YWwYo5yYvpED2qg9IC/0ct+tRgDZi9fJb8LAk+E1l9ljEt7MFQ2KB/ExonyWIJNBKypelstxyFVO1BJ6S76ZmekygaltdukQ1UHJAJKACxy94WI9KEL09VTMJ+VbyYAGUFQZGAK1CYLND8QXMCDCWI3SA=


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

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

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

查看您的代码,这两种方法似乎是等效的,因为
false
作为第二个参数传递到
rsacyptoserviceprovider#Encrypt
以使用PKCS#1 v1.5填充,而
Cipher.getInstance(“RSA/ECB/pkcs1ppadding”)
请求相同的填充。输入/输出编码似乎也相当。所以,是的,这个代码是等效的



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

如果再次运行C#和Java代码,会发生什么情况?密文会变吗?如果是这样,则使用随机填充(很重要),您需要在其中一个中加密,在另一个中解密以检查兼容性。谢谢@ArtjomB。我刚刚检查了与供应商解密代码的兼容性,它工作正常。@ArtjomB。对于加密,必须使用随机填充。加密必须是非确定性的,否则您将获得相同明文的相同密文(实际上与对称ECB模式加密相同)。只有教科书上的RSA是确定性的,并且由于各种原因都非常不安全。但签名生成可能是确定性的。你能给出答案吗?@MaartenBodewes PKCS#1 v1.5 1型填充不是随机的。实际使用的可能性很小,但它仍然存在。@ArtjomB。抢手货我还没有在实践中看到过,但我会确保它不会出现在后续问题中。嗨,我在问题中面临着同样的情况。如果使用随机填充,如何检查用户输入的密码是否与数据库中的密码相同,而不解密数据库中的密码?因为我听说解密密码不是一个好的做法。我们只检查两个加密值是否相同。然而,在这里我不明白我怎么能做到这一点。唯一的办法似乎是从db解密密码。@nanospeck您永远不应该加密用户的密码。您需要使用散列,而一些强散列是PBKDF2、bcrypt、scrypt和Argon2。由于散列函数是单向函数,因此无法“解密”散列。为了对用户进行身份验证,您可以再次通过哈希函数运行密码,以便与存储在数据库中的哈希进行比较。更多信息:RSA绝对不是这个工作的合适工具。你的话在这个话题上对我真的很有帮助。不幸的是,我正在使用RSACryptServiceProvider将一个已经在.NET中实现的项目移植到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;
}