在没有填充的情况下检测AES中的错误密钥

时间:2015-12-08 13:17:30

标签: java encryption cryptography

如果使用AES/ECB/PKCS5Padding,则在尝试使用错误的密钥解密消息时会出现BadPaddingException。但是在使用AES/ECB/NoPadding时没有例外 - 消息被成功解密为某些错误的数据。

在没有使用填充的情况下,有没有办法在AES解密期间检测错误的密钥?

编辑: 我正在与加密设置为AES/ECB/NoPadding的设备进行通信。我想我无法改变这一点。

1 个答案:

答案 0 :(得分:4)

用于完整性检测的填充

PKCS#5填充将成功解密,概率略大于2 -8 。你尝试的每256个随机密钥都会给你一个错误的明文而不会抛出异常 1 。检查填充是必要的,但这不是确定密钥是否正确的好方法。

ANSI X.923填充的数字相同,但ISO 10126填充不同。填充最多是一个完整的块,至少是一个字节,因此ISO10126Padding的有效值为0x01到0x10。由于它是随机的,因此只使用了最后一个填充字节,因此大约16 / 256~6%的错误密钥不会引发异常。

用于密钥检查的分组密码

在尝试解密完整密文之前检查密钥有效性的方法是通过发送密钥检查值(KCV)和密文。

这只是用密钥加密完整的零填充块。由于AES之类的分组密码(目前)不易受到已知明文攻击的密钥恢复的影响,因此这应该是检查有效密钥的好方法。

用于密钥检查的哈希函数

您可以使用HMAC检查密钥完整性。伪代码:

byte[] salt = generateRandomByteArray(16);
byte[] keyTag = hmacSha256(key, salt);
return keyTag + salt + encrypt(data, key);

在接收器端,您可以读取盐,通过HMAC运行密钥和盐,并与收到的keyTag进行比较。但这只会检查密钥是否正确。你真的应该检查密钥和密文的整个组合是否正确。

验证密文

此属性称为经过身份验证的加密,可以通过在密文上运行密钥HMAC来创建身份验证标记来实现。然后,您需要通过HKDF(伪代码)生成两个密钥:

byte[] keyEnc = hkdf(key, "Encryption");
byte[] keyMac = hkdf(key, "MAC");
byte[] ciphertext = encrypt(data, keyEnc);
byte[] authTag = hmacSha256(keyMac, ciphertext);
return ciphertext + authTag;

在最基本的形式中,HKDF只是对HMAC的双重调用。使用GCM或EAX等经过身份验证的模式可能更容易。

检查密钥有效性的其他方法

如果您无法在当前加密过程中添加任何内容,则仍有一些概率方法可以确定密钥是否正确。主要思想是必须检查恢复的明文是否有意义。

例如,如果您的真正纯文本是某些文本,那么您可以检查解密的纯文本是否仅包含ASCII中可用的字符,或者如果您加密了UTF-8,则可以检查它是否实际上正确解码了它。如果原始明文是某些JSON,那么您可以运行JSON验证器来检查您是否获得了有效的JSON,并相对确定是否应用了正确的密钥。

请记住,攻击者可能仍会篡改密文以生成正确验证的相关明文。成功率在很大程度上取决于明文的结构。

1 当你有随机密钥时,那么卸载之前解密明文的最后一个字节是0x01字节的机会是256 in 1,这是一个有效的填充,无论它在它之前是什么。你有一个256 * 256的机会在最后两个字节中得到一个0x0202,这也是一个有效的填充。

请不要使用ECB模式。它不是特别安全,因为它不提供语义安全性。你应该至少使用随机生成的IV的CBC模式。

实施:HMAC-SHA256AES-GCM
参考文献:HKDF