【问题标题】:Java RSA Encryption Non-Repeatable?Java RSA加密不可重复?
【发布时间】:2011-01-21 11:34:27
【问题描述】:

我在使用 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,在 Ubuntu 10.10 机器上运行。

【问题讨论】:

  • P.S.我使用了 BouncyCastle 提供程序,现在我的测试成功了。
  • 测试成功是一个非常糟糕的信号,因为 RSA 加密应该是随机的。必须将 OEAP 填充与 RSA 加密一起使用。教科书 RSA 和 PKCS#1 v1.5 填充都不安全。

标签: java cryptography rsa


【解决方案1】:

我的猜测是它正在应用随机填充,正是为了使其更安全。来自RSA wikipedia page

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

...

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

【讨论】:

  • (+1) 比我快一分钟,而且解释得更好
  • 是的——真正重要的是它是否解密为相同的原始明文。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    为 Jon 的回答添加额外的细节:

    当您使用Cipher.getInstance("...") 时,您有很多选择,正如您可能已经收集到的那样。 The Standard Algorithm Names 指定这些是什么。

    您要求的RSA 默认是PKCS1 下的RSA,引用维基百科文章:

    有两种加密方案 和解密:

    • RSAES-OAEP:改进的加密/解密方案;基于 最优非对称加密 Mihir 提出的填充方案 Bellare 和 Phillip Rogaway。
    • RSAES-PKCS1-v1_5:旧的加密/解密方案优先 在 PKCS#1 的 1.5 版中标准化。

    请参阅 RSALab 的 PKCS1 documentation 了解上述填充方案的详细信息。

    【讨论】:

    • 需要强调的是,RSAES-PKCS1-v1_5 允许实际攻击,因此不应使用RSAES-OAEP 是要走的路。
    猜你喜欢
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 2016-10-14
    • 2014-07-12
    相关资源
    最近更新 更多