如果密码编码失败,重试也将失败



假设你有一些字符串,你想用你的公钥加密,然后dectrypt,它们彼此不相关。但是其中一个不符合条件(它比关键位长度可以处理的长(,并且您想抛出错误并继续解码其他错误。

好吧,问题是如果抛出Data must not be longer than x bytes异常,那么下一个异常也将失败

为什么会发生这种情况,我怎样才能防止它发生?

我制作了一个不言自明的代码,可用于重现错误:

Cipher encrypter;
Cipher decrypter;
Key pubKey;
Key privKey;
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
pubKey = kp.getPublic();
privKey = kp.getPrivate();
encrypter = Cipher.getInstance("RSA");
encrypter.init(Cipher.ENCRYPT_MODE, pubKey);
decrypter = Cipher.getInstance("RSA");
decrypter.init(Cipher.DECRYPT_MODE, privKey);
byte[] encryptedData;
byte[] decryptedData;

System.out.println("Starting short test 1");
encryptedData = encrypter.doFinal("SHORT TEST 1".getBytes());
decryptedData = decrypter.doFinal(encryptedData);
System.out.println(new String(decryptedData)); //SHORT TEST
System.out.println("Starting short test 2");
encryptedData = encrypter.doFinal("SHORT TEST 2".getBytes());
decryptedData = decrypter.doFinal(encryptedData);
System.out.println(new String(decryptedData)); //SHORT TEST 2
System.out.println("Starting short test 3");
encryptedData = encrypter.doFinal("SHORT TEST 3".getBytes());
decryptedData = decrypter.doFinal(encryptedData);
System.out.println(new String(decryptedData)); //SHORT TEST 3
try {
encryptedData = encrypter.doFinal(("LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST" +
" LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST" +
" LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST LONG TEST ").getBytes());
decryptedData = decrypter.doFinal(encryptedData);
System.out.println(new String(decryptedData)); // IT DOESN'T REACH HERE, WHICH IS OK
} catch (IllegalBlockSizeException e){
System.out.println(e.toString());  // Data must not be longer than 117 bytes (OK, fair enough, my bad)
}
System.out.println("Starting short test 4");
encryptedData = encrypter.doFinal("SHORT TEST 4".getBytes());
decryptedData = decrypter.doFinal(encryptedData);
System.out.println(new String(decryptedData)); // THROWS THE SAME EXCEPTION THAN IN PREVIOUS TEST

控制台打印:

Starting short test 1
SHORT TEST 1
Starting short test 2
SHORT TEST 2
Starting short test 3
SHORT TEST 3
javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes
Starting short test 4
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes
at java.base/com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:347)
at java.base/com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:392)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2202)
at main.main(main.java:66)

doFinal(( 文档指出:

注意:如果抛出任何异常,则可能需要此密码对象 在再次使用之前重置。

由于没有reset方法,我假设您必须再次调用init

m0skit0 相当直接的答案当然没问题,但需要考虑一些事情。


应尽可能避免异常(在已发布的代码中(。重新加密相同的消息将不起作用,因为您将获得相同的异常,因此对于该特定消息,您将没有选择。如果您使用混合加密(下一点(,那么您可以轻松避免此问题。


RSA 不是用来传输大量数据的。了解如何将 AES/GCM 和 RSA/OAEP 结合起来,以创建可以高效加密/解密任意数量数据的混合密码系统


Cipher类的实例通常是轻量级的。它们的实例化和初始化相对便宜,并且不携带太多状态因此,简单地生成一个新实例比重用旧实例更不容易出错。

这意味着,例如,您应该将存储在类的字段中,而不是Cipher实例本身。由于键是不可变的,这意味着无论Cipher实例发生什么情况,类的状态都保持有效。


关于代码/密码学:

kpg.initialize(1024);

这不再被认为是足够好的密钥大小。尝试 3072 或更高版本。或者选择椭圆曲线加密(ECC(。

encrypter = Cipher.getInstance("RSA");

永远不要忘记指定完整的算法,不要使用默认值。上述用途"RSA/ECB/PKCS1Padding"但OAEP应该是首选(但开销更大(。


String.getBytes()new String(byte[]):始终指定StandardCharsets中的字符集,除非您绑定到平台默认编码(以及另一个平台上的后续解码错误(。

相关内容

  • 没有找到相关文章

最新更新