Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/provider/DSAParameterGenerator.java
38830 views
/*1* Copyright (c) 1997, 2017, 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;6869// useful constants70private static final BigInteger TWO = BigInteger.valueOf(2);7172public DSAParameterGenerator() {73}7475/**76* Initializes this parameter generator for a certain strength77* and source of randomness.78*79* @param strength the strength (size of prime) in bits80* @param random the source of randomness81*/82@Override83protected void engineInit(int strength, SecureRandom random) {84if ((strength != 2048) && (strength != 3072) &&85((strength < 512) || (strength > 1024) || (strength % 64 != 0))) {86throw new InvalidParameterException(87"Unexpected strength (size of prime): " + strength +88". Prime size should be 512-1024, 2048, or 3072");89}90this.valueL = strength;91this.valueN = getDefDSASubprimeSize(strength);92this.seedLen = valueN;93this.random = random;94}9596/**97* Initializes this parameter generator with a set of98* algorithm-specific parameter generation values.99*100* @param genParamSpec the set of algorithm-specific parameter101* generation values102* @param random the source of randomness103*104* @exception InvalidAlgorithmParameterException if the given parameter105* generation values are inappropriate for this parameter generator106*/107@Override108protected void engineInit(AlgorithmParameterSpec genParamSpec,109SecureRandom random) throws InvalidAlgorithmParameterException {110if (!(genParamSpec instanceof DSAGenParameterSpec)) {111throw new InvalidAlgorithmParameterException("Invalid parameter");112}113DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec)genParamSpec;114115// directly initialize using the already validated values116this.valueL = dsaGenParams.getPrimePLength();117this.valueN = dsaGenParams.getSubprimeQLength();118this.seedLen = dsaGenParams.getSeedLength();119this.random = random;120}121122/**123* Generates the parameters.124*125* @return the new AlgorithmParameters object126*/127@Override128protected AlgorithmParameters engineGenerateParameters() {129AlgorithmParameters algParams = null;130try {131if (this.random == null) {132this.random = new SecureRandom();133}134if (valueL == -1) {135engineInit(DEF_DSA_KEY_SIZE, this.random);136}137BigInteger[] pAndQ = generatePandQ(this.random, valueL,138valueN, seedLen);139BigInteger paramP = pAndQ[0];140BigInteger paramQ = pAndQ[1];141BigInteger paramG = generateG(paramP, paramQ);142143DSAParameterSpec dsaParamSpec =144new DSAParameterSpec(paramP, paramQ, paramG);145algParams = AlgorithmParameters.getInstance("DSA", "SUN");146algParams.init(dsaParamSpec);147} catch (InvalidParameterSpecException e) {148// this should never happen149throw new RuntimeException(e.getMessage());150} catch (NoSuchAlgorithmException e) {151// this should never happen, because we provide it152throw new RuntimeException(e.getMessage());153} catch (NoSuchProviderException e) {154// this should never happen, because we provide it155throw new RuntimeException(e.getMessage());156}157158return algParams;159}160161/*162* Generates the prime and subprime parameters for DSA,163* using the provided source of randomness.164* This method will generate new seeds until a suitable165* seed has been found.166*167* @param random the source of randomness to generate the168* seed169* @param valueL the size of <code>p</code>, in bits.170* @param valueN the size of <code>q</code>, in bits.171* @param seedLen the length of <code>seed</code>, in bits.172*173* @return an array of BigInteger, with <code>p</code> at index 0 and174* <code>q</code> at index 1, the seed at index 2, and the counter value175* at index 3.176*/177private static BigInteger[] generatePandQ(SecureRandom random, int valueL,178int valueN, int seedLen) {179String hashAlg = null;180if (valueN == 160) {181hashAlg = "SHA";182} else if (valueN == 224) {183hashAlg = "SHA-224";184} else if (valueN == 256) {185hashAlg = "SHA-256";186}187MessageDigest hashObj = null;188try {189hashObj = MessageDigest.getInstance(hashAlg);190} catch (NoSuchAlgorithmException nsae) {191// should never happen192nsae.printStackTrace();193}194195/* Step 3, 4: Useful variables */196int outLen = hashObj.getDigestLength()*8;197int n = (valueL - 1) / outLen;198int b = (valueL - 1) % outLen;199byte[] seedBytes = new byte[seedLen/8];200BigInteger twoSl = TWO.pow(seedLen);201int primeCertainty = -1;202if (valueL <= 1024) {203primeCertainty = 80;204} else if (valueL == 2048) {205primeCertainty = 112;206} else if (valueL == 3072) {207primeCertainty = 128;208}209if (primeCertainty < 0) {210throw new ProviderException("Invalid valueL: " + valueL);211}212BigInteger resultP, resultQ, seed = null;213int counter;214while (true) {215do {216/* Step 5 */217random.nextBytes(seedBytes);218seed = new BigInteger(1, seedBytes);219220/* Step 6 */221BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)).222mod(TWO.pow(valueN - 1));223224/* Step 7 */225resultQ = TWO.pow(valueN - 1)226.add(U)227.add(BigInteger.ONE)228.subtract(U.mod(TWO));229} while (!resultQ.isProbablePrime(primeCertainty));230231/* Step 10 */232BigInteger offset = BigInteger.ONE;233/* Step 11 */234for (counter = 0; counter < 4*valueL; counter++) {235BigInteger V[] = new BigInteger[n + 1];236/* Step 11.1 */237for (int j = 0; j <= n; j++) {238BigInteger J = BigInteger.valueOf(j);239BigInteger tmp = (seed.add(offset).add(J)).mod(twoSl);240byte[] vjBytes = hashObj.digest(toByteArray(tmp));241V[j] = new BigInteger(1, vjBytes);242}243/* Step 11.2 */244BigInteger W = V[0];245for (int i = 1; i < n; i++) {246W = W.add(V[i].multiply(TWO.pow(i * outLen)));247}248W = W.add((V[n].mod(TWO.pow(b)))249.multiply(TWO.pow(n * outLen)));250/* Step 11.3 */251BigInteger twoLm1 = TWO.pow(valueL - 1);252BigInteger X = W.add(twoLm1);253/* Step 11.4, 11.5 */254BigInteger c = X.mod(resultQ.multiply(TWO));255resultP = X.subtract(c.subtract(BigInteger.ONE));256/* Step 11.6, 11.7 */257if (resultP.compareTo(twoLm1) > -1258&& resultP.isProbablePrime(primeCertainty)) {259/* Step 11.8 */260BigInteger[] result = {resultP, resultQ, seed,261BigInteger.valueOf(counter)};262return result;263}264/* Step 11.9 */265offset = offset.add(BigInteger.valueOf(n)).add(BigInteger.ONE);266}267}268269}270271/*272* Generates the <code>g</code> parameter for DSA.273*274* @param p the prime, <code>p</code>.275* @param q the subprime, <code>q</code>.276*277* @param the <code>g</code>278*/279private static BigInteger generateG(BigInteger p, BigInteger q) {280BigInteger h = BigInteger.ONE;281/* Step 1 */282BigInteger pMinusOneOverQ = (p.subtract(BigInteger.ONE)).divide(q);283BigInteger resultG = BigInteger.ONE;284while (resultG.compareTo(TWO) < 0) {285/* Step 3 */286resultG = h.modPow(pMinusOneOverQ, p);287h = h.add(BigInteger.ONE);288}289return resultG;290}291292/*293* Converts the result of a BigInteger.toByteArray call to an exact294* signed magnitude representation for any positive number.295*/296private static byte[] toByteArray(BigInteger bigInt) {297byte[] result = bigInt.toByteArray();298if (result[0] == 0) {299byte[] tmp = new byte[result.length - 1];300System.arraycopy(result, 1, tmp, 0, tmp.length);301result = tmp;302}303return result;304}305}306307308