[英]Handling Java crypto exceptions
在 Java 中处理加密/解密时,这段非常基本的代码非常常见。
final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
cipher.doFinal(*something*);
仅这三行,可能会引发六个异常,我不确定处理它们的最干净(就代码可读性而言)的方法是什么。 尝试使用六个 catch 子句对我来说真的很香。
在使用此类对象时,是否存在我显然遗漏的微模式或最佳实践?
编辑
对不起,我想我没有很好地解释自己。 我的问题并不是要避免使用 try\catch 子句,而是是否有处理类似情况的通用方法。
加密例外是
NoSuchPaddingException, NoSuchAlgorithmException
InvalidAlgorithmParameterException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException
您指出了以下例外情况:
NoSuchPaddingException, NoSuchAlgorithmException
InvalidAlgorithmParameterException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException
现在所有这些都是GeneralSecurityException
,所以很容易抓住它们。 但是看看用例,您可能不想这样做。
如果您查看异常的原因,您会发现这些异常中的任何一个(最后两个除外)仅在生成算法或密钥的实现时才被抛出。 我认为,一旦您测试了您的应用程序,这些值或多或少保持不变是合理的。 因此,抛出 - 例如 - IllegalStateException
是合乎逻辑的。 IllegalStateException
是一个运行时异常,您不需要抛出(在方法签名中)或捕获。 当然,您应该将安全异常作为异常的原因包括在内。
现在最后两个异常BadPaddingException
和IllegalBlockSizeException
是不同的。 它们依赖于实际的密文,因此它们依赖于算法的输入。 现在通常您应该始终在将输入输入到您的Cipher
实例之前验证输入的完整性,启动解密,例如通过首先验证 HMAC 校验和)。 因此,从这个意义上说,您仍然可以摆脱运行时异常。 如果您不执行单独的完整性检查,那么您不应该转换为RuntimeException
。 相反,您可以让用户处理异常,或者将其作为特定于用例的异常重新抛出。
如果您通过(重新)抛出BadPaddingException
来处理它,那么应该了解明文 oracle 攻击,例如 padding oracle 攻击。 对于 CBC 模式下的 padding oracle 攻击:如果对手可以尝试让您多次解密密文并收到解密失败(或失败)的指示,那么他们可以在不破坏密码的情况下检索消息的明文。 出于这个原因,在可以处理身份验证标签的 16 个附加字节的情况下,应该首选 GCM 模式等身份验证模式。
最好使用单独的try
/ catch
块来构造和初始化Cipher
以及解密本身。 您还可以在处理GeneralSecurityException
之前捕获异常BadPaddingException
和IllegalBlockSizeException
。 从 Java 7 开始,您也可以使用 multi-catch 语句(例如catch(final BadPaddingException | IllegalBlockSizeException e)
)。
最后一些注意事项:
BadPaddingException
和IllegalBlockSizeException
可能是Cipher
抛出的,因为数据没有完全接收到,但也可能是因为攻击者弄乱了数据;BadPaddingException
。如果您愿意失去一些细节,所有 Crypto 异常都扩展GeneralSecurityException ,您可以抓住它。
处理这个问题的最好方法是创建一个业务异常(MyModuleException 或其他东西),然后重新抛出该异常,添加 Crypto 异常以导致部分。 这样,您的方法将只抛出一个异常,而不是六个,这在应用程序的其他层中会更容易管理。
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.