CVE-2016-1000339
Description
In the Bouncy Castle JCE Provider version 1.55 and earlier the primary engine class used for AES was AESFastEngine. Due to the highly table driven approach used in the algorithm it turns out that if the data channel on the CPU can be monitored the lookup table accesses are sufficient to leak information on the AES key being used. There was also a leak in AESEngine although it was substantially less. AESEngine has been modified to remove any signs of leakage (testing carried out on Intel X86-64) and is now the primary AES class for the BC JCE provider from 1.56. Use of AESFastEngine is now only recommended where otherwise deemed appropriate.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Bouncy Castle JCE Provider up to 1.55 leaks AES key material via CPU side-channel in AESFastEngine; fixed in 1.56.
Vulnerability
The Bouncy Castle JCE Provider versions 1.55 and earlier used AESFastEngine as the primary AES engine. This implementation is highly table-driven, making it vulnerable to cache-based side-channel attacks. An attacker with the ability to monitor the CPU's data channel (e.g., via timing or cache analysis) can observe lookup table accesses, which leak information about the AES key [1][2][4]. The AESEngine class also exhibited a minor leak, though significantly less severe. From version 1.56, AESEngine has been modified to eliminate signs of leakage (testing on Intel X86-64) and is now the default AES provider; AESFastEngine is only recommended where deemed appropriate.
Exploitation
To exploit this vulnerability, an attacker requires the ability to monitor the CPU’s data channel—typically achieved through shared hardware environments (e.g., cloud co-tenancy) or via malicious code running on the same system. No authentication or user interaction is needed beyond executing code that can observe cache timing. The attacker repeatedly measures the encryption time or cache behavior during AES operations using AESFastEngine, then applies statistical analysis to recover the secret key. The attack does not require network access but does require execution privilege on the same hardware as the vulnerable library.
Impact
A successful attacker can recover the full AES secret key used by the Bouncy Castle library. This leads to a complete compromise of cryptographic confidentiality: any data encrypted with that key can be decrypted, and any authenticated sessions relying on it can be forged. The impact is limited to systems using AESFastEngine in Bouncy Castle versions ≤1.55, but given the key’s use for securing communications in applications like JBoss, Red Hat Satellite, and similar integrated stacks, the breach could affect a wide range of systems and data [1][3].
Mitigation
The vulnerability is fixed in Bouncy Castle JCE Provider version 1.56, released in 2017 [2]. Red Hat has issued advisories RHSA-2018:2927 (Satellite 6.4), RHSA-2018:2669 (Fuse 7.1), and Ubuntu USN-3727-1, which update Bouncy Castle to the patched version [1][3][4]. Users should upgrade to version 1.56 or later. For systems where immediate patching is not possible, avoid using AESFastEngine and switch to AESEngine, though note that only version 1.56+ provides the fully mitigated implementation. No mitigation is available for earlier versions other than upgrading.
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.
| Package | Affected versions | Patched versions |
|---|---|---|
org.bouncycastle:bcprov-jdk14Maven | < 1.56 | 1.56 |
org.bouncycastle:bcprov-jdk15Maven | < 1.56 | 1.56 |
org.bouncycastle:bcprov-jdk15onMaven | < 1.56 | 1.56 |
Affected products
4- ghsa-coords4 versionspkg:maven/org.bouncycastle/bcprov-jdk14pkg:maven/org.bouncycastle/bcprov-jdk15pkg:maven/org.bouncycastle/bcprov-jdk15onpkg:rpm/opensuse/bouncycastle&distro=openSUSE%20Tumbleweed
< 1.56+ 3 more
- (no CPE)range: < 1.56
- (no CPE)range: < 1.56
- (no CPE)range: < 1.56
- (no CPE)range: < 1.68-3.2
Patches
28a73f0893145Added table use obfuscation to AESFastEngine
3 files changed · +11 −79
core/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java+4 −2 modified@@ -26,9 +26,11 @@ * the contents of the first * * The slowest version uses no static tables at all and computes the values in each round + * </p> * <p> - * This file contains the fast version with 8Kbytes of static tables for round precomputation - * + * This file contains the fast version with 8Kbytes of static tables for round precomputation. + * </p> + * @deprecated unfortunately this class is has a few side channel issues. In an environment where encryption/decryption may be closely observed it should not be used. */ public class AESFastEngine implements BlockCipher
prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java+6 −76 modified@@ -1,6 +1,5 @@ package org.bouncycastle.jcajce.provider.drbg; -import java.lang.reflect.Constructor; import java.security.SecureRandom; import java.security.SecureRandomSpi; @@ -22,22 +21,19 @@ public static class Default extends SecureRandomSpi { private SecureRandom random = new SP800SecureRandomBuilder(secureRandom, true) - .setPersonalizationString(generateDefaultPersonalizationString()) + .setPersonalizationString(generateDefaultPersonalizationString(secureRandom)) .buildHash(new SHA512Digest(), secureRandom.generateSeed(32), true); - @Override protected void engineSetSeed(byte[] bytes) { random.setSeed(bytes); } - @Override protected void engineNextBytes(byte[] bytes) { random.nextBytes(bytes); } - @Override protected byte[] engineGenerateSeed(int numBytes) { return secureRandom.generateSeed(numBytes); @@ -48,22 +44,19 @@ public static class NonceAndIV extends SecureRandomSpi { private SecureRandom random = new SP800SecureRandomBuilder(secureRandom, true) - .setPersonalizationString(generateNonceIVPersonalizationString()) + .setPersonalizationString(generateNonceIVPersonalizationString(secureRandom)) .buildHash(new SHA512Digest(), secureRandom.generateSeed(32), false); - @Override protected void engineSetSeed(byte[] bytes) { random.setSeed(bytes); } - @Override protected void engineNextBytes(byte[] bytes) { random.nextBytes(bytes); } - @Override protected byte[] engineGenerateSeed(int numBytes) { return secureRandom.generateSeed(numBytes); @@ -84,78 +77,15 @@ public void configure(ConfigurableProvider provider) } } - private static byte[] generateDefaultPersonalizationString() + private static byte[] generateDefaultPersonalizationString(SecureRandom random) { - return Arrays.concatenate(Strings.toByteArray("Default"), Strings.toUTF8ByteArray(getVIMID()), + return Arrays.concatenate(Strings.toByteArray("Default"), random.generateSeed(16), Pack.longToBigEndian(Thread.currentThread().getId()), Pack.longToBigEndian(System.currentTimeMillis())); } - private static byte[] generateNonceIVPersonalizationString() + private static byte[] generateNonceIVPersonalizationString(SecureRandom random) { - return Arrays.concatenate(Strings.toByteArray("Default"), Strings.toUTF8ByteArray(getVIMID()), + return Arrays.concatenate(Strings.toByteArray("Nonce"), random.generateSeed(16), Pack.longToLittleEndian(Thread.currentThread().getId()), Pack.longToLittleEndian(System.currentTimeMillis())); } - - private static final Constructor vimIDConstructor; - - static - { - Class vimIDClass = lookup("java.rmi.dgc.VMID"); - if (vimIDClass != null) - { - vimIDConstructor = findConstructor(vimIDClass); - } - else - { - vimIDConstructor = null; - } - } - - private static Class lookup(String className) - { - try - { - Class def = DRBG.class.getClassLoader().loadClass(className); - - return def; - } - catch (Exception e) - { - return null; - } - } - - private static Constructor findConstructor(Class clazz) - { - try - { - return clazz.getConstructor(); - } - catch (Exception e) - { - return null; - } - } - - static String getVIMID() - { - if (vimIDConstructor != null) - { - Object vimID = null; - try - { - vimID = vimIDConstructor.newInstance(); - } - catch (Exception i) - { - // might happen, fall through if it does - } - if (vimID != null) - { - return vimID.toString(); - } - } - - return "No VIM ID"; // TODO: maybe there is a system property we can use here. - } }
prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java+1 −1 modified@@ -184,7 +184,7 @@ public int doFinal(byte[] out, int outOff) } catch (InvalidCipherTextException e) { - throw new IllegalStateException("exception on doFinal()", e); + throw new IllegalStateException("exception on doFinal(): " + e.toString()); } }
413b42f4d770added better support for DH domain parameters
8 files changed · +288 −136
core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java+19 −8 modified@@ -5,6 +5,7 @@ import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; /** @@ -415,6 +416,8 @@ private int[][] generateWorkingKey(byte[] key, boolean forEncryption) private int C0, C1, C2, C3; private boolean forEncryption; + private byte[] s; + private static final int BLOCK_SIZE = 16; /** @@ -440,6 +443,14 @@ public void init( { WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption); this.forEncryption = forEncryption; + if (forEncryption) + { + s = Arrays.clone(S); + } + else + { + s = Arrays.clone(Si); + } return; } @@ -578,10 +589,10 @@ private void encryptBlock(int[][] KW) // the final round's table is a simple function of S so we don't use a whole other four tables for it - this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0]; - this.C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1]; - this.C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; - this.C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; + this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((s[(r2>>16)&255]&255)<<16) ^ (s[(r3>>24)&255]<<24) ^ KW[r][0]; + this.C1 = (s[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (s[(r0>>24)&255]<<24) ^ KW[r][1]; + this.C2 = (s[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; + this.C3 = (s[r3&255]&255) ^ ((s[(r0>>8)&255]&255)<<8) ^ ((s[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; } private void decryptBlock(int[][] KW) @@ -610,9 +621,9 @@ private void decryptBlock(int[][] KW) // the final round's table is a simple function of Si so we don't use a whole other four tables for it - this.C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; - this.C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1]; - this.C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2]; - this.C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3]; + this.C0 = (Si[r0&255]&255) ^ ((s[(r3>>8)&255]&255)<<8) ^ ((s[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; + this.C1 = (s[r1&255]&255) ^ ((s[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (s[(r2>>24)&255]<<24) ^ KW[0][1]; + this.C2 = (s[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (s[(r3>>24)&255]<<24) ^ KW[0][2]; + this.C3 = (Si[r3&255]&255) ^ ((s[(r2>>8)&255]&255)<<8) ^ ((s[(r1>>16)&255]&255)<<16) ^ (s[(r0>>24)&255]<<24) ^ KW[0][3]; } }
core/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java+6 −6 modified@@ -26,6 +26,12 @@ private BigInteger validate(BigInteger y, DHParameters dhParams) throw new NullPointerException("y value cannot be null"); } + // TLS check + if (y.compareTo(TWO) < 0 || y.compareTo(dhParams.getP().subtract(TWO)) > 0) + { + throw new IllegalArgumentException("invalid DH public key"); + } + if (dhParams.getQ() != null) { if (ONE.equals(y.modPow(dhParams.getQ(), dhParams.getP()))) @@ -37,12 +43,6 @@ 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/BCDHPublicKey.java+24 −1 modified@@ -16,10 +16,12 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x9.DHDomainParameters; import org.bouncycastle.asn1.x9.DomainParameters; +import org.bouncycastle.asn1.x9.ValidationParams; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPublicKeyParameters; +import org.bouncycastle.crypto.params.DHValidationParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; public class BCDHPublicKey @@ -29,6 +31,7 @@ public class BCDHPublicKey private BigInteger y; + private transient DHPublicKeyParameters dhPublicKey; private transient DHParameterSpec dhSpec; private transient SubjectPublicKeyInfo info; @@ -37,20 +40,23 @@ public class BCDHPublicKey { this.y = spec.getY(); this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG()); + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(spec.getP(), spec.getG())); } BCDHPublicKey( DHPublicKey key) { this.y = key.getY(); this.dhSpec = key.getParams(); + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG())); } BCDHPublicKey( DHPublicKeyParameters params) { this.y = params.getY(); this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL()); + this.dhPublicKey = params; } BCDHPublicKey( @@ -59,6 +65,7 @@ public class BCDHPublicKey { this.y = y; this.dhSpec = dhSpec; + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG())); } public BCDHPublicKey( @@ -94,12 +101,23 @@ public BCDHPublicKey( { this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); } + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG())); } else if (id.equals(X9ObjectIdentifiers.dhpublicnumber)) { DomainParameters params = DomainParameters.getInstance(seq); this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); + ValidationParams validationParams = params.getValidationParams(); + if (validationParams != null) + { + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), + new DHValidationParameters(validationParams.getSeed(), validationParams.getPgenCounter().intValue()))); + } + else + { + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), null)); + } } else { @@ -137,6 +155,11 @@ public BigInteger getY() return y; } + public DHPublicKeyParameters engineGetKeyParameters() + { + return dhPublicKey; + } + private boolean isPKCSParam(ASN1Sequence seq) { if (seq.size() == 2)
prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java+8 −1 modified@@ -82,7 +82,14 @@ protected PublicKey engineGeneratePublic( { if (keySpec instanceof DHPublicKeySpec) { - return new BCDHPublicKey((DHPublicKeySpec)keySpec); + try + { + return new BCDHPublicKey((DHPublicKeySpec)keySpec); + } + catch (IllegalArgumentException e) + { + throw new InvalidKeySpecException(e.getMessage(), e); + } } return super.engineGeneratePublic(keySpec);
prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/IESCipher.java+2 −2 modified@@ -24,7 +24,7 @@ import org.bouncycastle.crypto.KeyEncoder; import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.engines.IESEngine; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; @@ -538,7 +538,7 @@ static public class ECIESwithAESCBC { public ECIESwithAESCBC() { - super(new CBCBlockCipher(new AESFastEngine()), 16); + super(new CBCBlockCipher(new AESEngine()), 16); } } }
prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java+5 −0 modified@@ -11,6 +11,7 @@ import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPrivateKeyParameters; import org.bouncycastle.crypto.params.DHPublicKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPublicKey; /** * utility class for converting jce/jca DH objects @@ -22,6 +23,10 @@ static public AsymmetricKeyParameter generatePublicKeyParameter( PublicKey key) throws InvalidKeyException { + if (key instanceof BCDHPublicKey) + { + return ((BCDHPublicKey)key).engineGetKeyParameters(); + } if (key instanceof DHPublicKey) { DHPublicKey k = (DHPublicKey)key;
prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java+20 −20 modified@@ -20,7 +20,7 @@ import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.Mac; -import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.AESWrapEngine; import org.bouncycastle.crypto.engines.RFC3211WrapEngine; import org.bouncycastle.crypto.engines.RFC5649WrapEngine; @@ -61,7 +61,7 @@ public ECB() { public BlockCipher get() { - return new AESFastEngine(); + return new AESEngine(); } }); } @@ -72,7 +72,7 @@ public static class CBC { public CBC() { - super(new CBCBlockCipher(new AESFastEngine()), 128); + super(new CBCBlockCipher(new AESEngine()), 128); } } @@ -81,7 +81,7 @@ static public class CFB { public CFB() { - super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128); + super(new BufferedBlockCipher(new CFBBlockCipher(new AESEngine(), 128)), 128); } } @@ -90,7 +90,7 @@ static public class OFB { public OFB() { - super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128); + super(new BufferedBlockCipher(new OFBBlockCipher(new AESEngine(), 128)), 128); } } @@ -99,7 +99,7 @@ static public class GCM { public GCM() { - super(new GCMBlockCipher(new AESFastEngine())); + super(new GCMBlockCipher(new AESEngine())); } } @@ -108,7 +108,7 @@ static public class CCM { public CCM() { - super(new CCMBlockCipher(new AESFastEngine()), false, 16); + super(new CCMBlockCipher(new AESEngine()), false, 16); } } @@ -117,7 +117,7 @@ public static class AESCMAC { public AESCMAC() { - super(new CMac(new AESFastEngine())); + super(new CMac(new AESEngine())); } } @@ -126,7 +126,7 @@ public static class AESGMAC { public AESGMAC() { - super(new GMac(new GCMBlockCipher(new AESFastEngine()))); + super(new GMac(new GCMBlockCipher(new AESEngine()))); } } @@ -141,7 +141,7 @@ public AESCCMMAC() private static class CCMMac implements Mac { - private final CCMBlockCipher ccm = new CCMBlockCipher(new AESFastEngine()); + private final CCMBlockCipher ccm = new CCMBlockCipher(new AESEngine()); private int macLength = 8; @@ -200,7 +200,7 @@ public static class Poly1305 { public Poly1305() { - super(new org.bouncycastle.crypto.macs.Poly1305(new AESFastEngine())); + super(new org.bouncycastle.crypto.macs.Poly1305(new AESEngine())); } } @@ -227,7 +227,7 @@ public static class RFC3211Wrap { public RFC3211Wrap() { - super(new RFC3211WrapEngine(new AESFastEngine()), 16); + super(new RFC3211WrapEngine(new AESEngine()), 16); } } @@ -236,7 +236,7 @@ public static class RFC5649Wrap { public RFC5649Wrap() { - super(new RFC5649WrapEngine(new AESFastEngine())); + super(new RFC5649WrapEngine(new AESEngine())); } } @@ -248,7 +248,7 @@ static public class PBEWithAESCBC { public PBEWithAESCBC() { - super(new CBCBlockCipher(new AESFastEngine())); + super(new CBCBlockCipher(new AESEngine())); } } @@ -260,7 +260,7 @@ static public class PBEWithSHA1AESCBC128 { public PBEWithSHA1AESCBC128() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 128, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 128, 16); } } @@ -269,7 +269,7 @@ static public class PBEWithSHA1AESCBC192 { public PBEWithSHA1AESCBC192() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 192, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 192, 16); } } @@ -278,7 +278,7 @@ static public class PBEWithSHA1AESCBC256 { public PBEWithSHA1AESCBC256() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 256, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA1, 256, 16); } } @@ -290,7 +290,7 @@ static public class PBEWithSHA256AESCBC128 { public PBEWithSHA256AESCBC128() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 128, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 128, 16); } } @@ -299,7 +299,7 @@ static public class PBEWithSHA256AESCBC192 { public PBEWithSHA256AESCBC192() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 192, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 192, 16); } } @@ -308,7 +308,7 @@ static public class PBEWithSHA256AESCBC256 { public PBEWithSHA256AESCBC256() { - super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 256, 16); + super(new CBCBlockCipher(new AESEngine()), PKCS12, SHA256, 256, 16); } }
prov/src/test/java/org/bouncycastle/jce/provider/test/DHTest.java+204 −98 modified@@ -7,10 +7,12 @@ import java.math.BigInteger; import java.security.AlgorithmParameterGenerator; import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; @@ -55,66 +57,66 @@ public class DHTest private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16); private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16); - private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); - private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); + private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); + private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); // public key with mismatched oid/parameters private byte[] oldPubEnc = Base64.decode( "MIIBnzCCARQGByqGSM4+AgEwggEHAoGBAPxSrN417g43VAM9sZRf1dt6AocAf7D6" + - "WVCtqEDcBJrMzt63+g+BNJzhXVtbZ9kp9vw8L/0PHgzv0Ot/kOLX7Khn+JalOECW" + - "YlkyBhmOVbjR79TY5u2GAlvG6pqpizieQNBCEMlUuYuK1Iwseil6VoRuA13Zm7uw" + - "WO1eZmaJtY7LAoGAQaPRCFKM5rEdkMrV9FNzeSsYRs8m3DqPnnJHpuySpyO9wUcX" + - "OOJcJY5qvHbDO5SxHXu/+bMgXmVT6dXI5o0UeYqJR7fj6pR4E6T0FwG55RFr5Ok4" + - "3C4cpXmaOu176SyWuoDqGs1RDGmYQjwbZUi23DjaaTFUly9LCYXMliKrQfEDgYQA" + - "AoGAQUGCBN4TaBw1BpdBXdTvTfCU69XDB3eyU2FOBE3UWhpx9D8XJlx4f5DpA4Y6" + - "6sQMuCbhfmjEph8W7/sbMurM/awR+PSR8tTY7jeQV0OkmAYdGK2nzh0ZSifMO1oE" + - "NNhN2O62TLs67msxT28S4/S89+LMtc98mevQ2SX+JF3wEVU="); + "WVCtqEDcBJrMzt63+g+BNJzhXVtbZ9kp9vw8L/0PHgzv0Ot/kOLX7Khn+JalOECW" + + "YlkyBhmOVbjR79TY5u2GAlvG6pqpizieQNBCEMlUuYuK1Iwseil6VoRuA13Zm7uw" + + "WO1eZmaJtY7LAoGAQaPRCFKM5rEdkMrV9FNzeSsYRs8m3DqPnnJHpuySpyO9wUcX" + + "OOJcJY5qvHbDO5SxHXu/+bMgXmVT6dXI5o0UeYqJR7fj6pR4E6T0FwG55RFr5Ok4" + + "3C4cpXmaOu176SyWuoDqGs1RDGmYQjwbZUi23DjaaTFUly9LCYXMliKrQfEDgYQA" + + "AoGAQUGCBN4TaBw1BpdBXdTvTfCU69XDB3eyU2FOBE3UWhpx9D8XJlx4f5DpA4Y6" + + "6sQMuCbhfmjEph8W7/sbMurM/awR+PSR8tTY7jeQV0OkmAYdGK2nzh0ZSifMO1oE" + + "NNhN2O62TLs67msxT28S4/S89+LMtc98mevQ2SX+JF3wEVU="); // bogus key with full PKCS parameter set private byte[] oldFullParams = Base64.decode( "MIIBIzCCARgGByqGSM4+AgEwggELAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E" + - "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f" + - "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv" + - "8iIDGZ3RSAHHAoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlX" + - "jrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j" + - "fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqAgFk" + - "AwUAAgIH0A=="); + "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f" + + "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv" + + "8iIDGZ3RSAHHAoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlX" + + "jrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j" + + "fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqAgFk" + + "AwUAAgIH0A=="); private byte[] samplePubEnc = Base64.decode( - "MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I8" + - "70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk" + - "n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX" + - "Ku/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR" + - "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWR" + - "bqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoC" + - "AgIAA4GEAAKBgEIiqxoUW6E6GChoOgcfNbVFclW91ITf5MFSUGQwt2R0RHoOhxvO" + - "lZhNs++d0VPATLAyXovjfgENT9SGCbuZttYcqqLdKTbMXBWPek+rfnAl9E4iEMED" + - "IDd83FJTKs9hQcPAm7zmp0Xm1bGF9CbUFjP5G02265z7eBmHDaT0SNlB"); + "MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I8" + + "70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk" + + "n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX" + + "Ku/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR" + + "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWR" + + "bqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoC" + + "AgIAA4GEAAKBgEIiqxoUW6E6GChoOgcfNbVFclW91ITf5MFSUGQwt2R0RHoOhxvO" + + "lZhNs++d0VPATLAyXovjfgENT9SGCbuZttYcqqLdKTbMXBWPek+rfnAl9E4iEMED" + + "IDd83FJTKs9hQcPAm7zmp0Xm1bGF9CbUFjP5G02265z7eBmHDaT0SNlB"); private byte[] samplePrivEnc = Base64.decode( - "MIIBZgIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YR" + - "t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ" + - "UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu" + - "K2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H" + - "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuz" + - "pnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P" + - "SSoCAgIABEICQAZYXnBHazxXUUdFP4NIf2Ipu7du0suJPZQKKff81wymi2zfCfHh" + - "uhe9gQ9xdm4GpzeNtrQ8/MzpTy+ZVrtd29Q="); + "MIIBZgIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YR" + + "t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ" + + "UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu" + + "K2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H" + + "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuz" + + "pnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P" + + "SSoCAgIABEICQAZYXnBHazxXUUdFP4NIf2Ipu7du0suJPZQKKff81wymi2zfCfHh" + + "uhe9gQ9xdm4GpzeNtrQ8/MzpTy+ZVrtd29Q="); public String getName() { return "DH"; } private void testGP( - String algName, - int size, - int privateValueSize, - BigInteger g, - BigInteger p) + String algName, + int size, + int privateValueSize, + BigInteger g, + BigInteger p) throws Exception { - DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algName, "BC"); @@ -127,11 +129,11 @@ private void testGP( // // public key encoding test // - byte[] pubEnc = aKeyPair.getPublic().getEncoded(); - KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); - X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); - DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); - DHParameterSpec spec = pubKey.getParams(); + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); + DHParameterSpec spec = pubKey.getParams(); if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) { @@ -172,9 +174,9 @@ private void testGP( // // private key encoding test // - byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); - DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); + DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); spec = privKey.getParams(); @@ -271,7 +273,7 @@ private void testGP( } private void testTwoParty(String algName, int size, int privateValueSize, KeyPairGenerator keyGen) - throws Exception + throws Exception { testTwoParty(algName, size, privateValueSize, keyGen.generateKeyPair(), keyGen.generateKeyPair()); } @@ -315,13 +317,13 @@ private byte[] testTwoParty(String algName, int size, int privateValueSize, KeyP } private void testExplicitWrapping( - int size, - int privateValueSize, - BigInteger g, - BigInteger p) + int size, + int privateValueSize, + BigInteger g, + BigInteger p) throws Exception { - DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); @@ -357,7 +359,7 @@ private void testExplicitWrapping( SecretKey k1 = aKeyAgree.generateSecret(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); SecretKey k2 = bKeyAgree.generateSecret(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); - + // TODO Compare k1 and k2? } @@ -389,7 +391,7 @@ private void checkKeySize(int privateValueSize, KeyPair aKeyPair) } private void testRandom( - int size) + int size) throws Exception { AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DH", "BC"); @@ -415,14 +417,14 @@ private void testRandom( } private void testDefault( - int privateValueSize, - BigInteger g, - BigInteger p) + int privateValueSize, + BigInteger g, + BigInteger p) throws Exception { - DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); - String algName = "DH"; - int size = p.bitLength(); + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + String algName = "DH"; + int size = p.bitLength(); new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, dhParams); @@ -439,11 +441,11 @@ private void testDefault( // // public key encoding test // - byte[] pubEnc = aKeyPair.getPublic().getEncoded(); - KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); - X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); - DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); - DHParameterSpec spec = pubKey.getParams(); + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); + DHParameterSpec spec = pubKey.getParams(); if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) { @@ -458,13 +460,13 @@ private void testDefault( // // public key serialisation test // - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ObjectOutputStream oOut = new ObjectOutputStream(bOut); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); oOut.writeObject(aKeyPair.getPublic()); - ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); - ObjectInputStream oIn = new ObjectInputStream(bIn); + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + ObjectInputStream oIn = new ObjectInputStream(bIn); pubKey = (DHPublicKey)oIn.readObject(); spec = pubKey.getParams(); @@ -482,9 +484,9 @@ private void testDefault( // // private key encoding test // - byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); - DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); + DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); spec = privKey.getParams(); @@ -622,18 +624,18 @@ private void testECDH(String algorithm, String curveName, String cipher, int key private void testECDH(String algorithm) throws Exception { - KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC"); + KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC"); EllipticCurve curve = new EllipticCurve( - new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b ECParameterSpec ecSpec = new ECParameterSpec( - curve, - ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G - new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n - 1); // h + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h g.initialize(ecSpec, new SecureRandom()); @@ -661,8 +663,8 @@ private void testECDH(String algorithm) aKeyAgree.doPhase(bKeyPair.getPublic(), true); bKeyAgree.doPhase(aKeyPair.getPublic(), true); - BigInteger k1 = new BigInteger(aKeyAgree.generateSecret()); - BigInteger k2 = new BigInteger(bKeyAgree.generateSecret()); + BigInteger k1 = new BigInteger(aKeyAgree.generateSecret()); + BigInteger k2 = new BigInteger(bKeyAgree.generateSecret()); if (!k1.equals(k2)) { @@ -672,10 +674,10 @@ private void testECDH(String algorithm) // // public key encoding test // - byte[] pubEnc = aKeyPair.getPublic().getEncoded(); - KeyFactory keyFac = KeyFactory.getInstance(algorithm, "BC"); - X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); - ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509); + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algorithm, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509); if (!pubKey.getW().equals(((ECPublicKey)aKeyPair.getPublic()).getW())) { @@ -692,9 +694,9 @@ private void testECDH(String algorithm) // // private key encoding test // - byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); - ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8); + ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8); if (!privKey.getS().equals(((ECPrivateKey)aKeyPair.getPrivate()).getS())) { @@ -756,7 +758,7 @@ private void testExceptions() private void testDESAndDESede(BigInteger g, BigInteger p) throws Exception { - DHParameterSpec dhParams = new DHParameterSpec(p, g, 256); + DHParameterSpec dhParams = new DHParameterSpec(p, g, 256); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); @@ -822,13 +824,13 @@ private void testSmallSecret() DHPrivateKeySpec aPrivSpec = new DHPrivateKeySpec( new BigInteger("30a6ea4e2240a42867ad98bd3adbfd5b81aba48bd930f20a595983d807566f7cba4e766951efef2c6c0c1be3823f63d66e12c2a091d5ff3bbeb1ea6e335d072d", 16), p, g); DHPublicKeySpec aPubSpec = new DHPublicKeySpec( - new BigInteger("694dfea1bfc8897e2fcbfd88033ab34f4581892d7d5cc362dc056e3d43955accda12222bd651ca31c85f008a05dea914de68828dfd83a54a340fa84f3bbe6caf", 16), p, g); + new BigInteger("694dfea1bfc8897e2fcbfd88033ab34f4581892d7d5cc362dc056e3d43955accda12222bd651ca31c85f008a05dea914de68828dfd83a54a340fa84f3bbe6caf", 16), p, g); DHPrivateKeySpec bPrivSpec = new DHPrivateKeySpec( - new BigInteger("775b1e7e162190700e2212dd8e4aaacf8a2af92c9c108b81d5bf9a14548f494eaa86a6c4844b9512eb3e3f2f22ffec44c795c813edfea13f075b99bbdebb34bd", 16), p, g); + new BigInteger("775b1e7e162190700e2212dd8e4aaacf8a2af92c9c108b81d5bf9a14548f494eaa86a6c4844b9512eb3e3f2f22ffec44c795c813edfea13f075b99bbdebb34bd", 16), p, g); DHPublicKeySpec bPubSpec = new DHPublicKeySpec( - new BigInteger("d8ddd4ff9246635eadbfa0bc2ef06d98a329b6e8cd2d1435d7b4921467570e697c9a9d3c172c684626a9d2b6b2fa0fc725d5b91f9a9625b717a4169bc714b064", 16), p, g); + new BigInteger("d8ddd4ff9246635eadbfa0bc2ef06d98a329b6e8cd2d1435d7b4921467570e697c9a9d3c172c684626a9d2b6b2fa0fc725d5b91f9a9625b717a4169bc714b064", 16), p, g); KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); @@ -848,7 +850,7 @@ private void testSmallSecret() private void testEnc() throws Exception { - KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); + KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); Key k = kFact.generatePrivate(new PKCS8EncodedKeySpec(samplePrivEnc)); @@ -889,9 +891,9 @@ private void testConfig() 384); DHParameterSpec dhSpec768 = new DHParameterSpec( - new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16), - new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16), - 384); + new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16), + new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16), + 384); DHParameterSpec dhSpec1024 = new DHParameterSpec( new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16), @@ -910,7 +912,7 @@ private void testConfig() fail("config found when none expected"); } - prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, new DHParameterSpec[] { dhSpec512, dhSpec768, dhSpec1024 }); + prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, new DHParameterSpec[]{dhSpec512, dhSpec768, dhSpec1024}); if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512))) { @@ -951,7 +953,7 @@ private void testConfig() fail("config found when none expected"); } - prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, new DHParameterSpec[] { dhSpec512, dhSpec768, dhSpec1024 }); + prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, new DHParameterSpec[]{dhSpec512, dhSpec768, dhSpec1024}); if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512))) { @@ -981,6 +983,109 @@ private void testConfig() } } + static final String MESSAGE = "Hello"; + + static final String PROVIDER_NAME = "BC"; + static final SecureRandom rand = new SecureRandom(); + + public void setUp() + { + // Add BouncyCastle for testing. + Security.insertProviderAt(new BouncyCastleProvider(), 1); + System.out.println("WARNING: Using BouncyCastleProvider"); + } + + public DHParameterSpec ike2048() + { + final BigInteger p = new BigInteger( + "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" + + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" + + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed" + + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05" + + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb" + + "9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3b" + + "e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695581718" + + "3995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff", 16); + final BigInteger g = new BigInteger("2"); + return new DHParameterSpec(p, g); + } + + /** + * Tests whether a provider accepts invalid public keys that result in predictable shared secrets. + * This test is based on RFC 2785, Section 4 and NIST SP 800-56A, + * If an attacker can modify both public keys in an ephemeral-ephemeral key agreement scheme then + * it may be possible to coerce both parties into computing the same predictable shared key. + * <p/> + * Note: the test is quite whimsical. If the prime p is not a safe prime then the provider itself + * cannot prevent all small-subgroup attacks because of the missing parameter q in the + * Diffie-Hellman parameters. Implementations must add additional countermeasures such as the ones + * proposed in RFC 2785. + */ + private void testSubgroupConfinement() + throws Exception + { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); + DHParameterSpec params = ike2048(); + final BigInteger p = params.getP(); + final BigInteger g = params.getG(); + keyGen.initialize(params); + PrivateKey priv = keyGen.generateKeyPair().getPrivate(); + KeyAgreement ka = KeyAgreement.getInstance("DH", "BC"); + BigInteger[] weakPublicKeys = { + BigInteger.ZERO, BigInteger.ONE, p.subtract(BigInteger.ONE), p, + p.add(BigInteger.ONE), BigInteger.ONE.negate()}; + for (final BigInteger weakKey : weakPublicKeys) + { + DHPublicKeySpec weakSpec = new DHPublicKeySpec(weakKey, p, g); + KeyFactory kf = KeyFactory.getInstance("DH", "BC"); + try + { + kf.generatePublic(weakSpec); + fail("Generated weak public key"); + } + catch (GeneralSecurityException ex) + { + isTrue("wrong message", "invalid DH public key".equals(ex.getMessage())); + } + ka.init(priv); + try + { + ka.doPhase(new DHPublicKey() + { + public BigInteger getY() + { + return weakKey; + } + + public DHParameterSpec getParams() + { + return new DHParameterSpec(p, g); + } + + public String getAlgorithm() + { + return null; + } + + public String getFormat() + { + return null; + } + + public byte[] getEncoded() + { + return new byte[0]; + } + }, true); + fail("Generated secrets with weak public key"); + } + catch (GeneralSecurityException ex) + { + isTrue("wrong message", "Invalid DH PublicKey".equals(ex.getMessage())); + } + } + } + public void performTest() throws Exception { @@ -1014,10 +1119,11 @@ public void performTest() testInitialise(); testSmallSecret(); testConfig(); + testSubgroupConfinement(); } public static void main( - String[] args) + String[] args) { Security.addProvider(new BouncyCastleProvider());
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
12- access.redhat.com/errata/RHSA-2018:2669ghsavendor-advisoryx_refsource_REDHATWEB
- access.redhat.com/errata/RHSA-2018:2927ghsavendor-advisoryx_refsource_REDHATWEB
- github.com/advisories/GHSA-c8xf-m4ff-jcxjghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-1000339ghsaADVISORY
- usn.ubuntu.com/3727-1/mitrevendor-advisoryx_refsource_UBUNTU
- github.com/bcgit/bc-java/commit/413b42f4d770456508585c830cfcde95f9b0e93bghsax_refsource_CONFIRMWEB
- github.com/bcgit/bc-java/commit/8a73f08931450c17c749af067b6a8185abdfd2c0ghsax_refsource_CONFIRMWEB
- lists.debian.org/debian-lts-announce/2018/07/msg00009.htmlghsamailing-listx_refsource_MLISTWEB
- security.netapp.com/advisory/ntap-20181127-0004ghsaWEB
- security.netapp.com/advisory/ntap-20181127-0004/mitrex_refsource_CONFIRM
- usn.ubuntu.com/3727-1ghsaWEB
- www.oracle.com/security-alerts/cpuoct2020.htmlghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.