Skip to content

CCM Block Mode includes MAC bytes when validating Payload Length #1570

Description

@CipherGato

Bouncy Castle validates that the payload length is less than the maximum allowed on both encrypt and decrypt operations. On decryption the validation is incorrectly including the appended MAC bytes in the length that is validated. This results in an error when decrypting valid ciphertext.

For Example:

With a 13 byte Nonce the maximum payload size is 65535 bytes. The example below attempts to encrypt and then decrypt a 65535 byte array. The decryption operation will fail with:

Exception in thread "main" java.lang.IllegalStateException: CCM packet too large for choice of q.
	at org.bouncycastle.crypto.modes.CCMBlockCipher.processPacket(Unknown Source)
	at org.bouncycastle.crypto.modes.CCMBlockCipher.doFinal(Unknown Source)
	at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source)
	at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
	at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2244)
	at org.example.Main.main(Main.java:20)
import org.bouncycastle.jcajce.spec.AEADParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;

public class Main {
    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        final byte[] secretKey = new byte[32];
        final byte[] nonce = new byte[13];

        final byte[] input = new byte[65535];

        final byte[] encrypted = getCipher(Cipher.ENCRYPT_MODE, secretKey, nonce).doFinal(input);
        final byte[] decrypted = getCipher(Cipher.DECRYPT_MODE, secretKey, nonce).doFinal(encrypted);
    }

    private static Cipher getCipher(final int mode, final byte[] secretkey, final byte[] nonce) throws Exception {
        final Cipher cipher = Cipher.getInstance("AES/CCM/NoPadding", "BC");
        final AlgorithmParameterSpec algorithmSpec = new AEADParameterSpec(nonce, 128);
        cipher.init(mode, new SecretKeySpec(secretkey, "AES"), algorithmSpec);
        return cipher;
    }
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions