Cipher.getInstance("AES") 的正确使用方法是什么?

What is the correct way to use Cipher.getInstance("AES")?

Cipher.getInstance("AES")

AndroidStudio的Lint对上面的代码报错如下:

cipher.getinstance should not be called without setting the encryption mode and padding

an SO answer 所解释的那样,上面的代码完美运行。

任何人都可以阐明如何正确使用 cipher.getinstance() 吗?

实例化 Cipher 实例时,算法、模式和填充应 始终显式 指定,例如:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

如果 指定了算法,则会应用 provider-specific 模式和填充值,请参阅 Android or Java 文档中的 Cipher。这有许多 error-prone 缺点,因此应严格避免:

  • 许多提供商使用 ECB 模式和 PKCS#5 填充作为默认值,例如Android 上的 BouncyCastle 提供商(已针对 API 级别 28 和 29 进行测试)。但是,ECB 模式不安全,因此不应应用,请参阅 Why shouldn't I use ECB encryption?。要防止使用 ECB 模式,需要 显式 指定模式。
  • Cross-platform 如果涉及具有不同模式和填充默认值的不同提供程序,则会出现问题。
  • 模式和填充的显式规范提高了可读性。

Lint 工具通过其警告指出这些问题 Cipher.getInstance should not be called without setting the encryption mode and padding。顺便说一句,当使用 AES/ECB/PKCS5Padding 指定时,Lint 报告还警告 ECB 的不安全性:不应使用 ECB 加密模式

相比之下,当使用 AES/CBC/PKCS5Padding 指定 CBC 时,不会在 Lint 中触发警告。


虽然 CBC 比 ECB 更安全,但 CBC 仅支持机密性。因此,authenticated encryption, which provides authenticity and integrity in addition to confidentiality, should be preferred, e.g. GCM. Since GCM is based on CTR, i.e. a stream cipher mode, no padding is required, unlike block cipher modes such as ECB or CBC (see Block cipher mode of operation)。因此,GCM 指定为 AES/GCM/NoPadding.

在这里您可以找到关于 CBC 和 ECB 之间区别的 post:Should I use ECB or CBC encryption mode for my block cipher? and here regarding the difference between CBC and GCM: What is the difference between CBC and GCM mode?

最后,关于 PKCS#5 填充的一点说明:Java/Android 世界中由于历史原因被称为 PKCS#5 填充的实际上是 PKCS#7 填充。您可以在此处找到有关此主题的更多详细信息:What is the difference between PKCS#5 padding and PKCS#7 padding?.