KeyPairGeneratorSpi.java revision a198e1ecc615e26a167d0f2dca9fa7e5fc62de10
1package org.bouncycastle.jcajce.provider.asymmetric.ec;
2
3import java.math.BigInteger;
4import java.security.InvalidAlgorithmParameterException;
5import java.security.InvalidParameterException;
6import java.security.KeyPair;
7import java.security.SecureRandom;
8import java.security.spec.AlgorithmParameterSpec;
9import java.security.spec.ECGenParameterSpec;
10import java.util.Hashtable;
11
12import org.bouncycastle.asn1.ASN1ObjectIdentifier;
13import org.bouncycastle.asn1.nist.NISTNamedCurves;
14import org.bouncycastle.asn1.sec.SECNamedCurves;
15// BEGIN android-removed
16// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
17// END android-removed
18import org.bouncycastle.asn1.x9.X962NamedCurves;
19import org.bouncycastle.asn1.x9.X9ECParameters;
20import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
21import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
22import org.bouncycastle.crypto.params.ECDomainParameters;
23import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
24import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
25import org.bouncycastle.crypto.params.ECPublicKeyParameters;
26import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
27import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
28import org.bouncycastle.jce.provider.BouncyCastleProvider;
29import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
30import org.bouncycastle.jce.spec.ECNamedCurveSpec;
31import org.bouncycastle.jce.spec.ECParameterSpec;
32import org.bouncycastle.math.ec.ECCurve;
33import org.bouncycastle.math.ec.ECPoint;
34import org.bouncycastle.util.Integers;
35
36public abstract class KeyPairGeneratorSpi
37    extends java.security.KeyPairGenerator
38{
39    public KeyPairGeneratorSpi(String algorithmName)
40    {
41        super(algorithmName);
42    }
43
44    public static class EC
45        extends KeyPairGeneratorSpi
46    {
47        ECKeyGenerationParameters   param;
48        ECKeyPairGenerator          engine = new ECKeyPairGenerator();
49        Object                      ecParams = null;
50        int                         strength = 239;
51        int                         certainty = 50;
52        SecureRandom                random = new SecureRandom();
53        boolean                     initialised = false;
54        String                      algorithm;
55        ProviderConfiguration       configuration;
56
57        static private Hashtable    ecParameters;
58
59        static {
60            ecParameters = new Hashtable();
61
62            ecParameters.put(Integers.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
63            ecParameters.put(Integers.valueOf(239), new ECGenParameterSpec("prime239v1"));
64            ecParameters.put(Integers.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
65
66            ecParameters.put(Integers.valueOf(224), new ECGenParameterSpec("P-224"));
67            ecParameters.put(Integers.valueOf(384), new ECGenParameterSpec("P-384"));
68            ecParameters.put(Integers.valueOf(521), new ECGenParameterSpec("P-521"));
69        }
70
71        public EC()
72        {
73            super("EC");
74            this.algorithm = "EC";
75            this.configuration = BouncyCastleProvider.CONFIGURATION;
76        }
77
78        public EC(
79            String  algorithm,
80            ProviderConfiguration configuration)
81        {
82            super(algorithm);
83            this.algorithm = algorithm;
84            this.configuration = configuration;
85        }
86
87        public void initialize(
88            int             strength,
89            SecureRandom    random)
90        {
91            this.strength = strength;
92            // BEGIN android-added
93            if (random != null) {
94            // END android-added
95            this.random = random;
96            // BEGIN android-added
97            }
98            // END android-added
99            ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integers.valueOf(strength));
100
101            if (ecParams != null)
102            {
103                try
104                {
105                    initialize(ecParams, random);
106                }
107                catch (InvalidAlgorithmParameterException e)
108                {
109                    throw new InvalidParameterException("key size not configurable.");
110                }
111            }
112            else
113            {
114                throw new InvalidParameterException("unknown key size.");
115            }
116        }
117
118        public void initialize(
119            AlgorithmParameterSpec  params,
120            SecureRandom            random)
121            throws InvalidAlgorithmParameterException
122        {
123            // BEGIN android-added
124            if (random == null) {
125                random = this.random;
126            }
127            // END android-added
128            if (params instanceof ECParameterSpec)
129            {
130                ECParameterSpec p = (ECParameterSpec)params;
131                this.ecParams = params;
132
133                param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
134
135                engine.init(param);
136                initialised = true;
137            }
138            else if (params instanceof java.security.spec.ECParameterSpec)
139            {
140                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)params;
141                this.ecParams = params;
142
143                ECCurve curve = EC5Util.convertCurve(p.getCurve());
144                ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
145
146                param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
147
148                engine.init(param);
149                initialised = true;
150            }
151            else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveGenParameterSpec)
152            {
153                String curveName;
154
155                if (params instanceof ECGenParameterSpec)
156                {
157                    curveName = ((ECGenParameterSpec)params).getName();
158                }
159                else
160                {
161                    curveName = ((ECNamedCurveGenParameterSpec)params).getName();
162                }
163
164                X9ECParameters  ecP = X962NamedCurves.getByName(curveName);
165                if (ecP == null)
166                {
167                    ecP = SECNamedCurves.getByName(curveName);
168                    if (ecP == null)
169                    {
170                        ecP = NISTNamedCurves.getByName(curveName);
171                    }
172                    // BEGIN android-removed
173                    // if (ecP == null)
174                    // {
175                    //     ecP = TeleTrusTNamedCurves.getByName(curveName);
176                    // }
177                    // END android-removed
178                    if (ecP == null)
179                    {
180                        // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
181                        try
182                        {
183                            ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName);
184                            ecP = X962NamedCurves.getByOID(oid);
185                            if (ecP == null)
186                            {
187                                ecP = SECNamedCurves.getByOID(oid);
188                            }
189                            if (ecP == null)
190                            {
191                                ecP = NISTNamedCurves.getByOID(oid);
192                            }
193                            // BEGIN android-removed
194                            // if (ecP == null)
195                            // {
196                            //     ecP = TeleTrusTNamedCurves.getByOID(oid);
197                            // }
198                            // END android-removed
199                            if (ecP == null)
200                            {
201                                throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
202                            }
203                        }
204                        catch (IllegalArgumentException ex)
205                        {
206                            throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
207                        }
208                    }
209                }
210
211                this.ecParams = new ECNamedCurveSpec(
212                            curveName,
213                            ecP.getCurve(),
214                            ecP.getG(),
215                            ecP.getN(),
216                            ecP.getH(),
217                            null); // ecP.getSeed());   Work-around JDK bug -- it won't look up named curves properly if seed is present
218
219                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
220
221                ECCurve curve = EC5Util.convertCurve(p.getCurve());
222                ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
223
224                param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
225
226                engine.init(param);
227                initialised = true;
228            }
229            else if (params == null && configuration.getEcImplicitlyCa() != null)
230            {
231                ECParameterSpec p = configuration.getEcImplicitlyCa();
232                this.ecParams = params;
233
234                param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
235
236                engine.init(param);
237                initialised = true;
238            }
239            else if (params == null && configuration.getEcImplicitlyCa() == null)
240            {
241                throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
242            }
243            else
244            {
245                throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
246            }
247        }
248
249        public KeyPair generateKeyPair()
250        {
251            if (!initialised)
252            {
253                initialize(strength, new SecureRandom());
254            }
255
256            AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
257            ECPublicKeyParameters       pub = (ECPublicKeyParameters)pair.getPublic();
258            ECPrivateKeyParameters      priv = (ECPrivateKeyParameters)pair.getPrivate();
259
260            if (ecParams instanceof ECParameterSpec)
261            {
262                ECParameterSpec p = (ECParameterSpec)ecParams;
263
264                BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
265                return new KeyPair(pubKey,
266                                   new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
267            }
268            else if (ecParams == null)
269            {
270               return new KeyPair(new BCECPublicKey(algorithm, pub, configuration),
271                                   new BCECPrivateKey(algorithm, priv, configuration));
272            }
273            else
274            {
275                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
276
277                BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
278
279                return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
280            }
281        }
282    }
283
284    public static class ECDSA
285        extends EC
286    {
287        public ECDSA()
288        {
289            super("ECDSA", BouncyCastleProvider.CONFIGURATION);
290        }
291    }
292
293    public static class ECDH
294        extends EC
295    {
296        public ECDH()
297        {
298            super("ECDH", BouncyCastleProvider.CONFIGURATION);
299        }
300    }
301
302    public static class ECDHC
303        extends EC
304    {
305        public ECDHC()
306        {
307            super("ECDHC", BouncyCastleProvider.CONFIGURATION);
308        }
309    }
310
311    public static class ECMQV
312        extends EC
313    {
314        public ECMQV()
315        {
316            super("ECMQV", BouncyCastleProvider.CONFIGURATION);
317        }
318    }
319}