VYPR
High severityGHSA Advisory· Published Apr 15, 2026· Updated Apr 21, 2026

CVE-2026-3505

CVE-2026-3505

Description

Allocation of resources without limits or throttling, Uncontrolled Resource Consumption vulnerability in Legion of the Bouncy Castle Inc. BC-JAVA bcpg on all (pg modules). This vulnerability is associated with program files AEADEncDataPacket.Java, BcAEADUtil.Java, JceAEADUtil.Java, OperatorHelper.Java.

This issue affects BC-JAVA: from 1.74 before 1.84.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.bouncycastle:bcpg-jdk12Maven
<= 130
org.bouncycastle:bcpg-jdk14Maven
< 1.841.84
org.bouncycastle:bcpg-jdk15Maven
<= 1.46
org.bouncycastle:bcpg-jdk15to18Maven
< 1.841.84
org.bouncycastle:bcpg-jdk15onMaven
<= 1.70
org.bouncycastle:bcpg-jdk16Maven
<= 1.46
org.bouncycastle:bcpg-jdk18onMaven
< 1.841.84

Affected products

1

Patches

1
dc7530939ffb

added chunk size checking for AEAD

https://github.com/bcgit/bc-javaDavid HookMar 4, 2026via ghsa
6 files changed · +122 93
  • pg/src/main/java/org/bouncycastle/bcpg/AEADEncDataPacket.java+12 0 modified
    @@ -47,6 +47,12 @@ public AEADEncDataPacket(BCPGInputStream in,
             aeadAlgorithm = (byte)in.read();
             chunkSize = (byte)in.read();
     
    +        // RFC 9580 - 5.13.2
    +        if (chunkSize < 0 || chunkSize > 16)
    +        {
    +            throw new MalformedPacketException("chunkSize out of range");
    +        }
    +
             try
             {
                 int ivLen = AEADUtils.getIVLength(aeadAlgorithm);
    @@ -63,6 +69,12 @@ public AEADEncDataPacket(int algorithm, int aeadAlgorithm, int chunkSize, byte[]
         {
             super(null, AEAD_ENC_DATA);
     
    +        // RFC 9580 - 5.13.2
    +        if (chunkSize < 0 || chunkSize > 16)
    +        {
    +            throw new IllegalArgumentException("chunkSize out of range");
    +        }
    +
             this.version = VERSION_1;
             this.algorithm = (byte)algorithm;
             this.aeadAlgorithm = (byte)aeadAlgorithm;
    
  • pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java+2 46 modified
    @@ -25,6 +25,7 @@
     import org.bouncycastle.crypto.params.KeyParameter;
     import org.bouncycastle.openpgp.PGPException;
     import org.bouncycastle.openpgp.PGPSessionKey;
    +import org.bouncycastle.openpgp.operator.PGPAEADUtil;
     import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
     import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
     import org.bouncycastle.util.Arrays;
    @@ -33,56 +34,11 @@
     import org.bouncycastle.util.io.Streams;
     
     public class BcAEADUtil
    +    extends PGPAEADUtil
     {
         final static String RecoverAEADEncryptedSessionDataErrorMessage = "Exception recovering session info";
         private final static String ProcessAeadKeyDataErrorMessage = "Exception recovering AEAD protected private key material";
         final static String GetEskAndTagErrorMessage = "cannot encrypt session info";
    -    /**
    -     * Generate a nonce by xor-ing the given iv with the chunk index.
    -     *
    -     * @param iv         initialization vector
    -     * @param chunkIndex chunk index
    -     * @return nonce
    -     */
    -    protected static byte[] getNonce(byte[] iv, long chunkIndex)
    -    {
    -        byte[] nonce = Arrays.clone(iv);
    -
    -        xorChunkId(nonce, chunkIndex);
    -
    -        return nonce;
    -    }
    -
    -    /**
    -     * XOR the byte array with the chunk index in-place.
    -     *
    -     * @param nonce      byte array
    -     * @param chunkIndex chunk index
    -     */
    -    protected static void xorChunkId(byte[] nonce, long chunkIndex)
    -    {
    -        int index = nonce.length - 8;
    -
    -        nonce[index++] ^= (byte)(chunkIndex >> 56);
    -        nonce[index++] ^= (byte)(chunkIndex >> 48);
    -        nonce[index++] ^= (byte)(chunkIndex >> 40);
    -        nonce[index++] ^= (byte)(chunkIndex >> 32);
    -        nonce[index++] ^= (byte)(chunkIndex >> 24);
    -        nonce[index++] ^= (byte)(chunkIndex >> 16);
    -        nonce[index++] ^= (byte)(chunkIndex >> 8);
    -        nonce[index] ^= (byte)(chunkIndex);
    -    }
    -
    -    /**
    -     * Calculate an actual chunk length from the encoded chunk size.
    -     *
    -     * @param chunkSize encoded chunk size
    -     * @return decoded length
    -     */
    -    protected static long getChunkLength(int chunkSize)
    -    {
    -        return 1L << (chunkSize + 6);
    -    }
     
         /**
          * Derive a message key and IV from the given session key.
    
  • pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java+2 47 modified
    @@ -21,6 +21,7 @@
     import org.bouncycastle.openpgp.PGPException;
     import org.bouncycastle.openpgp.PGPSessionKey;
     import org.bouncycastle.openpgp.PGPUtil;
    +import org.bouncycastle.openpgp.operator.PGPAEADUtil;
     import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
     import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
     import org.bouncycastle.util.Arrays;
    @@ -29,6 +30,7 @@
     import org.bouncycastle.util.io.Streams;
     
     class JceAEADUtil
    +    extends PGPAEADUtil
     {
         private final OperatorHelper helper;
     
    @@ -37,53 +39,6 @@ public JceAEADUtil(OperatorHelper helper)
             this.helper = helper;
         }
     
    -    /**
    -     * Generate a nonce by xor-ing the given iv with the chunk index.
    -     *
    -     * @param iv         initialization vector
    -     * @param chunkIndex chunk index
    -     * @return nonce
    -     */
    -    protected static byte[] getNonce(byte[] iv, long chunkIndex)
    -    {
    -        byte[] nonce = Arrays.clone(iv);
    -
    -        xorChunkId(nonce, chunkIndex);
    -
    -        return nonce;
    -    }
    -
    -    /**
    -     * XOR the byte array with the chunk index in-place.
    -     *
    -     * @param nonce      byte array
    -     * @param chunkIndex chunk index
    -     */
    -    protected static void xorChunkId(byte[] nonce, long chunkIndex)
    -    {
    -        int index = nonce.length - 8;
    -
    -        nonce[index++] ^= (byte)(chunkIndex >> 56);
    -        nonce[index++] ^= (byte)(chunkIndex >> 48);
    -        nonce[index++] ^= (byte)(chunkIndex >> 40);
    -        nonce[index++] ^= (byte)(chunkIndex >> 32);
    -        nonce[index++] ^= (byte)(chunkIndex >> 24);
    -        nonce[index++] ^= (byte)(chunkIndex >> 16);
    -        nonce[index++] ^= (byte)(chunkIndex >> 8);
    -        nonce[index] ^= (byte)(chunkIndex);
    -    }
    -
    -    /**
    -     * Calculate an actual chunk length from the encoded chunk size.
    -     *
    -     * @param chunkSize encoded chunk size
    -     * @return decoded length
    -     */
    -    protected static long getChunkLength(int chunkSize)
    -    {
    -        return 1L << (chunkSize + 6);
    -    }
    -
         /**
          * Derive a message key and IV from the given session key.
          * The result is two byte arrays containing the key bytes and the IV.
    
  • pg/src/main/java/org/bouncycastle/openpgp/operator/PGPAEADUtil.java+65 0 added
    @@ -0,0 +1,65 @@
    +package org.bouncycastle.openpgp.operator;
    +
    +import java.io.IOException;
    +
    +import org.bouncycastle.util.Arrays;
    +
    +public class PGPAEADUtil
    +{
    +    protected PGPAEADUtil()
    +    {
    +
    +    }
    +
    +    /**
    +     * Generate a nonce by xor-ing the given iv with the chunk index.
    +     *
    +     * @param iv         initialization vector
    +     * @param chunkIndex chunk index
    +     * @return nonce
    +     */
    +    protected static byte[] getNonce(byte[] iv, long chunkIndex)
    +    {
    +        byte[] nonce = Arrays.clone(iv);
    +
    +        xorChunkId(nonce, chunkIndex);
    +
    +        return nonce;
    +    }
    +
    +    /**
    +     * XOR the byte array with the chunk index in-place.
    +     *
    +     * @param nonce      byte array
    +     * @param chunkIndex chunk index
    +     */
    +    protected static void xorChunkId(byte[] nonce, long chunkIndex)
    +    {
    +        int index = nonce.length - 8;
    +
    +        nonce[index++] ^= (byte)(chunkIndex >> 56);
    +        nonce[index++] ^= (byte)(chunkIndex >> 48);
    +        nonce[index++] ^= (byte)(chunkIndex >> 40);
    +        nonce[index++] ^= (byte)(chunkIndex >> 32);
    +        nonce[index++] ^= (byte)(chunkIndex >> 24);
    +        nonce[index++] ^= (byte)(chunkIndex >> 16);
    +        nonce[index++] ^= (byte)(chunkIndex >> 8);
    +        nonce[index] ^= (byte)(chunkIndex);
    +    }
    +
    +    /**
    +     * Calculate an actual chunk length from the encoded chunk size.
    +     *
    +     * @param chunkSize encoded chunk size
    +     * @return decoded length
    +     */
    +    protected static long getChunkLength(int chunkSize)
    +    {
    +        // RFC 9580 - 5.13.2
    +        if (chunkSize < 0 || chunkSize > 16)
    +        {
    +            throw new IllegalStateException("chunkSize out of range");
    +        }
    +        return 1L << (chunkSize + 6);
    +    }
    +}
    
  • pg/src/main/jdk1.4/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java+5 0 modified
    @@ -151,6 +151,11 @@ Cipher createStreamCipher(int encAlgorithm, boolean withIntegrityPacket)
     
         static long getChunkLength(int chunkSize)
         {
    +        // RFC 9580 - 5.13.2
    +        if (chunkSize < 0 || chunkSize > 16)
    +        {
    +            throw new IllegalStateException("chunkSize out of range");
    +        }
             return 1L << (chunkSize + 6);
         }
     
    
  • pg/src/test/java/org/bouncycastle/bcpg/test/OCBEncryptedDataPacketTest.java+36 0 modified
    @@ -21,6 +21,7 @@ public void performTest()
         {
             parseTestVector();
             parseUnsupportedPacketVersion();
    +        testUnsupportedChunkSize();
         }
     
         private void parseTestVector()
    @@ -72,6 +73,41 @@ private void parseUnsupportedPacketVersion()
             }
         }
     
    +    private void testUnsupportedChunkSize()
    +            throws IOException
    +    {
    +        try
    +        {
    +            new AEADEncDataPacket(SymmetricKeyAlgorithmTags.AES_128, AEADAlgorithmTags.OCB, 20, new byte[16]);
    +            fail("Expected IllegalArgument - chunkSize out of range");
    +        }
    +        catch (IllegalArgumentException e)
    +        {
    +            isEquals("chunkSize out of range", e.getMessage());
    +        }
    +        // Test vector with modified chunk size 18
    +        String testVector = "" +
    +        "d45301090212c265ff63a61ed8af00fa" +
    +        "43866be8eb9eef77241518a3d60e387b" +
    +        "1e283bdd90e2233d17a937a595686024" +
    +        "1d13ddfaccd2b724a491167631d1cd3e" +
    +        "a74fe5d9e617f1f267d891fd338fddb2" +
    +        "c66c025cde";
    +
    +        ByteArrayInputStream bIn = new ByteArrayInputStream(Hex.decode(testVector));
    +        BCPGInputStream pIn = new BCPGInputStream(bIn);
    +
    +        try
    +        {
    +            pIn.readPacket();
    +            fail("Expected chunkSize out of range");
    +        }
    +        catch (MalformedPacketException e)
    +        {
    +            isEquals("chunkSize out of range", e.getMessage());
    +        }
    +    }
    +
         public static void main(String[] args)
         {
             runTest(new OCBEncryptedDataPacketTest());
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

1