1 package org.bouncycastle.jcajce.provider.asymmetric.dsa; 2 3 import java.security.InvalidAlgorithmParameterException; 4 import java.security.InvalidParameterException; 5 import java.security.KeyPair; 6 import java.security.SecureRandom; 7 import java.security.spec.AlgorithmParameterSpec; 8 import java.security.spec.DSAParameterSpec; 9 import java.util.Hashtable; 10 11 import org.bouncycastle.crypto.AsymmetricCipherKeyPair; 12 import org.bouncycastle.crypto.digests.SHA256Digest; 13 import org.bouncycastle.crypto.generators.DSAKeyPairGenerator; 14 import org.bouncycastle.crypto.generators.DSAParametersGenerator; 15 import org.bouncycastle.crypto.params.DSAKeyGenerationParameters; 16 import org.bouncycastle.crypto.params.DSAParameterGenerationParameters; 17 import org.bouncycastle.crypto.params.DSAParameters; 18 import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; 19 import org.bouncycastle.crypto.params.DSAPublicKeyParameters; 20 import org.bouncycastle.jcajce.provider.asymmetric.util.PrimeCertaintyCalculator; 21 import org.bouncycastle.util.Integers; 22 import org.bouncycastle.util.Properties; 23 24 public class KeyPairGeneratorSpi 25 extends java.security.KeyPairGenerator 26 { 27 private static Hashtable params = new Hashtable(); 28 private static Object lock = new Object(); 29 30 DSAKeyGenerationParameters param; 31 DSAKeyPairGenerator engine = new DSAKeyPairGenerator(); 32 // Android-changed: Change default strength to 1024 33 // In 1.57, the default strength was changed to 2048. We keep it at 1024 for app 34 // compatibility, particularly because the default digest (SHA-1) doesn't have 35 // a sufficiently long digest to work with 2048-bit keys. 36 int strength = 1024; 37 38 SecureRandom random = new SecureRandom(); 39 boolean initialised = false; 40 41 public KeyPairGeneratorSpi() 42 { 43 super("DSA"); 44 } 45 46 public void initialize( 47 int strength, 48 SecureRandom random) 49 { 50 if (strength < 512 || strength > 4096 || ((strength < 1024) && strength % 64 != 0) || (strength >= 1024 && strength % 1024 != 0)) 51 { 52 throw new InvalidParameterException("strength must be from 512 - 4096 and a multiple of 1024 above 1024"); 53 } 54 55 this.strength = strength; 56 this.random = random; 57 this.initialised = false; 58 } 59 60 public void initialize( 61 AlgorithmParameterSpec params, 62 SecureRandom random) 63 throws InvalidAlgorithmParameterException 64 { 65 if (!(params instanceof DSAParameterSpec)) 66 { 67 throw new InvalidAlgorithmParameterException("parameter object not a DSAParameterSpec"); 68 } 69 DSAParameterSpec dsaParams = (DSAParameterSpec)params; 70 71 param = new DSAKeyGenerationParameters(random, new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG())); 72 73 engine.init(param); 74 initialised = true; 75 } 76 77 public KeyPair generateKeyPair() 78 { 79 if (!initialised) 80 { 81 Integer paramStrength = Integers.valueOf(strength); 82 83 if (params.containsKey(paramStrength)) 84 { 85 param = (DSAKeyGenerationParameters)params.get(paramStrength); 86 } 87 else 88 { 89 synchronized (lock) 90 { 91 // we do the check again in case we were blocked by a generator for 92 // our key size. 93 if (params.containsKey(paramStrength)) 94 { 95 param = (DSAKeyGenerationParameters)params.get(paramStrength); 96 } 97 else 98 { 99 DSAParametersGenerator pGen; 100 DSAParameterGenerationParameters dsaParams; 101 102 int certainty = PrimeCertaintyCalculator.getDefaultCertainty(strength); 103 104 // Typical combination of keysize and size of q. 105 // keysize = 1024, q's size = 160 106 // keysize = 2048, q's size = 224 107 // keysize = 2048, q's size = 256 108 // keysize = 3072, q's size = 256 109 // For simplicity if keysize is greater than 1024 then we choose q's size to be 256. 110 // For legacy keysize that is less than 1024-bit, we just use the 186-2 style parameters 111 if (strength == 1024) 112 { 113 pGen = new DSAParametersGenerator(); 114 if (Properties.isOverrideSet("org.bouncycastle.dsa.FIPS186-2for1024bits")) 115 { 116 pGen.init(strength, certainty, random); 117 } 118 else 119 { 120 dsaParams = new DSAParameterGenerationParameters(1024, 160, certainty, random); 121 pGen.init(dsaParams); 122 } 123 } 124 else if (strength > 1024) 125 { 126 dsaParams = new DSAParameterGenerationParameters(strength, 256, certainty, random); 127 pGen = new DSAParametersGenerator(new SHA256Digest()); 128 pGen.init(dsaParams); 129 } 130 else 131 { 132 pGen = new DSAParametersGenerator(); 133 pGen.init(strength, certainty, random); 134 } 135 param = new DSAKeyGenerationParameters(random, pGen.generateParameters()); 136 137 params.put(paramStrength, param); 138 } 139 } 140 } 141 142 engine.init(param); 143 initialised = true; 144 } 145 146 AsymmetricCipherKeyPair pair = engine.generateKeyPair(); 147 DSAPublicKeyParameters pub = (DSAPublicKeyParameters)pair.getPublic(); 148 DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate(); 149 150 return new KeyPair(new BCDSAPublicKey(pub), new BCDSAPrivateKey(priv)); 151 } 152 } 153