1 package org.bouncycastle.jcajce.provider.asymmetric.util;
2 
3 import java.math.BigInteger;
4 import java.security.spec.ECField;
5 import java.security.spec.ECFieldF2m;
6 import java.security.spec.ECFieldFp;
7 import java.security.spec.ECParameterSpec;
8 import java.security.spec.ECPoint;
9 import java.security.spec.EllipticCurve;
10 import java.util.Enumeration;
11 import java.util.HashMap;
12 import java.util.Map;
13 import java.util.Set;
14 
15 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
16 import org.bouncycastle.asn1.ASN1Sequence;
17 import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
18 import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
19 import org.bouncycastle.asn1.x9.ECNamedCurveTable;
20 import org.bouncycastle.asn1.x9.X962Parameters;
21 import org.bouncycastle.asn1.x9.X9ECParameters;
22 import org.bouncycastle.crypto.ec.CustomNamedCurves;
23 import org.bouncycastle.crypto.params.ECDomainParameters;
24 import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
25 import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
26 import org.bouncycastle.jce.provider.BouncyCastleProvider;
27 import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
28 import org.bouncycastle.jce.spec.ECNamedCurveSpec;
29 import org.bouncycastle.math.ec.ECAlgorithms;
30 import org.bouncycastle.math.ec.ECCurve;
31 import org.bouncycastle.math.field.FiniteField;
32 import org.bouncycastle.math.field.Polynomial;
33 import org.bouncycastle.math.field.PolynomialExtensionField;
34 import org.bouncycastle.util.Arrays;
35 
36 public class EC5Util
37 {
38     private static Map customCurves = new HashMap();
39 
40     static
41     {
42         Enumeration e = CustomNamedCurves.getNames();
43         while (e.hasMoreElements())
44         {
45             String name = (String)e.nextElement();
46 
47             X9ECParameters curveParams = ECNamedCurveTable.getByName(name);
48             if (curveParams != null)  // there may not be a regular curve, may just be a custom curve.
49             {
curveParams.getCurve()50                 customCurves.put(curveParams.getCurve(), CustomNamedCurves.getByName(name).getCurve());
51             }
52         }
53 
54         X9ECParameters x9_25519 = CustomNamedCurves.getByName("Curve25519");
55         ECCurve c_25519 = x9_25519.getCurve();
56 
customCurves.put(new ECCurve.Fp( c_25519.getField().getCharacteristic(), c_25519.getA().toBigInteger(), c_25519.getB().toBigInteger(), c_25519.getOrder(), c_25519.getCofactor() ), c_25519)57         customCurves.put(new ECCurve.Fp(
58             c_25519.getField().getCharacteristic(),
59             c_25519.getA().toBigInteger(),
60             c_25519.getB().toBigInteger(),
61             c_25519.getOrder(),
62             c_25519.getCofactor()
63             ), c_25519);
64     }
65 
getCurve( ProviderConfiguration configuration, X962Parameters params)66     public static ECCurve getCurve(
67         ProviderConfiguration configuration,
68         X962Parameters params)
69     {
70         ECCurve curve;
71         Set acceptableCurves = configuration.getAcceptableNamedCurves();
72 
73         if (params.isNamedCurve())
74         {
75             ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
76 
77             if (acceptableCurves.isEmpty() || acceptableCurves.contains(oid))
78             {
79                 X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
80 
81                 if (ecP == null)
82                 {
83                     ecP = (X9ECParameters)configuration.getAdditionalECParameters().get(oid);
84                 }
85 
86                 curve = ecP.getCurve();
87             }
88             else
89             {
90                 throw new IllegalStateException("named curve not acceptable");
91             }
92         }
93         else if (params.isImplicitlyCA())
94         {
95             curve = configuration.getEcImplicitlyCa().getCurve();
96         }
97         else
98         {
99             ASN1Sequence pSeq = ASN1Sequence.getInstance(params.getParameters());
100             if (acceptableCurves.isEmpty())
101             {
102                 if (pSeq.size() > 3)
103                 {
104                     X9ECParameters ecP = X9ECParameters.getInstance(pSeq);
105 
106                     curve = ecP.getCurve();
107                 }
108                 else    // GOST parameters
109                 {
110                     ASN1ObjectIdentifier gostCurve = ASN1ObjectIdentifier.getInstance(pSeq.getObjectAt(0));
111 
112                     curve = ECGOST3410NamedCurves.getByOIDX9(gostCurve).getCurve();
113                 }
114             }
115             else
116             {
117                 throw new IllegalStateException("encoded parameters not acceptable");
118             }
119         }
120 
121         return curve;
122     }
123 
getDomainParameters( ProviderConfiguration configuration, java.security.spec.ECParameterSpec params)124     public static ECDomainParameters getDomainParameters(
125         ProviderConfiguration configuration,
126         java.security.spec.ECParameterSpec params)
127     {
128         ECDomainParameters domainParameters;
129 
130         if (params == null)
131         {
132             org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa();
133 
134             domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed());
135         }
136         else
137         {
138             domainParameters = ECUtil.getDomainParameters(configuration, convertSpec(params));
139         }
140 
141         return domainParameters;
142     }
143 
convertToSpec( X962Parameters params, ECCurve curve)144     public static ECParameterSpec convertToSpec(
145         X962Parameters params, ECCurve curve)
146     {
147         ECParameterSpec ecSpec;
148         EllipticCurve ellipticCurve;
149 
150         if (params.isNamedCurve())
151         {
152             ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
153             X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
154             if (ecP == null)
155             {
156                 Map additionalECParameters = BouncyCastleProvider.CONFIGURATION.getAdditionalECParameters();
157                 if (!additionalECParameters.isEmpty())
158                 {
159                     ecP = (X9ECParameters)additionalECParameters.get(oid);
160                 }
161             }
162 
163             ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
164 
165             ecSpec = new ECNamedCurveSpec(
166                 ECUtil.getCurveName(oid),
167                 ellipticCurve,
168                 convertPoint(ecP.getG()),
169                 ecP.getN(),
170                 ecP.getH());
171         }
172         else if (params.isImplicitlyCA())
173         {
174             ecSpec = null;
175         }
176         else
177         {
178             ASN1Sequence pSeq = ASN1Sequence.getInstance(params.getParameters());
179             if (pSeq.size() > 3)
180             {
181                 X9ECParameters ecP = X9ECParameters.getInstance(pSeq);
182 
183                 ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
184 
185                 if (ecP.getH() != null)
186                 {
187                     ecSpec = new ECParameterSpec(
188                         ellipticCurve,
189                         convertPoint(ecP.getG()),
190                         ecP.getN(),
191                         ecP.getH().intValue());
192                 }
193                 else
194                 {
195                     ecSpec = new ECParameterSpec(
196                         ellipticCurve,
197                         convertPoint(ecP.getG()),
198                         ecP.getN(),
199                         1);      // TODO: not strictly correct... need to fix the test data...
200                 }
201             }
202             else    // GOST parameters
203             {
204                 GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(pSeq);
205 
206                 ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(
207                     gostParams.getPublicKeyParamSet()));
208 
209                 curve = spec.getCurve();
210                 ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
211 
212                 ecSpec = new ECNamedCurveSpec(
213                     ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
214                     ellipticCurve,
215                     EC5Util.convertPoint(spec.getG()),
216                     spec.getN(), spec.getH());
217             }
218         }
219 
220         return ecSpec;
221     }
222 
convertToSpec( X9ECParameters domainParameters)223     public static ECParameterSpec convertToSpec(
224         X9ECParameters domainParameters)
225     {
226         return new ECParameterSpec(
227             convertCurve(domainParameters.getCurve(), null),  // JDK 1.5 has trouble with this if it's not null...
228             EC5Util.convertPoint(domainParameters.getG()),
229             domainParameters.getN(),
230             domainParameters.getH().intValue());
231     }
232 
convertToSpec( ECDomainParameters domainParameters)233     public static ECParameterSpec convertToSpec(
234         ECDomainParameters domainParameters)
235     {
236         return new ECParameterSpec(
237             convertCurve(domainParameters.getCurve(), null),  // JDK 1.5 has trouble with this if it's not null...
238             EC5Util.convertPoint(domainParameters.getG()),
239             domainParameters.getN(),
240             domainParameters.getH().intValue());
241     }
242 
convertCurve( ECCurve curve, byte[] seed)243     public static EllipticCurve convertCurve(
244         ECCurve curve,
245         byte[]  seed)
246     {
247         ECField field = convertField(curve.getField());
248         BigInteger a = curve.getA().toBigInteger(), b = curve.getB().toBigInteger();
249 
250         // TODO: the Sun EC implementation doesn't currently handle the seed properly
251         // so at the moment it's set to null. Should probably look at making this configurable
252         return new EllipticCurve(field, a, b, null);
253     }
254 
convertCurve( EllipticCurve ec)255     public static ECCurve convertCurve(
256         EllipticCurve ec)
257     {
258         ECField field = ec.getField();
259         BigInteger a = ec.getA();
260         BigInteger b = ec.getB();
261 
262         if (field instanceof ECFieldFp)
263         {
264             ECCurve.Fp curve = new ECCurve.Fp(((ECFieldFp)field).getP(), a, b);
265 
266             if (customCurves.containsKey(curve))
267             {
268                 return (ECCurve)customCurves.get(curve);
269             }
270 
271             return curve;
272         }
273         else
274         {
275             ECFieldF2m fieldF2m = (ECFieldF2m)field;
276             int m = fieldF2m.getM();
277             int ks[] = ECUtil.convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
278             return new ECCurve.F2m(m, ks[0], ks[1], ks[2], a, b);
279         }
280     }
281 
convertField(FiniteField field)282     public static ECField convertField(FiniteField field)
283     {
284         if (ECAlgorithms.isFpField(field))
285         {
286             return new ECFieldFp(field.getCharacteristic());
287         }
288         else //if (ECAlgorithms.isF2mField(curveField))
289         {
290             Polynomial poly = ((PolynomialExtensionField)field).getMinimalPolynomial();
291             int[] exponents = poly.getExponentsPresent();
292             int[] ks = Arrays.reverseInPlace(Arrays.copyOfRange(exponents, 1, exponents.length - 1));
293             return new ECFieldF2m(poly.getDegree(), ks);
294         }
295     }
296 
convertSpec( EllipticCurve ellipticCurve, org.bouncycastle.jce.spec.ECParameterSpec spec)297     public static ECParameterSpec convertSpec(
298         EllipticCurve ellipticCurve,
299         org.bouncycastle.jce.spec.ECParameterSpec spec)
300     {
301         ECPoint g = convertPoint(spec.getG());
302 
303         if (spec instanceof ECNamedCurveParameterSpec)
304         {
305             String name = ((ECNamedCurveParameterSpec)spec).getName();
306 
307             return new ECNamedCurveSpec(name, ellipticCurve, g, spec.getN(), spec.getH());
308         }
309         else
310         {
311             return new ECParameterSpec(ellipticCurve, g, spec.getN(), spec.getH().intValue());
312         }
313     }
314 
convertSpec(ECParameterSpec ecSpec)315     public static org.bouncycastle.jce.spec.ECParameterSpec convertSpec(ECParameterSpec ecSpec)
316     {
317         ECCurve curve = convertCurve(ecSpec.getCurve());
318 
319         org.bouncycastle.math.ec.ECPoint g = convertPoint(curve, ecSpec.getGenerator());
320         BigInteger n = ecSpec.getOrder();
321         BigInteger h = BigInteger.valueOf(ecSpec.getCofactor());
322         byte[] seed = ecSpec.getCurve().getSeed();
323 
324         if (ecSpec instanceof ECNamedCurveSpec)
325         {
326             return new org.bouncycastle.jce.spec.ECNamedCurveParameterSpec(((ECNamedCurveSpec)ecSpec).getName(), curve,
327                 g, n, h, seed);
328         }
329         else
330         {
331             return new org.bouncycastle.jce.spec.ECParameterSpec(curve, g, n, h, seed);
332         }
333     }
334 
convertPoint(ECParameterSpec ecSpec, ECPoint point)335     public static org.bouncycastle.math.ec.ECPoint convertPoint(ECParameterSpec ecSpec, ECPoint point)
336     {
337         return convertPoint(convertCurve(ecSpec.getCurve()), point);
338     }
339 
convertPoint(ECCurve curve, ECPoint point)340     public static org.bouncycastle.math.ec.ECPoint convertPoint(ECCurve curve, ECPoint point)
341     {
342         return curve.createPoint(point.getAffineX(), point.getAffineY());
343     }
344 
convertPoint(org.bouncycastle.math.ec.ECPoint point)345     public static ECPoint convertPoint(org.bouncycastle.math.ec.ECPoint point)
346     {
347         point = point.normalize();
348 
349         return new ECPoint(
350             point.getAffineXCoord().toBigInteger(),
351             point.getAffineYCoord().toBigInteger());
352     }
353 }
354