JCEECPrivateKey.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
1package org.bouncycastle.jce.provider;
2
3import java.io.IOException;
4import java.io.ObjectInputStream;
5import java.io.ObjectOutputStream;
6import java.math.BigInteger;
7import java.security.interfaces.ECPrivateKey;
8import java.security.spec.ECParameterSpec;
9import java.security.spec.ECPoint;
10import java.security.spec.ECPrivateKeySpec;
11import java.security.spec.EllipticCurve;
12import java.util.Enumeration;
13
14import org.bouncycastle.asn1.ASN1Encodable;
15import org.bouncycastle.asn1.ASN1Encoding;
16import org.bouncycastle.asn1.ASN1ObjectIdentifier;
17import org.bouncycastle.asn1.ASN1Primitive;
18import org.bouncycastle.asn1.ASN1Sequence;
19import org.bouncycastle.asn1.DERBitString;
20import org.bouncycastle.asn1.DERInteger;
21import org.bouncycastle.asn1.DERNull;
22import org.bouncycastle.asn1.DERObjectIdentifier;
23// BEGIN android-removed
24// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
25// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
26// END android-removed
27import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
28import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
29import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
30import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
31import org.bouncycastle.asn1.x9.X962Parameters;
32import org.bouncycastle.asn1.x9.X9ECParameters;
33import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
34import org.bouncycastle.crypto.params.ECDomainParameters;
35import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
36import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
37import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
38import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
39import org.bouncycastle.jce.interfaces.ECPointEncoder;
40import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
41import org.bouncycastle.jce.spec.ECNamedCurveSpec;
42import org.bouncycastle.math.ec.ECCurve;
43
44public class JCEECPrivateKey
45    implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
46{
47    private String          algorithm = "EC";
48    private BigInteger      d;
49    private ECParameterSpec ecSpec;
50    private boolean         withCompression;
51
52    private DERBitString publicKey;
53
54    private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
55
56    protected JCEECPrivateKey()
57    {
58    }
59
60    public JCEECPrivateKey(
61        ECPrivateKey    key)
62    {
63        this.d = key.getS();
64        this.algorithm = key.getAlgorithm();
65        this.ecSpec = key.getParams();
66    }
67
68    public JCEECPrivateKey(
69        String              algorithm,
70        org.bouncycastle.jce.spec.ECPrivateKeySpec     spec)
71    {
72        this.algorithm = algorithm;
73        this.d = spec.getD();
74
75        if (spec.getParams() != null) // can be null if implicitlyCA
76        {
77            ECCurve curve = spec.getParams().getCurve();
78            EllipticCurve ellipticCurve;
79
80            ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
81
82            this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
83        }
84        else
85        {
86            this.ecSpec = null;
87        }
88    }
89
90
91    public JCEECPrivateKey(
92        String              algorithm,
93        ECPrivateKeySpec    spec)
94    {
95        this.algorithm = algorithm;
96        this.d = spec.getS();
97        this.ecSpec = spec.getParams();
98    }
99
100    public JCEECPrivateKey(
101        String             algorithm,
102        JCEECPrivateKey    key)
103    {
104        this.algorithm = algorithm;
105        this.d = key.d;
106        this.ecSpec = key.ecSpec;
107        this.withCompression = key.withCompression;
108        this.attrCarrier = key.attrCarrier;
109        this.publicKey = key.publicKey;
110    }
111
112    public JCEECPrivateKey(
113        String                  algorithm,
114        ECPrivateKeyParameters  params,
115        JCEECPublicKey          pubKey,
116        ECParameterSpec         spec)
117    {
118        ECDomainParameters      dp = params.getParameters();
119
120        this.algorithm = algorithm;
121        this.d = params.getD();
122
123        if (spec == null)
124        {
125            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
126
127            this.ecSpec = new ECParameterSpec(
128                            ellipticCurve,
129                            new ECPoint(
130                                    dp.getG().getAffineXCoord().toBigInteger(),
131                                    dp.getG().getAffineYCoord().toBigInteger()),
132                            dp.getN(),
133                            dp.getH().intValue());
134        }
135        else
136        {
137            this.ecSpec = spec;
138        }
139
140        publicKey = getPublicKeyDetails(pubKey);
141    }
142
143    public JCEECPrivateKey(
144        String                  algorithm,
145        ECPrivateKeyParameters  params,
146        JCEECPublicKey          pubKey,
147        org.bouncycastle.jce.spec.ECParameterSpec         spec)
148    {
149        ECDomainParameters      dp = params.getParameters();
150
151        this.algorithm = algorithm;
152        this.d = params.getD();
153
154        if (spec == null)
155        {
156            EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
157
158            this.ecSpec = new ECParameterSpec(
159                            ellipticCurve,
160                            new ECPoint(
161                                    dp.getG().getAffineXCoord().toBigInteger(),
162                                    dp.getG().getAffineYCoord().toBigInteger()),
163                            dp.getN(),
164                            dp.getH().intValue());
165        }
166        else
167        {
168            EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
169
170            this.ecSpec = new ECParameterSpec(
171                                ellipticCurve,
172                                new ECPoint(
173                                    spec.getG().getAffineXCoord().toBigInteger(),
174                                    spec.getG().getAffineYCoord().toBigInteger()),
175                                spec.getN(),
176                                spec.getH().intValue());
177        }
178
179        publicKey = getPublicKeyDetails(pubKey);
180    }
181
182    public JCEECPrivateKey(
183        String                  algorithm,
184        ECPrivateKeyParameters  params)
185    {
186        this.algorithm = algorithm;
187        this.d = params.getD();
188        this.ecSpec = null;
189    }
190
191    JCEECPrivateKey(
192        PrivateKeyInfo      info)
193        throws IOException
194    {
195        populateFromPrivKeyInfo(info);
196    }
197
198    private void populateFromPrivKeyInfo(PrivateKeyInfo info)
199        throws IOException
200    {
201        X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters());
202
203        if (params.isNamedCurve())
204        {
205            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
206            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
207
208            // BEGIN android-removed
209            // if (ecP == null) // GOST Curve
210            // {
211            //     ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
212            //     EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
213            //
214            //     ecSpec = new ECNamedCurveSpec(
215            //             ECGOST3410NamedCurves.getName(oid),
216            //             ellipticCurve,
217            //             new ECPoint(
218            //                     gParam.getG().getAffineXCoord().toBigInteger(),
219            //                     gParam.getG().getAffineYCoord().toBigInteger()),
220            //             gParam.getN(),
221            //             gParam.getH());
222            // }
223            // else
224            // END android-removed
225            {
226                EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
227
228                ecSpec = new ECNamedCurveSpec(
229                        ECUtil.getCurveName(oid),
230                        ellipticCurve,
231                        new ECPoint(
232                                ecP.getG().getAffineXCoord().toBigInteger(),
233                                ecP.getG().getAffineYCoord().toBigInteger()),
234                        ecP.getN(),
235                        ecP.getH());
236            }
237        }
238        else if (params.isImplicitlyCA())
239        {
240            ecSpec = null;
241        }
242        else
243        {
244            X9ECParameters      ecP = X9ECParameters.getInstance(params.getParameters());
245            EllipticCurve       ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
246
247            this.ecSpec = new ECParameterSpec(
248                ellipticCurve,
249                new ECPoint(
250                        ecP.getG().getAffineXCoord().toBigInteger(),
251                        ecP.getG().getAffineYCoord().toBigInteger()),
252                ecP.getN(),
253                ecP.getH().intValue());
254        }
255
256        ASN1Encodable privKey = info.parsePrivateKey();
257        if (privKey instanceof DERInteger)
258        {
259            DERInteger          derD = DERInteger.getInstance(privKey);
260
261            this.d = derD.getValue();
262        }
263        else
264        {
265            ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)privKey);
266
267            this.d = ec.getKey();
268            this.publicKey = ec.getPublicKey();
269        }
270    }
271
272    public String getAlgorithm()
273    {
274        return algorithm;
275    }
276
277    /**
278     * return the encoding format we produce in getEncoded().
279     *
280     * @return the string "PKCS#8"
281     */
282    public String getFormat()
283    {
284        return "PKCS#8";
285    }
286
287    /**
288     * Return a PKCS8 representation of the key. The sequence returned
289     * represents a full PrivateKeyInfo object.
290     *
291     * @return a PKCS8 representation of the key.
292     */
293    public byte[] getEncoded()
294    {
295        X962Parameters          params;
296
297        if (ecSpec instanceof ECNamedCurveSpec)
298        {
299            DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
300            if (curveOid == null)  // guess it's the OID
301            {
302                curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
303            }
304            params = new X962Parameters(curveOid);
305        }
306        else if (ecSpec == null)
307        {
308            params = new X962Parameters(DERNull.INSTANCE);
309        }
310        else
311        {
312            ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
313
314            X9ECParameters ecP = new X9ECParameters(
315                curve,
316                EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
317                ecSpec.getOrder(),
318                BigInteger.valueOf(ecSpec.getCofactor()),
319                ecSpec.getCurve().getSeed());
320
321            params = new X962Parameters(ecP);
322        }
323
324        PrivateKeyInfo          info;
325        ECPrivateKeyStructure keyStructure;
326
327        if (publicKey != null)
328        {
329            keyStructure = new ECPrivateKeyStructure(this.getS(), publicKey, params);
330        }
331        else
332        {
333            keyStructure = new ECPrivateKeyStructure(this.getS(), params);
334        }
335
336        try
337        {
338            // BEGIN android-removed
339            // if (algorithm.equals("ECGOST3410"))
340            // {
341            //     info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
342            // }
343            // else
344            // END android-removed
345            {
346
347                info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
348            }
349
350            return info.getEncoded(ASN1Encoding.DER);
351        }
352        catch (IOException e)
353        {
354            return null;
355        }
356    }
357
358    public ECParameterSpec getParams()
359    {
360        return ecSpec;
361    }
362
363    public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
364    {
365        if (ecSpec == null)
366        {
367            return null;
368        }
369
370        return EC5Util.convertSpec(ecSpec, withCompression);
371    }
372
373    org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
374    {
375        if (ecSpec != null)
376        {
377            return EC5Util.convertSpec(ecSpec, withCompression);
378        }
379
380        return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
381    }
382
383    public BigInteger getS()
384    {
385        return d;
386    }
387
388    public BigInteger getD()
389    {
390        return d;
391    }
392
393    public void setBagAttribute(
394        ASN1ObjectIdentifier oid,
395        ASN1Encodable        attribute)
396    {
397        attrCarrier.setBagAttribute(oid, attribute);
398    }
399
400    public ASN1Encodable getBagAttribute(
401        ASN1ObjectIdentifier oid)
402    {
403        return attrCarrier.getBagAttribute(oid);
404    }
405
406    public Enumeration getBagAttributeKeys()
407    {
408        return attrCarrier.getBagAttributeKeys();
409    }
410
411    public void setPointFormat(String style)
412    {
413       withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
414    }
415
416    public boolean equals(Object o)
417    {
418        if (!(o instanceof JCEECPrivateKey))
419        {
420            return false;
421        }
422
423        JCEECPrivateKey other = (JCEECPrivateKey)o;
424
425        return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
426    }
427
428    public int hashCode()
429    {
430        return getD().hashCode() ^ engineGetSpec().hashCode();
431    }
432
433    public String toString()
434    {
435        StringBuffer    buf = new StringBuffer();
436        String          nl = System.getProperty("line.separator");
437
438        buf.append("EC Private Key").append(nl);
439        buf.append("             S: ").append(this.d.toString(16)).append(nl);
440
441        return buf.toString();
442
443    }
444
445    private DERBitString getPublicKeyDetails(JCEECPublicKey   pub)
446    {
447        try
448        {
449            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
450
451            return info.getPublicKeyData();
452        }
453        catch (IOException e)
454        {   // should never happen
455            return null;
456        }
457    }
458
459    private void readObject(
460        ObjectInputStream in)
461        throws IOException, ClassNotFoundException
462    {
463        byte[] enc = (byte[])in.readObject();
464
465        populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
466
467        this.algorithm = (String)in.readObject();
468        this.withCompression = in.readBoolean();
469        this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
470
471        attrCarrier.readObject(in);
472    }
473
474    private void writeObject(
475        ObjectOutputStream out)
476        throws IOException
477    {
478        out.writeObject(this.getEncoded());
479        out.writeObject(algorithm);
480        out.writeBoolean(withCompression);
481
482        attrCarrier.writeObject(out);
483    }
484}
485