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