如何计算 AES-128-CBC 的密钥校验值?

How do I calculate a key check value for AES-128-CBC?

我正在尝试在 Java 中实现一个函数来计算 128 位 AES 加密密钥的密钥校验值。 AES128CBCEncryptor class 正在使用 ISO 9797-1 M2 填充实现 AES/128/CBC。

我能找到的关于 AES 密钥校验值算法的唯一信息是“AES 密钥的 KCV 是通过加密 16 个字节计算的,每个字节的值为 '01'”。它没有指定应该如何构建 IV。

这是我到目前为止的结果,但没有产生预期的结果:

    public String computeAesCheckValue(String key) throws InvalidKeyException,
            IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException,
            NoSuchAlgorithmException, NoSuchPaddingException, IOException {
        AES128CBCEncryptor encryptor = new AES128CBCEncryptor(key);

        byte[] cleartext = new byte[16];
        byte[] iv = new byte[16];
        for (int i = 0; i < 16; i++) {
            cleartext[i] = (byte) 0x01;
            iv[i] = (byte) 0x00;
        }
        String kcv = encryptor.encrypt(new String(cleartext, "utf-8"), Hex.encodeHexString(iv));

        return (kcv != null && kcv.length() >= 6)
                ? Hex.encodeHexString(kcv.getBytes()).substring(0, 6)
                : null;
    }

我错过了什么?

对于密钥校验值(KCV),通常使用单块加密,没有任何模式,例如 ECB 或 CBC。由于只使用了16字节的常量值,所以也不需要填充。

如果您只有一个执行 ISO 9797-1 M2 填充的 CBC class,那么您可以使用 全零 IV 并从结果中取出前 16 个字节(在末尾删除 16 个字节的密文,这只是强制填充的加密)。

如下图所示,由于 IV 全为零,与明文的 XOR 使输入保持不变,基本上使第一个密文与使用块密码的直接加密相同。

作者:WhiteTimberwolf(SVG 版本)- PNG 版本,Public 域,https://commons.wikimedia.org/w/index.php?curid=26434096

但是,当您使用 Java 时,使用算法 "AES/ECB/NoPadding"Cipher 对象并使用它来加密 01010101010101010101010101010101 的值更有意义直接地。 ECB 不采用 IV,因此可以避免该问题。此外,指定 "NoPadding" 时无需考虑填充。

如果您需要更少的字节:这些字节通常取自结果的左侧(最低索引)。


请注意,这类 KCV 有点危险,因为它们显示了一个特定明文块的密文。在最坏的情况下,这可能导致对手解密一个密文块,或者使经过身份验证的方案丢失其 integrity/authentication 属性。

通常 KCV 在全零明文块上。使用全单值块可以降低发生这种情况的可能性,但这种可能性仍然很大。