Java 卡中的 AES 密码没有填充

No padding for AES cipher in Java Card

在JavaCard 2.2.2 API中,我可以看到一些对称密码是用填充模式实现的,例如:

Cipher algorithm ALG_DES_CBC_ISO9797_M1 provides a cipher using DES in CBC mode or triple DES in outer CBC mode, and pads input data according to the ISO 9797 method 1 scheme.

但对于 AES 密码,没有可用的填充模式(ALG_AES_BLOCK_128_ECB_NOPADALG_AES_BLOCK_128_CBC_NOPAD)。

那么这个算法不支持怎么解释呢?

这些填充方法是否容易受到使用 AES 的已知攻击?

不一定 - 它仅表示此算法不会自动填充输入数据。你必须自己做(可能填充到 16 字节的倍数,因为这是 AES 需要的)。

So how explain that it's not supported for this algorithm?

我不确定,但请注意,有几种方法可以做到这一点,也许作者决定您已经选择了最适合您的填充样式。

如果您想了解更多有关填充的信息,请考虑以下示例:

您必须使用 AES 加密单词 "overflow"。 首先,您必须将其转换为字节形式,因为这是 AES 的操作依据。

ASCII 编码字符串 "overflow" 是

"6F 76 65 72 66 6C 6F 77 00"

(最后一个字节是字符串终止符,又名 [=11=] 或空字节) 不幸的是,这对于纯 AES 算法也是不够的,因为它可以对整个数据块进行 OLNY 操作——比如 16 字节数据块。 这意味着,您还需要 16-9=7 个字节的数据。因此,您将编码后的字符串填充为完整的 16 字节数据,例如使用空字节。结果是

"6F 76 65 72 66 6C 6F 77 00 00 00 00 00 00 00 00"

现在您选择加密密钥并加密数据。 解密数据后,您会再次收到

"6F 76 65 72 66 6C 6F 77 00 00 00 00 00 00 00 00"

现在问题的关键是:你怎么知道哪些字节最初在你的字符串中,哪些是填充字节? 在 en/decrypting 字符串的情况下,这非常简单,因为字符串(几乎)总是以空字节结尾,并且末尾永远不会有多个连续的空字节。所以很容易确定在哪里削减你的数据。

有关 "crypto-padding" 样式的更多信息,您可以在此处找到:https://en.wikipedia.org/wiki/Padding_%28cryptography%29#Byte_padding

是否可以使用其他填充模式取决于您使用的 Java 卡 API 以及特定 Java 卡的实现细节。

以后API的有:

由于模式和填充方法的爆炸式增长,添加了特殊的 getInstance 方法。

旧的 API 实现可能确实没有这些方法,但请再次检查可用性。


AES 本身就是一种分组密码。 CBC 等不同模式使用密码和填充 - 因此 CBC_AES_PKCS7PADDING 在某种意义上会更合乎逻辑。作为块密码,AES 因此不容易受到填充 oracle 攻击。

另一方面,CBC 容易受到填充 oracle - 和其他明文 oracle - 攻击。所以你应该保护你的 IV 和密文,例如AES-CMAC 身份验证标签,如果您需要针对这些攻击的保护。

然而,这并不是不包括填充模式的原因。不同的填充模式 are certainly present now.