Path: blob/master/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java
67848 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider;2627import java.math.BigInteger;28import java.security.AlgorithmParameterGeneratorSpi;29import java.security.AlgorithmParameters;30import java.security.InvalidAlgorithmParameterException;31import java.security.NoSuchAlgorithmException;32import java.security.NoSuchProviderException;33import java.security.InvalidParameterException;34import java.security.MessageDigest;35import java.security.SecureRandom;36import java.security.ProviderException;37import java.security.spec.AlgorithmParameterSpec;38import java.security.spec.InvalidParameterSpecException;39import java.security.spec.DSAParameterSpec;40import java.security.spec.DSAGenParameterSpec;4142import static sun.security.util.SecurityProviderConstants.DEF_DSA_KEY_SIZE;43import static sun.security.util.SecurityProviderConstants.getDefDSASubprimeSize;444546/**47* This class generates parameters for the DSA algorithm.48*49* @author Jan Luehe50*51*52* @see java.security.AlgorithmParameters53* @see java.security.spec.AlgorithmParameterSpec54* @see DSAParameters55*56* @since 1.257*/5859public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi {6061// the length of prime P, subPrime Q, and seed in bits62private int valueL = -1;63private int valueN = -1;64private int seedLen = -1;6566// the source of randomness67private SecureRandom random;6869public DSAParameterGenerator() {70}7172/**73* Initializes this parameter generator for a certain strength74* and source of randomness.75*76* @param strength the strength (size of prime) in bits77* @param random the source of randomness78*/79@Override80protected void engineInit(int strength, SecureRandom random) {81if ((strength != 2048) && (strength != 3072) &&82((strength < 512) || (strength > 1024) || (strength % 64 != 0))) {83throw new InvalidParameterException(84"Unexpected strength (size of prime): " + strength +85". Prime size should be 512-1024, 2048, or 3072");86}87this.valueL = strength;88this.valueN = getDefDSASubprimeSize(strength);89this.seedLen = valueN;90this.random = random;91}9293/**94* Initializes this parameter generator with a set of95* algorithm-specific parameter generation values.96*97* @param genParamSpec the set of algorithm-specific parameter98* generation values99* @param random the source of randomness100*101* @exception InvalidAlgorithmParameterException if the given parameter102* generation values are inappropriate for this parameter generator103*/104@Override105protected void engineInit(AlgorithmParameterSpec genParamSpec,106SecureRandom random) throws InvalidAlgorithmParameterException {107if (!(genParamSpec instanceof DSAGenParameterSpec)) {108throw new InvalidAlgorithmParameterException("Invalid parameter");109}110DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec)genParamSpec;111112// directly initialize using the already validated values113this.valueL = dsaGenParams.getPrimePLength();114this.valueN = dsaGenParams.getSubprimeQLength();115this.seedLen = dsaGenParams.getSeedLength();116this.random = random;117}118119/**120* Generates the parameters.121*122* @return the new AlgorithmParameters object123*/124@Override125protected AlgorithmParameters engineGenerateParameters() {126AlgorithmParameters algParams = null;127try {128if (this.random == null) {129this.random = new SecureRandom();130}131if (valueL == -1) {132engineInit(DEF_DSA_KEY_SIZE, this.random);133}134BigInteger[] pAndQ = generatePandQ(this.random, valueL,135valueN, seedLen);136BigInteger paramP = pAndQ[0];137BigInteger paramQ = pAndQ[1];138BigInteger paramG = generateG(paramP, paramQ);139140DSAParameterSpec dsaParamSpec =141new DSAParameterSpec(paramP, paramQ, paramG);142algParams = AlgorithmParameters.getInstance("DSA", "SUN");143algParams.init(dsaParamSpec);144} catch (InvalidParameterSpecException e) {145// this should never happen146throw new RuntimeException(e.getMessage());147} catch (NoSuchAlgorithmException e) {148// this should never happen, because we provide it149throw new RuntimeException(e.getMessage());150} catch (NoSuchProviderException e) {151// this should never happen, because we provide it152throw new RuntimeException(e.getMessage());153}154155return algParams;156}157158/*159* Generates the prime and subprime parameters for DSA,160* using the provided source of randomness.161* This method will generate new seeds until a suitable162* seed has been found.163*164* @param random the source of randomness to generate the165* seed166* @param valueL the size of <code>p</code>, in bits.167* @param valueN the size of <code>q</code>, in bits.168* @param seedLen the length of <code>seed</code>, in bits.169*170* @return an array of BigInteger, with <code>p</code> at index 0 and171* <code>q</code> at index 1, the seed at index 2, and the counter value172* at index 3.173*/174private static BigInteger[] generatePandQ(SecureRandom random, int valueL,175int valueN, int seedLen) {176String hashAlg = null;177if (valueN == 160) {178hashAlg = "SHA";179} else if (valueN == 224) {180hashAlg = "SHA-224";181} else if (valueN == 256) {182hashAlg = "SHA-256";183}184MessageDigest hashObj = null;185try {186hashObj = MessageDigest.getInstance(hashAlg);187} catch (NoSuchAlgorithmException nsae) {188// should never happen189}190191/* Step 3, 4: Useful variables */192int outLen = hashObj.getDigestLength()*8;193int n = (valueL - 1) / outLen;194int b = (valueL - 1) % outLen;195byte[] seedBytes = new byte[seedLen/8];196BigInteger twoSl = BigInteger.TWO.pow(seedLen);197int primeCertainty = -1;198if (valueL <= 1024) {199primeCertainty = 80;200} else if (valueL == 2048) {201primeCertainty = 112;202} else if (valueL == 3072) {203primeCertainty = 128;204}205if (primeCertainty < 0) {206throw new ProviderException("Invalid valueL: " + valueL);207}208BigInteger resultP, resultQ, seed = null;209int counter;210while (true) {211do {212/* Step 5 */213random.nextBytes(seedBytes);214seed = new BigInteger(1, seedBytes);215216/* Step 6 */217BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)).218mod(BigInteger.TWO.pow(valueN - 1));219220/* Step 7 */221resultQ = BigInteger.TWO.pow(valueN - 1)222.add(U)223.add(BigInteger.ONE)224.subtract(U.mod(BigInteger.TWO));225} while (!resultQ.isProbablePrime(primeCertainty));226227/* Step 10 */228BigInteger offset = BigInteger.ONE;229/* Step 11 */230for (counter = 0; counter < 4*valueL; counter++) {231BigInteger[] V = new BigInteger[n + 1];232/* Step 11.1 */233for (int j = 0; j <= n; j++) {234BigInteger J = BigInteger.valueOf(j);235BigInteger tmp = (seed.add(offset).add(J)).mod(twoSl);236byte[] vjBytes = hashObj.digest(toByteArray(tmp));237V[j] = new BigInteger(1, vjBytes);238}239/* Step 11.2 */240BigInteger W = V[0];241for (int i = 1; i < n; i++) {242W = W.add(V[i].multiply(BigInteger.TWO.pow(i * outLen)));243}244W = W.add((V[n].mod(BigInteger.TWO.pow(b)))245.multiply(BigInteger.TWO.pow(n * outLen)));246/* Step 11.3 */247BigInteger twoLm1 = BigInteger.TWO.pow(valueL - 1);248BigInteger X = W.add(twoLm1);249/* Step 11.4, 11.5 */250BigInteger c = X.mod(resultQ.multiply(BigInteger.TWO));251resultP = X.subtract(c.subtract(BigInteger.ONE));252/* Step 11.6, 11.7 */253if (resultP.compareTo(twoLm1) > -1254&& resultP.isProbablePrime(primeCertainty)) {255/* Step 11.8 */256BigInteger[] result = {resultP, resultQ, seed,257BigInteger.valueOf(counter)};258return result;259}260/* Step 11.9 */261offset = offset.add(BigInteger.valueOf(n)).add(BigInteger.ONE);262}263}264265}266267/*268* Generates the <code>g</code> parameter for DSA.269*270* @param p the prime, <code>p</code>.271* @param q the subprime, <code>q</code>.272*273* @param the <code>g</code>274*/275private static BigInteger generateG(BigInteger p, BigInteger q) {276BigInteger h = BigInteger.ONE;277/* Step 1 */278BigInteger pMinusOneOverQ = (p.subtract(BigInteger.ONE)).divide(q);279BigInteger resultG = BigInteger.ONE;280while (resultG.compareTo(BigInteger.TWO) < 0) {281/* Step 3 */282resultG = h.modPow(pMinusOneOverQ, p);283h = h.add(BigInteger.ONE);284}285return resultG;286}287288/*289* Converts the result of a BigInteger.toByteArray call to an exact290* signed magnitude representation for any positive number.291*/292private static byte[] toByteArray(BigInteger bigInt) {293byte[] result = bigInt.toByteArray();294if (result[0] == 0) {295byte[] tmp = new byte[result.length - 1];296System.arraycopy(result, 1, tmp, 0, tmp.length);297result = tmp;298}299return result;300}301}302303304