2011-01-21 45 views
0

我一直遇到与RSA公钥加密问题。以下是重现问题的示例JUnit代码:Java RSA加密不可重复?

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加密,那么为什么我没有发生异常?

我必须做些什么才能获得可重复的结果?

P.S.我的JDK是1.6.0_22,在Ubuntu 10.10上运行。

+0

P.S.我使用了BouncyCastle提供程序,现在我的测试成功了。 – malaverdiere 2011-01-21 12:09:18

+0

测试成功是一个非常糟糕的迹象,因为RSA加密应该*随机化。使用RSA加密使用OEAP填充是非常重要的。教科书RSA和PKCS#1 v1.5填充都不安全。 – CodesInChaos 2013-01-09 11:41:39

回答

7

我的猜想是它应用随机填充,正是为了使它更安全。从RSA wikipedia page

因为RSA加密是一个确定性的加密算法 - 即没有随机成分 - 攻击者能够成功发动针对加密方式的选择明文攻击,通过公钥和测试,如果在加密可能明文它们等于密文。如果攻击者知道(或已经选择)相应的明文,则攻击者无法区分两种加密,所以称为语义安全。如上所述,没有填充的RSA在语义上是不安全的。

...

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

+0

(+1)快一分钟,比我更好解释 – Ralph 2011-01-21 11:42:49

1

您可以确认发生的事情是通过用字符串“RSA/ECB/NoPadding”初始化密码来添加随机填充。现在,您应该看到密文在每种情况下都是相同的(尽管由于另一个回答者陈述的原因,您在实践中不应该这样做)。

0

额外的细节添加到乔恩的答案:

当你做你Cipher.getInstance("...")有很多的选择,因为你可能已经聚集。 The Standard Algorithm Names指定这些是什么。

你问的一个,RSA是默认RSA PKCS1,其中,引用维基百科的文章下:

有加密 和解密两种方案:

  • RSAES- OAEP:改进的加密/解密方案;基于 的最优非对称加密 由Mihir提出的填充方案 Bellare和Phillip Rogaway。
  • RSAES-PKCS1-v1_5:较早的加密/解密方案,作为PKCS#1版本1.5中标准化的第一个 。

见RSALab的PKCS1 documentation为的详细说填充方案。