|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.provider; |
|
|
|
import java.math.BigInteger; |
|
import java.security.AlgorithmParameterGeneratorSpi; |
|
import java.security.AlgorithmParameters; |
|
import java.security.InvalidAlgorithmParameterException; |
|
import java.security.NoSuchAlgorithmException; |
|
import java.security.NoSuchProviderException; |
|
import java.security.InvalidParameterException; |
|
import java.security.MessageDigest; |
|
import java.security.SecureRandom; |
|
import java.security.ProviderException; |
|
import java.security.spec.AlgorithmParameterSpec; |
|
import java.security.spec.InvalidParameterSpecException; |
|
import java.security.spec.DSAParameterSpec; |
|
import java.security.spec.DSAGenParameterSpec; |
|
|
|
import static sun.security.util.SecurityProviderConstants.DEF_DSA_KEY_SIZE; |
|
import static sun.security.util.SecurityProviderConstants.getDefDSASubprimeSize; |
|
|
|
|
|
/** |
|
* This class generates parameters for the DSA algorithm. |
|
* |
|
* @author Jan Luehe |
|
* |
|
* |
|
* @see java.security.AlgorithmParameters |
|
* @see java.security.spec.AlgorithmParameterSpec |
|
* @see DSAParameters |
|
* |
|
* @since 1.2 |
|
*/ |
|
|
|
public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { |
|
|
|
|
|
private int valueL = -1; |
|
private int valueN = -1; |
|
private int seedLen = -1; |
|
|
|
|
|
private SecureRandom random; |
|
|
|
public DSAParameterGenerator() { |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
protected void engineInit(int strength, SecureRandom random) { |
|
if ((strength != 2048) && (strength != 3072) && |
|
((strength < 512) || (strength > 1024) || (strength % 64 != 0))) { |
|
throw new InvalidParameterException( |
|
"Unexpected strength (size of prime): " + strength + |
|
". Prime size should be 512-1024, 2048, or 3072"); |
|
} |
|
this.valueL = strength; |
|
this.valueN = getDefDSASubprimeSize(strength); |
|
this.seedLen = valueN; |
|
this.random = random; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
protected void engineInit(AlgorithmParameterSpec genParamSpec, |
|
SecureRandom random) throws InvalidAlgorithmParameterException { |
|
if (!(genParamSpec instanceof DSAGenParameterSpec)) { |
|
throw new InvalidAlgorithmParameterException("Invalid parameter"); |
|
} |
|
DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec)genParamSpec; |
|
|
|
|
|
this.valueL = dsaGenParams.getPrimePLength(); |
|
this.valueN = dsaGenParams.getSubprimeQLength(); |
|
this.seedLen = dsaGenParams.getSeedLength(); |
|
this.random = random; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
protected AlgorithmParameters engineGenerateParameters() { |
|
AlgorithmParameters algParams = null; |
|
try { |
|
if (this.random == null) { |
|
this.random = new SecureRandom(); |
|
} |
|
if (valueL == -1) { |
|
engineInit(DEF_DSA_KEY_SIZE, this.random); |
|
} |
|
BigInteger[] pAndQ = generatePandQ(this.random, valueL, |
|
valueN, seedLen); |
|
BigInteger paramP = pAndQ[0]; |
|
BigInteger paramQ = pAndQ[1]; |
|
BigInteger paramG = generateG(paramP, paramQ); |
|
|
|
DSAParameterSpec dsaParamSpec = |
|
new DSAParameterSpec(paramP, paramQ, paramG); |
|
algParams = AlgorithmParameters.getInstance("DSA", "SUN"); |
|
algParams.init(dsaParamSpec); |
|
} catch (InvalidParameterSpecException e) { |
|
|
|
throw new RuntimeException(e.getMessage()); |
|
} catch (NoSuchAlgorithmException e) { |
|
|
|
throw new RuntimeException(e.getMessage()); |
|
} catch (NoSuchProviderException e) { |
|
|
|
throw new RuntimeException(e.getMessage()); |
|
} |
|
|
|
return algParams; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static BigInteger[] generatePandQ(SecureRandom random, int valueL, |
|
int valueN, int seedLen) { |
|
String hashAlg = null; |
|
if (valueN == 160) { |
|
hashAlg = "SHA"; |
|
} else if (valueN == 224) { |
|
hashAlg = "SHA-224"; |
|
} else if (valueN == 256) { |
|
hashAlg = "SHA-256"; |
|
} |
|
MessageDigest hashObj = null; |
|
try { |
|
hashObj = MessageDigest.getInstance(hashAlg); |
|
} catch (NoSuchAlgorithmException nsae) { |
|
|
|
nsae.printStackTrace(); |
|
} |
|
|
|
|
|
int outLen = hashObj.getDigestLength()*8; |
|
int n = (valueL - 1) / outLen; |
|
int b = (valueL - 1) % outLen; |
|
byte[] seedBytes = new byte[seedLen/8]; |
|
BigInteger twoSl = BigInteger.TWO.pow(seedLen); |
|
int primeCertainty = -1; |
|
if (valueL <= 1024) { |
|
primeCertainty = 80; |
|
} else if (valueL == 2048) { |
|
primeCertainty = 112; |
|
} else if (valueL == 3072) { |
|
primeCertainty = 128; |
|
} |
|
if (primeCertainty < 0) { |
|
throw new ProviderException("Invalid valueL: " + valueL); |
|
} |
|
BigInteger resultP, resultQ, seed = null; |
|
int counter; |
|
while (true) { |
|
do { |
|
|
|
random.nextBytes(seedBytes); |
|
seed = new BigInteger(1, seedBytes); |
|
|
|
|
|
BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)). |
|
mod(BigInteger.TWO.pow(valueN - 1)); |
|
|
|
|
|
resultQ = BigInteger.TWO.pow(valueN - 1) |
|
.add(U) |
|
.add(BigInteger.ONE) |
|
.subtract(U.mod(BigInteger.TWO)); |
|
} while (!resultQ.isProbablePrime(primeCertainty)); |
|
|
|
|
|
BigInteger offset = BigInteger.ONE; |
|
|
|
for (counter = 0; counter < 4*valueL; counter++) { |
|
BigInteger[] V = new BigInteger[n + 1]; |
|
|
|
for (int j = 0; j <= n; j++) { |
|
BigInteger J = BigInteger.valueOf(j); |
|
BigInteger tmp = (seed.add(offset).add(J)).mod(twoSl); |
|
byte[] vjBytes = hashObj.digest(toByteArray(tmp)); |
|
V[j] = new BigInteger(1, vjBytes); |
|
} |
|
|
|
BigInteger W = V[0]; |
|
for (int i = 1; i < n; i++) { |
|
W = W.add(V[i].multiply(BigInteger.TWO.pow(i * outLen))); |
|
} |
|
W = W.add((V[n].mod(BigInteger.TWO.pow(b))) |
|
.multiply(BigInteger.TWO.pow(n * outLen))); |
|
|
|
BigInteger twoLm1 = BigInteger.TWO.pow(valueL - 1); |
|
BigInteger X = W.add(twoLm1); |
|
|
|
BigInteger c = X.mod(resultQ.multiply(BigInteger.TWO)); |
|
resultP = X.subtract(c.subtract(BigInteger.ONE)); |
|
|
|
if (resultP.compareTo(twoLm1) > -1 |
|
&& resultP.isProbablePrime(primeCertainty)) { |
|
|
|
BigInteger[] result = {resultP, resultQ, seed, |
|
BigInteger.valueOf(counter)}; |
|
return result; |
|
} |
|
|
|
offset = offset.add(BigInteger.valueOf(n)).add(BigInteger.ONE); |
|
} |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static BigInteger generateG(BigInteger p, BigInteger q) { |
|
BigInteger h = BigInteger.ONE; |
|
|
|
BigInteger pMinusOneOverQ = (p.subtract(BigInteger.ONE)).divide(q); |
|
BigInteger resultG = BigInteger.ONE; |
|
while (resultG.compareTo(BigInteger.TWO) < 0) { |
|
|
|
resultG = h.modPow(pMinusOneOverQ, p); |
|
h = h.add(BigInteger.ONE); |
|
} |
|
return resultG; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private static byte[] toByteArray(BigInteger bigInt) { |
|
byte[] result = bigInt.toByteArray(); |
|
if (result[0] == 0) { |
|
byte[] tmp = new byte[result.length - 1]; |
|
System.arraycopy(result, 1, tmp, 0, tmp.length); |
|
result = tmp; |
|
} |
|
return result; |
|
} |
|
} |