From 6c5aefe60c8d294631c716c63ec411feb7f7a4ea Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 7 Oct 2022 22:25:38 +0000 Subject: [PATCH] 8293554: Enhanced DH Key Exchanges Reviewed-by: rhalade, mschoene, ascarpino, weijun --- .../crypto/provider/DHKeyPairGenerator.java | 56 +++++++++---------- .../crypto/provider/DHParameterGenerator.java | 31 +++++----- .../sun/security/provider/ParameterCache.java | 29 ++++++---- .../ssl/PredefinedDHParameterSpecs.java | 11 ++-- .../util/SecurityProviderConstants.java | 24 ++++++++ 5 files changed, 91 insertions(+), 60 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java index 98b54784587..d78c0204382 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java @@ -34,6 +34,7 @@ import javax.crypto.spec.DHGenParameterSpec; import sun.security.provider.ParameterCache; import static sun.security.util.SecurityProviderConstants.DEF_DH_KEY_SIZE; +import static sun.security.util.SecurityProviderConstants.getDefDHPrivateExpSize; /** * This class represents the key pair generator for Diffie-Hellman key pairs. @@ -71,7 +72,8 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { initialize(DEF_DH_KEY_SIZE, null); } - private static void checkKeySize(int keysize) + // pkg private; used by DHParameterGenerator class as well + static void checkKeySize(int keysize, int expSize) throws InvalidParameterException { if ((keysize < 512) || (keysize > 8192) || ((keysize & 0x3F) != 0)) { @@ -80,6 +82,13 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { "from 512 to 8192 (inclusive). " + "The specific key size " + keysize + " is not supported"); } + + // optional, could be 0 if not specified + if ((expSize < 0) || (expSize > keysize)) { + throw new InvalidParameterException + ("Exponent size must be positive and no larger than" + + " modulus size"); + } } /** @@ -91,21 +100,18 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { * @param random the source of randomness */ public void initialize(int keysize, SecureRandom random) { - checkKeySize(keysize); + checkKeySize(keysize, 0); - // Use the built-in parameters (ranging from 512 to 8192) - // when available. - this.params = ParameterCache.getCachedDHParameterSpec(keysize); - - // Due to performance issue, only support DH parameters generation - // up to 1024 bits. - if ((this.params == null) && (keysize > 1024)) { - throw new InvalidParameterException( - "Unsupported " + keysize + "-bit DH parameter generation"); + try { + // Use the built-in parameters (ranging from 512 to 8192) + // when available. + this.params = ParameterCache.getDHParameterSpec(keysize, random); + } catch (GeneralSecurityException e) { + throw new InvalidParameterException(e.getMessage()); } this.pSize = keysize; - this.lSize = 0; + this.lSize = params.getL(); this.random = random; } @@ -130,22 +136,14 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { ("Inappropriate parameter type"); } - params = (DHParameterSpec)algParams; + params = (DHParameterSpec) algParams; pSize = params.getP().bitLength(); + lSize = params.getL(); try { - checkKeySize(pSize); + checkKeySize(pSize, lSize); } catch (InvalidParameterException ipe) { throw new InvalidAlgorithmParameterException(ipe.getMessage()); } - - // exponent size is optional, could be 0 - lSize = params.getL(); - - // Require exponentSize < primeSize - if ((lSize != 0) && (lSize > pSize)) { - throw new InvalidAlgorithmParameterException - ("Exponent size must not be larger than modulus size"); - } this.random = random; } @@ -159,24 +157,20 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { random = SunJCE.getRandom(); } - if (params == null) { + if (params == null) { // when init() not called try { params = ParameterCache.getDHParameterSpec(pSize, random); + lSize = params.getL(); } catch (GeneralSecurityException e) { // should never happen throw new ProviderException(e); } } - BigInteger p = params.getP(); BigInteger g = params.getG(); - if (lSize <= 0) { - lSize = pSize >> 1; - // use an exponent size of (pSize / 2) but at least 384 bits - if (lSize < 384) { - lSize = 384; - } + if (lSize == 0) { // not specified; use our own default + lSize = getDefDHPrivateExpSize(pSize); } BigInteger x; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHParameterGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/DHParameterGenerator.java index 293dfd895a3..5dd30ced4ff 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHParameterGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHParameterGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ public final class DHParameterGenerator extends AlgorithmParameterGeneratorSpi { // The source of randomness private SecureRandom random = null; - private static void checkKeySize(int keysize) + private static void checkSupport(int keysize, int exponentSize) throws InvalidParameterException { boolean supported = ((keysize == 2048) || (keysize == 3072) || @@ -67,9 +67,13 @@ public final class DHParameterGenerator extends AlgorithmParameterGeneratorSpi { if (!supported) { throw new InvalidParameterException( - "DH key size must be multiple of 64 and range " + + "Supported DH key size must be multiple of 64 and range " + "from 512 to 1024 (inclusive), or 2048, 3072. " + - "The specific key size " + keysize + " is not supported"); + "The specified key size " + keysize + " is not supported"); + } + + if (exponentSize != 0) { + DHKeyPairGenerator.checkKeySize(keysize, exponentSize); } } @@ -83,7 +87,8 @@ public final class DHParameterGenerator extends AlgorithmParameterGeneratorSpi { */ @Override protected void engineInit(int keysize, SecureRandom random) { - checkKeySize(keysize); + checkSupport(keysize, 0); + this.primeSize = keysize; this.random = random; } @@ -108,21 +113,17 @@ public final class DHParameterGenerator extends AlgorithmParameterGeneratorSpi { ("Inappropriate parameter type"); } - DHGenParameterSpec dhParamSpec = (DHGenParameterSpec)genParamSpec; - primeSize = dhParamSpec.getPrimeSize(); - exponentSize = dhParamSpec.getExponentSize(); - if ((exponentSize <= 0) || (exponentSize >= primeSize)) { - throw new InvalidAlgorithmParameterException( - "Exponent size (" + exponentSize + - ") must be positive and less than modulus size (" + - primeSize + ")"); - } + DHGenParameterSpec dhParamSpec = (DHGenParameterSpec) genParamSpec; + int primeSize = dhParamSpec.getPrimeSize(); + int exponentSize = dhParamSpec.getExponentSize(); try { - checkKeySize(primeSize); + checkSupport(primeSize, exponentSize); } catch (InvalidParameterException ipe) { throw new InvalidAlgorithmParameterException(ipe.getMessage()); } + this.primeSize = primeSize; + this.exponentSize = exponentSize; this.random = random; } diff --git a/src/java.base/share/classes/sun/security/provider/ParameterCache.java b/src/java.base/share/classes/sun/security/provider/ParameterCache.java index 942e4bc47e9..ed6efae16cf 100644 --- a/src/java.base/share/classes/sun/security/provider/ParameterCache.java +++ b/src/java.base/share/classes/sun/security/provider/ParameterCache.java @@ -34,6 +34,7 @@ import java.security.SecureRandom; import java.security.spec.*; import javax.crypto.spec.DHParameterSpec; +import static sun.security.util.SecurityProviderConstants.getDefDHPrivateExpSize; /** * Cache for DSA and DH parameter specs. Used by the KeyPairGenerators @@ -562,15 +563,23 @@ public final class ParameterCache { "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16); // use DSA parameters for DH for sizes not defined in RFC 7296, 3526 - dhCache.put(Integer.valueOf(512), new DHParameterSpec(p512, g512)); - - dhCache.put(Integer.valueOf(768), new DHParameterSpec(dhP768, dhG)); - dhCache.put(Integer.valueOf(1024), new DHParameterSpec(dhP1024, dhG)); - dhCache.put(Integer.valueOf(1536), new DHParameterSpec(dhP1536, dhG)); - dhCache.put(Integer.valueOf(2048), new DHParameterSpec(dhP2048, dhG)); - dhCache.put(Integer.valueOf(3072), new DHParameterSpec(dhP3072, dhG)); - dhCache.put(Integer.valueOf(4096), new DHParameterSpec(dhP4096, dhG)); - dhCache.put(Integer.valueOf(6144), new DHParameterSpec(dhP6144, dhG)); - dhCache.put(Integer.valueOf(8192), new DHParameterSpec(dhP8192, dhG)); + dhCache.put(Integer.valueOf(512), new DHParameterSpec(p512, g512, + getDefDHPrivateExpSize(512))); + dhCache.put(Integer.valueOf(768), new DHParameterSpec(dhP768, dhG, + getDefDHPrivateExpSize(768))); + dhCache.put(Integer.valueOf(1024), new DHParameterSpec(dhP1024, dhG, + getDefDHPrivateExpSize(1024))); + dhCache.put(Integer.valueOf(1536), new DHParameterSpec(dhP1536, dhG, + getDefDHPrivateExpSize(1536))); + dhCache.put(Integer.valueOf(2048), new DHParameterSpec(dhP2048, dhG, + getDefDHPrivateExpSize(2048))); + dhCache.put(Integer.valueOf(3072), new DHParameterSpec(dhP3072, dhG, + getDefDHPrivateExpSize(3072))); + dhCache.put(Integer.valueOf(4096), new DHParameterSpec(dhP4096, dhG, + getDefDHPrivateExpSize(4096))); + dhCache.put(Integer.valueOf(6144), new DHParameterSpec(dhP6144, dhG, + getDefDHPrivateExpSize(6144))); + dhCache.put(Integer.valueOf(8192), new DHParameterSpec(dhP8192, dhG, + getDefDHPrivateExpSize(8192))); } } diff --git a/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java b/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java index 97231e25977..2a8b5209f2e 100644 --- a/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java +++ b/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java @@ -33,6 +33,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.crypto.spec.DHParameterSpec; +import static sun.security.util.SecurityProviderConstants.getDefDHPrivateExpSize; /** * Predefined default DH ephemeral parameters. @@ -280,8 +281,9 @@ final class PredefinedDHParameterSpecs { String baseGenerator = paramsFinder.group(2); BigInteger g = new BigInteger(baseGenerator, 16); - DHParameterSpec spec = new DHParameterSpec(p, g); int primeLen = p.bitLength(); + DHParameterSpec spec = new DHParameterSpec(p, g, + getDefDHPrivateExpSize(primeLen)); defaultParams.put(primeLen, spec); } } else if (SSLLogger.isOn && SSLLogger.isOn("sslctx")) { @@ -293,7 +295,8 @@ final class PredefinedDHParameterSpecs { Map tempFFDHEs = new HashMap<>(); for (BigInteger p : ffdhePrimes) { int primeLen = p.bitLength(); - DHParameterSpec dhps = new DHParameterSpec(p, BigInteger.TWO); + DHParameterSpec dhps = new DHParameterSpec(p, BigInteger.TWO, + getDefDHPrivateExpSize(primeLen)); tempFFDHEs.put(primeLen, dhps); defaultParams.putIfAbsent(primeLen, dhps); } @@ -301,8 +304,8 @@ final class PredefinedDHParameterSpecs { for (BigInteger p : supportedPrimes) { int primeLen = p.bitLength(); if (defaultParams.get(primeLen) == null) { - defaultParams.put(primeLen, - new DHParameterSpec(p, BigInteger.TWO)); + defaultParams.put(primeLen, new DHParameterSpec(p, + BigInteger.TWO, getDefDHPrivateExpSize(primeLen))); } } diff --git a/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java b/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java index 1e0e936fd63..b3b2c5c9b0b 100644 --- a/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java +++ b/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java @@ -102,6 +102,30 @@ public final class SecurityProviderConstants { } } + public static final int getDefDHPrivateExpSize(int dhGroupSize) { + // use 2*security strength as default private exponent size + // as in table 2 of NIST SP 800-57 part 1 rev 5, sec 5.6.1.1 + // and table 25 of NIST SP 800-56A rev 3, appendix D. + if (dhGroupSize >= 15360) { + return 512; + } else if (dhGroupSize >= 8192) { + return 400; + } else if (dhGroupSize >= 7680) { + return 384; + } else if (dhGroupSize >= 6144) { + return 352; + } else if (dhGroupSize >= 4096) { + return 304; + } else if (dhGroupSize >= 3072) { + return 256; + } else if (dhGroupSize >= 2048) { + return 224; + } else { + // min value for legacy key sizes + return 160; + } + } + public static final int getDefAESKeySize() { int currVal = DEF_AES_KEY_SIZE.get(); if (currVal == -1) {