处理加密exception
在Java中处理加密\解密时,这个非常基本的代码段很常见。
final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key, iv); cipher.doFinal(*something*);
仅这三行,可能会抛出六个exception,我不确定处理它们的最干净(在代码可读性方面)是什么。 尝试六个catch子句对我来说真的很像。
在使用这些物体时,是否有微图案或最佳实践,我显然是缺失的?
编辑
对不起,我想我没有很好地解释自己。 我的问题不是关于避免try \ catch子句,而是如果有一种常见的方法来处理类似的情况。
例外情况是
NoSuchPaddingException, NoSuchAlgorithmException InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException
您指出了以下例外情况:
NoSuchPaddingException, NoSuchAlgorithmException InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException
现在所有这些都是GeneralSecurityException
,因此很容易捕获它们。 但是看一下用例,你可能不想这样做。
如果查看exception的原因,那么您将发现除了最后两个exception之外的任何exception仅在生成算法或密钥的实现时抛出。 我认为,一旦您测试了应用程序,这些值或多或少是静态的,这是合理的。 因此,抛出 – 例如 – IllegalStateException
是合乎逻辑的。 IllegalStateException
是一个运行时exception,您不需要抛出或捕获它。 当然,您应该将安全exception指示为exception的原因 。
现在最后两个exception, BadPaddingException
和IllegalBlockSizeException
是不同的。 它们取决于实际的密文,因此它们取决于算法的输入。 现在,通常您应该在将输入提供给Cipher
实例之前validation输入的完整性,然后启动解密,例如首先validationHMAC校验和。 所以从这个意义上说,你仍然可以逃避运行时exception。
如果不检查完整性,则应该对exception执行不同的操作,例如将其重新抛出为(不同的?)已检查exception。 如果你采取这条路线,你应该了解填充oracle攻击; 如果攻击者可以多次尝试和解密密文,并且可以发现填充是否正确,那么消息的机密性就会丢失。
最好使用单独的try
/ catch
块来构造和初始化Cipher
以及解密本身。 在处理GeneralSecurityException
之前,您还可以捕获exceptionBadPaddingException
和IllegalBlockSizeException
。 从Java 7开始,您也可以使用多捕获语句(例如catch(final BadPaddingException | IllegalBlockSizeException e)
)。
最后一些说明:
- 请注意,如果未安装无限加密文件,则可能会因为AES密钥大小为192位和256位而抛出exception(有关详细信息,请查看Oracle JavaSE站点 ); 您应该检查应用程序启动时是否允许密钥大小;
-
BadPaddingException
和IllegalBlockSizeException
可能因为攻击或因为数据不完整而被创建; - 如果密钥不正确,也可能抛出
BadPaddingException
。
如果您愿意丢失一些特定内容,所有Cryptoexception都会扩展GeneralSecurityException ,您可以将其捕获。
处理它的最好方法是创建一个bussinesexception(MyModuleException或其他),然后重新抛出该exception,添加Cryptoexception以导致部分。 这样,您的方法只会抛出一个exception,而不是六个exception,在应用程序的其他层中更容易管理。
public void myMethod(...) throws MyModuleException { try { final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key, iv); cipher.doFinal(*something*); } catch(Crypto1Ex ex){ throw new MyModuleException("something is wrong", ex); //ex added, so it is not lost and visible in stacktraceses } catch(Crypto1Ex ex){ throw new MyModuleException("something is wrong", ex); } //etc. }
在Java 7中,您可以更轻松地处理它(请参阅: http : //docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html )