在 JAVA 中使用 AES/GCM 检测不正确的密钥

Posted

技术标签:

【中文标题】在 JAVA 中使用 AES/GCM 检测不正确的密钥【英文标题】:Detecting incorrect key using AES/GCM in JAVA 【发布时间】:2012-08-27 00:48:03 【问题描述】:

我正在使用 AES 使用 BouncyCastle 在 GCM 模式下加密/解密一些文件。 虽然我证明了错误的解密密钥,但也不例外。 我应该如何检查密钥是否不正确? 我的代码是这样的:

    SecretKeySpec   incorrectKey = new SecretKeySpec(keyBytes, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
    Cipher          cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
    byte[] block = new byte[1048576];
    int i;

    cipher.init(Cipher.DECRYPT_MODE, incorrectKey, ivSpec);

    BufferedInputStream fis=new BufferedInputStream(new ProgressMonitorInputStream(null,"Decrypting ...",new FileInputStream("file.enc")));
    BufferedOutputStream ro=new BufferedOutputStream(new FileOutputStream("file_org"));        
    CipherOutputStream dcOut = new CipherOutputStream(ro, cipher);

    while ((i = fis.read(block)) != -1) 
        dcOut.write(block, 0, i);
    

    dcOut.close();
    fis.close();

谢谢

【问题讨论】:

如果您能接受更多答案并跟进您的问题 4r1y4n(我想那将是 Ariyan),那就太好了 您不接受加密问题 4r1y4n 的答案是否有特定原因,或者它们只是逃避了您的注意?您没有连续接受任何 4 个。 请注意:Java 7 中的 AEAD 模式与 CipherInputStream 组合不受完整性保护:github.com/binwiederhier/syncany/issues/… 对我来说,CipherInputStream 在 Java 8u25 中工作。我在 Oracle 的发行说明中找不到他们对 CipherInputStream 进行了更新。 【参考方案1】:

没有任何方法可以在 GCM 模式下检测到不正确的键。您可以检查的是身份验证标签是否有效,这意味着您使用了正确的密钥。问题是,如果身份验证标签不正确,那么这可能表明以下各项(或所有内容的组合,直至并包括完全替换密文和身份验证标签):

    使用了不正确的密钥; 计数器模式加密数据在传输过程中被更改; 其他经过身份验证的数据已更改; 身份验证标签本身在传输过程中被更改。

您可以做的是发送额外的数据来识别所使用的密钥。这可能是一个可读的标识符 ("encryption-key-1"),但它也可能是一个 KCV,一个密钥检查值。 KCV 通常由使用密钥加密的零块或密钥上的加密安全哈希(也称为指纹)组成。因为零块上的加密会泄漏信息,所以您不应该使用它来识别加密密钥。

您实际上可以使用 GCM 模式的 AAD 功能来计算密钥标识数据上的身份验证标签。请注意,您无法区分指纹泄露和使用不正确的密钥。但是指纹被意外损坏的可能性比IV、AAD、密文和认证标签的整个结构要小。

【讨论】:

【参考方案2】:

您正在使用NoPadding。将其更改为 PKCS7Padding 以进行加密和解密。如果使用了错误的密钥,那么填充几乎肯定无法按预期解密,并且会抛出 InvalidCipherTextException

【讨论】:

1) GCM 是一种流模式,因此不需要填充 2) 依靠填充进行完整性检查是一个非常糟糕的主意。您很可能会以这种方式向填充预言家敞开心扉。 3) GCM 有一个集成的 MAC,它已经处理了您需要的任何完整性检查。 问题是关于识别不正确的密钥,而不是完整性检查。对于该特定问题,使用填充很好。你对 GCM 的看法是正确的,我的错。 非常罕见的失传玫瑰,我相信我会赚更多。你介意我把它放在我的罕见失误收藏中吗? :)

以上是关于在 JAVA 中使用 AES/GCM 检测不正确的密钥的主要内容,如果未能解决你的问题,请参考以下文章

Java AES/GCM/NoPadding 加密在 doFinal 之后不会增加 IV 的计数器

使用 Java 8u20 进行慢速 AES GCM 加密和解密

使用 C# 与 PHP 的 AES GCM 加密

PKCS5Padding 可以处于 AES/GCM 模式吗?

AES GCM加密模式的初始向量IV怎么确定

JOSEException:无法创建 AES/GCM/NoPadding 密码:非法密钥大小