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.
| Package | Affected versions | Patched versions |
|---|---|---|
org.bouncycastle:bcpg-jdk12Maven | <= 130 | — |
org.bouncycastle:bcpg-jdk14Maven | < 1.84 | 1.84 |
org.bouncycastle:bcpg-jdk15Maven | <= 1.46 | — |
org.bouncycastle:bcpg-jdk15to18Maven | < 1.84 | 1.84 |
org.bouncycastle:bcpg-jdk15onMaven | <= 1.70 | — |
org.bouncycastle:bcpg-jdk16Maven | <= 1.46 | — |
org.bouncycastle:bcpg-jdk18onMaven | < 1.84 | 1.84 |
Affected products
1Patches
1dc7530939ffbadded chunk size checking for AEAD
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
3News mentions
1- Siemens SIMATICCISA Alerts