我一直无法使用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加密,那么为什么我没有得到例外?
我该怎样做才能获得可重复的结果?
P.S。我的JDK是在Ubuntu 10.10盒子上运行的1.6.0_22。
答案 0 :(得分:7)
我的猜测是它正在应用随机填充,正是为了使其更安全。来自RSA wikipedia page:
由于RSA加密是一种确定性加密算法 - 即没有随机组件 - 攻击者可以通过加密公钥下的可能明文并测试它们是否等于密文,成功启动对密码系统的选定明文攻击。如果攻击者无法区分两个加密,即使攻击者知道(或已选择)相应的明文,也称为密码系统在语义上是安全的。如上所述,没有填充的RSA在语义上不安全。
...
为了避免这些问题,实际的RSA实现通常在加密之前将某种形式的结构化随机填充嵌入到值m中。这个填充确保m不会落入不安全的明文范围内,并且一旦填充,给定的消息将加密到大量不同的可能密文中的一个。
答案 1 :(得分:1)
您可以通过使用字符串“RSA / ECB / NoPadding”初始化您的密码来确认正在发生的事情是添加了随机填充。现在,您应该看到密文在每种情况下都是相同的(尽管出于另一个回答者所说的原因,您实际上不应该在实践中这样做。)
答案 2 :(得分:0)
为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。