Home | History | Annotate | Download | only in dsa
      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