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