Java RSA加密不可重复?

Java RSA加密不可重复?,java,cryptography,rsa,Java,Cryptography,Rsa,我用RSA公钥加密时遇到问题。下面是重现问题的JUnit代码示例: public class CryptoTests { private static KeyPair keys; @BeforeClass public static void init() throws NoSuchAlgorithmException{ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); SecureRandom ra

我用RSA公钥加密时遇到问题。下面是重现问题的JUnit代码示例:

public class CryptoTests {

private static KeyPair keys;

@BeforeClass
public static void init() throws NoSuchAlgorithmException{
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    SecureRandom random = CryptoUtils.getSecureRandom();
    keyGen.initialize(2176, random);
    keys = keyGen.generateKeyPair();
}
@Test
public void testRepeatabilityPlainRSAPublic() throws EdrmCryptoException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
    byte[] plaintext = new byte [10];
    Random r = new Random();
    r.nextBytes(plaintext);

    Cipher rsa = Cipher.getInstance("RSA");
    rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
    byte[] encrypted1 =  rsa.doFinal(plaintext);

    rsa = Cipher.getInstance("RSA");
    rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
    byte[] encrypted2 =  rsa.doFinal(plaintext);

    rsa = Cipher.getInstance("RSA");
    rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
    byte[] encrypted3 =  rsa.doFinal(plaintext);

    assertArrayEquals(encrypted1, encrypted2);
    assertArrayEquals(encrypted1, encrypted3);
}
}
结果如何?断言失败了

为什么会出现这种行为?根据我的加密类的记忆,任何密钥都可以用于加密。然而,这并不是这里发生的事情。 我用私钥测试了同样的东西,得到了一个可重复的输出

如果出于某种原因,使用公钥的RSA加密被禁止,那么为什么我没有得到异常

我必须做什么才能得到可重复的结果

另外,我的JDK是1.6.0_22,运行在Ubuntu10.10机器上。

我猜它正在应用随机填充,正是为了让它更安全。从:

由于RSA加密是一种确定性加密算法,即没有随机组件,攻击者可以通过加密公钥下可能的明文并测试它们是否等于密文,成功地对密码系统发起选定的明文攻击。如果攻击者即使知道或选择了相应的明文,也无法区分两种加密,则称密码系统为语义安全。如上所述,没有填充的RSA在语义上是不安全的

为了避免这些问题,实际的RSA实现通常会在加密值m之前将某种形式的结构化随机填充嵌入其中。这种填充确保m不属于不安全的明文范围,并且给定的消息一旦填充,将加密为大量可能的密文之一


您可以通过使用字符串RSA/ECB/NoPadding初始化密码来确认正在添加随机填充。现在,您应该看到,密文在每种情况下都是相同的,尽管出于另一位回答者所述的原因,您实际上不应该这样做。

要在Jon的回答中添加额外的细节:

当您执行Cipher.getInstance时。。。正如您可能已经收集到的,您有许多选择。指定这些是什么

您要求的RSA默认为RSA,引用wikipedia文章:

有两种加密方案 和解密:

RSAES-OAEP:改进的加密/解密方案;基于 最优非对称加密 Mihir提出的填充方案 贝拉尔和菲利普·罗格威。 RSAES-PKCS1-v1_5:旧的加密/解密方案作为第一个 在PKCS1的1.5版中标准化。
有关上述填充方案的详细信息,请参见RSALab。

+1比meYes快一分钟,而且解释得更好-真正重要的是它是否解密为相同的原始明文。p.s。我使用了BouncyCastle提供程序,现在我的测试成功了。测试成功是一个非常糟糕的迹象,因为RSA加密应该是随机的。必须将OEAP填充与RSA加密结合使用。教科书中的RSA和PKCS1 v1.5填充都不安全。需要强调的是,RSAES-PKCS1-v1_5允许实际攻击,因此不应使用它。RSAES-OAEP是一条路要走。