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