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

I'm trying to implement a function in Java to calculate the key check value for a 128 bit AES encryption key. The AES128CBCEncryptor class is implementing AES/128/CBC with ISO 9797-1 M2 padding.

The only information I can find on the key check value algorithm for AES says "the KCV for an AES key is computed by encrypting 16 bytes, each with value '01'.". It does not specify how the IV should be constructed.

Here is what I have thus far, but it's not generating the expected result:

    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;
    }

What am I missing?


For a Key Check Value (KCV) one generally uses single block encryption, without any mode such as ECB or CBC. As only a constant value of 16 bytes is used, there is no need for padding either.

If you just have a CBC class that performs ISO 9797-1 M2 padding then you could encrypt the static value of 01010101010101010101010101010101 (hex encoding of 16 bytes), using an all-zero IV and taking the first 16 bytes from the result (removing 16 bytes of ciphertext at the end that is just encryption of the mandatory padding).

As you can see in the image below, because the IV is all zero, the XOR with the plaintext leaves the input intact, basically making the first ciphertext identical to direct encryption with the block cipher.

enter image description here By WhiteTimberwolf (SVG version) - PNG version, Public Domain, https://commons.wikimedia.org/w/index.php?curid=26434096

However, as you are using Java, it makes more sense to use a Cipher object using algorithm "AES/ECB/NoPadding" and use that to encrypt the value of 01010101010101010101010101010101 directly. ECB doesn't take an IV, so that problem is avoided. Also, no padding needs to be considered when "NoPadding" is specified.

If you need fewer bytes: those are usually taken from the left (lowest index) of the result.


Beware that these kinds of KCV's are somewhat dangerous as they show the ciphertext of one particular plaintext block. In the worst instances, this could lead to an adversary decrypting one ciphertext block, or for an authenticated scheme to lose its integrity/authentication properties.

Commonly KCV's are over an all-zero plaintext block. Using an all one-valued block makes the chance that this happens smaller, but that chance is still significant.