VYPR
Low severityNVD Advisory· Published Jun 4, 2018· Updated Aug 6, 2024

CVE-2016-1000346

CVE-2016-1000346

Description

In the Bouncy Castle JCE Provider version 1.55 and earlier the other party DH public key is not fully validated. This can cause issues as invalid keys can be used to reveal details about the other party's private key where static Diffie-Hellman is in use. As of release 1.56 the key parameters are checked on agreement calculation.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Bouncy Castle JCE Provider prior to 1.56 does not fully validate DH public keys, enabling private key recovery in static Diffie-Hellman scenarios.

Vulnerability

In the Bouncy Castle JCE Provider version 1.55 and earlier, the other party's Diffie-Hellman (DH) public key is not fully validated during agreement calculation [1][3][4]. This flaw resides in the cryptographic library's DH key exchange implementation. When using static Diffie-Hellman, where long-term keys are reused, the missing validation allows the use of invalid public keys crafted by an attacker. The issue was addressed in version 1.56 of the library, which added full validation of the public key parameters [2].

Exploitation

An attacker must be in a position to participate in a Diffie-Hellman key agreement where the victim uses a static (long-term) private key and the library does not enforce required parameter checks [1]. By supplying a specially crafted invalid DH public key, the attacker can exploit the missing validation to learn details about the victim's private key through multiple protocol interactions [3]. No authentication is needed if the attacker can initiate the key agreement, and the attack is performed remotely over a network [4].

Impact

Successful exploitation allows an attacker to recover information about the victim's private key when static DH is used [1]. This leads to a compromise of confidentiality, as the attacker can derive the shared secret and decrypt past or future communications where that private key is reused [3]. The attacker gains knowledge of the private key, enabling impersonation and further cryptographic attacks.

Mitigation

Users should upgrade to Bouncy Castle JCE Provider version 1.56 or later, which properly validates DH public key parameters [2]. Red Hat Satellite 6.4, Red Hat Fuse 7.1, and Ubuntu (14.04 LTS, 16.04 LTS, 18.04 LTS) have released updates containing the fixed version [1][3][4]. For deployments that cannot immediately upgrade, disabling static DH or applying vendor-specific workarounds may reduce risk until a patch can be applied.

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.bouncycastle:bcprov-jdk14Maven
< 1.561.56
org.bouncycastle:bcprov-jdk15Maven
< 1.561.56
org.bouncycastle:bcprov-jdk15onMaven
< 1.561.56

Affected products

4

Patches

1
1127131c8902

Added TLS validation check for DH keys

https://github.com/bcgit/bc-javaDavid HookOct 29, 2016via ghsa
5 files changed · +55 10
  • core/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java+11 3 modified
    @@ -6,11 +6,11 @@
     import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
     import org.bouncycastle.crypto.CipherParameters;
     import org.bouncycastle.crypto.generators.DHKeyPairGenerator;
    +import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
     import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
     import org.bouncycastle.crypto.params.DHParameters;
    -import org.bouncycastle.crypto.params.DHPublicKeyParameters;
     import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
    -import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
    +import org.bouncycastle.crypto.params.DHPublicKeyParameters;
     import org.bouncycastle.crypto.params.ParametersWithRandom;
     
     /**
    @@ -26,6 +26,8 @@
      */
     public class DHAgreement
     {
    +    private static final BigInteger ONE = BigInteger.valueOf(1);
    +
         private DHPrivateKeyParameters  key;
         private DHParameters            dhParams;
         private BigInteger              privateValue;
    @@ -89,6 +91,12 @@ public BigInteger calculateAgreement(
     
             BigInteger p = dhParams.getP();
     
    -        return message.modPow(key.getX(), p).multiply(pub.getY().modPow(privateValue, p)).mod(p);
    +        BigInteger result = pub.getY().modPow(privateValue, p);
    +        if (result.compareTo(ONE) == 0)
    +        {
    +            throw new IllegalStateException("Shared key can't be 1");
    +        }
    +
    +        return message.modPow(key.getX(), p).multiply(result).mod(p);
         }
     }
    
  • core/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java+9 1 modified
    @@ -20,6 +20,8 @@
     public class DHBasicAgreement
         implements BasicAgreement
     {
    +    private static final BigInteger ONE = BigInteger.valueOf(1);
    +
         private DHPrivateKeyParameters  key;
         private DHParameters            dhParams;
     
    @@ -66,6 +68,12 @@ public BigInteger calculateAgreement(
                 throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
             }
     
    -        return pub.getY().modPow(key.getX(), dhParams.getP());
    +        BigInteger result = pub.getY().modPow(key.getX(), dhParams.getP());
    +        if (result.compareTo(ONE) == 0)
    +        {
    +            throw new IllegalStateException("Shared key can't be 1");
    +        }
    +
    +        return result;
         }
     }
    
  • core/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java+4 0 modified
    @@ -408,6 +408,10 @@ public byte[] processBlock(
                     {
                         throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
                     }
    +                catch (IllegalArgumentException e)
    +                {
    +                    throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
    +                }
     
                     int encLength = (inLen - bIn.available());
                     this.V = Arrays.copyOfRange(in, inOff, inOff + encLength);
    
  • core/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java+15 1 modified
    @@ -5,6 +5,9 @@
     public class DHPublicKeyParameters
         extends DHKeyParameters
     {
    +    private static final BigInteger ONE = BigInteger.valueOf(1);
    +    private static final BigInteger TWO = BigInteger.valueOf(2);
    +
         private BigInteger      y;
     
         public DHPublicKeyParameters(
    @@ -18,9 +21,14 @@ public DHPublicKeyParameters(
     
         private BigInteger validate(BigInteger y, DHParameters dhParams)
         {
    +        if (y == null)
    +        {
    +            throw new NullPointerException("y value cannot be null");
    +        }
    +
             if (dhParams.getQ() != null)
             {
    -            if (BigInteger.ONE.equals(y.modPow(dhParams.getQ(), dhParams.getP())))
    +            if (ONE.equals(y.modPow(dhParams.getQ(), dhParams.getP())))
                 {
                     return y;
                 }
    @@ -29,6 +37,12 @@ private BigInteger validate(BigInteger y, DHParameters dhParams)
             }
             else
             {
    +            // TLS check
    +            if (y.compareTo(TWO) < 0 || y.compareTo(dhParams.getP().subtract(TWO)) > 0)
    +            {
    +                throw new IllegalArgumentException("invalid DH public key");
    +            }
    +
                 return y;         // we can't validate without Q.
             }
         }
    
  • prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java+16 5 modified
    @@ -29,6 +29,9 @@
     public class KeyAgreementSpi
         extends BaseAgreementSpi
     {
    +    private static final BigInteger ONE = BigInteger.valueOf(1);
    +    private static final BigInteger TWO = BigInteger.valueOf(2);
    +
         private BigInteger      x;
         private BigInteger      p;
         private BigInteger      g;
    @@ -101,14 +104,22 @@ protected Key engineDoPhase(
                 throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
             }
     
    -        if (lastPhase)
    +        BigInteger peerY = ((DHPublicKey)key).getY();
    +        if (peerY == null || peerY.compareTo(TWO) < 0
    +            || peerY.compareTo(p.subtract(ONE)) >= 0)
             {
    -            result = ((DHPublicKey)key).getY().modPow(x, p);
    -            return null;
    +            throw new InvalidKeyException("Invalid DH PublicKey");
             }
    -        else
    +
    +        result = peerY.modPow(x, p);
    +        if (result.compareTo(ONE) == 0)
             {
    -            result = ((DHPublicKey)key).getY().modPow(x, p);
    +            throw new InvalidKeyException("Shared key can't be 1");
    +        }
    +
    +        if (lastPhase)
    +        {
    +            return null;
             }
     
             return new BCDHPublicKey(result, pubKey.getParams());
    

Vulnerability mechanics

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

References

11

News mentions

0

No linked articles in our index yet.