Path: blob/master/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java
41159 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;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 happen189nsae.printStackTrace();190}191192/* Step 3, 4: Useful variables */193int outLen = hashObj.getDigestLength()*8;194int n = (valueL - 1) / outLen;195int b = (valueL - 1) % outLen;196byte[] seedBytes = new byte[seedLen/8];197BigInteger twoSl = BigInteger.TWO.pow(seedLen);198int primeCertainty = -1;199if (valueL <= 1024) {200primeCertainty = 80;201} else if (valueL == 2048) {202primeCertainty = 112;203} else if (valueL == 3072) {204primeCertainty = 128;205}206if (primeCertainty < 0) {207throw new ProviderException("Invalid valueL: " + valueL);208}209BigInteger resultP, resultQ, seed = null;210int counter;211while (true) {212do {213/* Step 5 */214random.nextBytes(seedBytes);215seed = new BigInteger(1, seedBytes);216217/* Step 6 */218BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)).219mod(BigInteger.TWO.pow(valueN - 1));220221/* Step 7 */222resultQ = BigInteger.TWO.pow(valueN - 1)223.add(U)224.add(BigInteger.ONE)225.subtract(U.mod(BigInteger.TWO));226} while (!resultQ.isProbablePrime(primeCertainty));227228/* Step 10 */229BigInteger offset = BigInteger.ONE;230/* Step 11 */231for (counter = 0; counter < 4*valueL; counter++) {232BigInteger[] V = new BigInteger[n + 1];233/* Step 11.1 */234for (int j = 0; j <= n; j++) {235BigInteger J = BigInteger.valueOf(j);236BigInteger tmp = (seed.add(offset).add(J)).mod(twoSl);237byte[] vjBytes = hashObj.digest(toByteArray(tmp));238V[j] = new BigInteger(1, vjBytes);239}240/* Step 11.2 */241BigInteger W = V[0];242for (int i = 1; i < n; i++) {243W = W.add(V[i].multiply(BigInteger.TWO.pow(i * outLen)));244}245W = W.add((V[n].mod(BigInteger.TWO.pow(b)))246.multiply(BigInteger.TWO.pow(n * outLen)));247/* Step 11.3 */248BigInteger twoLm1 = BigInteger.TWO.pow(valueL - 1);249BigInteger X = W.add(twoLm1);250/* Step 11.4, 11.5 */251BigInteger c = X.mod(resultQ.multiply(BigInteger.TWO));252resultP = X.subtract(c.subtract(BigInteger.ONE));253/* Step 11.6, 11.7 */254if (resultP.compareTo(twoLm1) > -1255&& resultP.isProbablePrime(primeCertainty)) {256/* Step 11.8 */257BigInteger[] result = {resultP, resultQ, seed,258BigInteger.valueOf(counter)};259return result;260}261/* Step 11.9 */262offset = offset.add(BigInteger.valueOf(n)).add(BigInteger.ONE);263}264}265266}267268/*269* Generates the <code>g</code> parameter for DSA.270*271* @param p the prime, <code>p</code>.272* @param q the subprime, <code>q</code>.273*274* @param the <code>g</code>275*/276private static BigInteger generateG(BigInteger p, BigInteger q) {277BigInteger h = BigInteger.ONE;278/* Step 1 */279BigInteger pMinusOneOverQ = (p.subtract(BigInteger.ONE)).divide(q);280BigInteger resultG = BigInteger.ONE;281while (resultG.compareTo(BigInteger.TWO) < 0) {282/* Step 3 */283resultG = h.modPow(pMinusOneOverQ, p);284h = h.add(BigInteger.ONE);285}286return resultG;287}288289/*290* Converts the result of a BigInteger.toByteArray call to an exact291* signed magnitude representation for any positive number.292*/293private static byte[] toByteArray(BigInteger bigInt) {294byte[] result = bigInt.toByteArray();295if (result[0] == 0) {296byte[] tmp = new byte[result.length - 1];297System.arraycopy(result, 1, tmp, 0, tmp.length);298result = tmp;299}300return result;301}302}303304305