• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.conscrypt;
18 
19 import java.math.BigInteger;
20 import java.security.InvalidAlgorithmParameterException;
21 import java.security.InvalidParameterException;
22 import java.security.spec.ECField;
23 import java.security.spec.ECFieldF2m;
24 import java.security.spec.ECFieldFp;
25 import java.security.spec.ECParameterSpec;
26 import java.security.spec.ECPoint;
27 import java.security.spec.EllipticCurve;
28 
29 public final class OpenSSLECGroupContext {
30     private final long groupCtx;
31 
OpenSSLECGroupContext(long groupCtx)32     public OpenSSLECGroupContext(long groupCtx) {
33         this.groupCtx = groupCtx;
34     }
35 
getCurveByName(String curveName)36     public static OpenSSLECGroupContext getCurveByName(String curveName) {
37         // Workaround for OpenSSL not supporting SECG names for NIST P-192 and P-256
38         // (aka ANSI X9.62 prime192v1 and prime256v1) curve names.
39         if ("secp256r1".equals(curveName)) {
40             curveName = "prime256v1";
41         } else if ("secp192r1".equals(curveName)) {
42             curveName = "prime192v1";
43         }
44 
45         final long ctx = NativeCrypto.EC_GROUP_new_by_curve_name(curveName);
46         if (ctx == 0) {
47             return null;
48         }
49 
50         NativeCrypto.EC_GROUP_set_point_conversion_form(ctx,
51                 NativeCrypto.POINT_CONVERSION_UNCOMPRESSED);
52         NativeCrypto.EC_GROUP_set_asn1_flag(ctx, NativeCrypto.OPENSSL_EC_NAMED_CURVE);
53 
54         return new OpenSSLECGroupContext(ctx);
55     }
56 
getInstance(int type, BigInteger p, BigInteger a, BigInteger b, BigInteger x, BigInteger y, BigInteger n, BigInteger h)57     public static OpenSSLECGroupContext getInstance(int type, BigInteger p, BigInteger a,
58             BigInteger b, BigInteger x, BigInteger y, BigInteger n, BigInteger h) {
59         final long ctx = NativeCrypto.EC_GROUP_new_curve(type, p.toByteArray(), a.toByteArray(),
60                 b.toByteArray());
61         if (ctx == 0) {
62             return null;
63         }
64 
65         NativeCrypto.EC_GROUP_set_point_conversion_form(ctx,
66                 NativeCrypto.POINT_CONVERSION_UNCOMPRESSED);
67 
68         OpenSSLECGroupContext group = new OpenSSLECGroupContext(ctx);
69 
70         OpenSSLECPointContext generator = new OpenSSLECPointContext(group,
71                 NativeCrypto.EC_POINT_new(ctx));
72 
73         NativeCrypto.EC_POINT_set_affine_coordinates(ctx, generator.getContext(),
74                 x.toByteArray(), y.toByteArray());
75 
76         NativeCrypto.EC_GROUP_set_generator(ctx, generator.getContext(), n.toByteArray(),
77                 h.toByteArray());
78 
79         return group;
80     }
81 
82     @Override
finalize()83     protected void finalize() throws Throwable {
84         try {
85             if (groupCtx != 0) {
86                 NativeCrypto.EC_GROUP_clear_free(groupCtx);
87             }
88         } finally {
89             super.finalize();
90         }
91     }
92 
93     @Override
equals(Object o)94     public boolean equals(Object o) {
95         if (!(o instanceof OpenSSLECGroupContext)) {
96             return false;
97         }
98 
99         final OpenSSLECGroupContext other = (OpenSSLECGroupContext) o;
100         return NativeCrypto.EC_GROUP_cmp(groupCtx, other.groupCtx);
101     }
102 
103     @Override
hashCode()104     public int hashCode() {
105         // TODO Auto-generated method stub
106         return super.hashCode();
107     }
108 
getContext()109     public long getContext() {
110         return groupCtx;
111     }
112 
getInstance(ECParameterSpec params)113     public static OpenSSLECGroupContext getInstance(ECParameterSpec params)
114             throws InvalidAlgorithmParameterException {
115         final String curveName = Platform.getCurveName(params);
116         if (curveName != null) {
117             return OpenSSLECGroupContext.getCurveByName(curveName);
118         }
119 
120         final EllipticCurve curve = params.getCurve();
121         final ECField field = curve.getField();
122 
123         final int type;
124         final BigInteger p;
125         if (field instanceof ECFieldFp) {
126             type = NativeCrypto.EC_CURVE_GFP;
127             p = ((ECFieldFp) field).getP();
128         } else if (field instanceof ECFieldF2m) {
129             type = NativeCrypto.EC_CURVE_GF2M;
130             p = ((ECFieldF2m) field).getReductionPolynomial();
131         } else {
132             throw new InvalidParameterException("unhandled field class "
133                     + field.getClass().getName());
134         }
135 
136         final ECPoint generator = params.getGenerator();
137         return OpenSSLECGroupContext.getInstance(type, p, curve.getA(), curve.getB(),
138                 generator.getAffineX(), generator.getAffineY(), params.getOrder(),
139                 BigInteger.valueOf(params.getCofactor()));
140     }
141 
getECParameterSpec()142     public ECParameterSpec getECParameterSpec() {
143         final String curveName = NativeCrypto.EC_GROUP_get_curve_name(groupCtx);
144 
145         final byte[][] curveParams = NativeCrypto.EC_GROUP_get_curve(groupCtx);
146         final BigInteger p = new BigInteger(curveParams[0]);
147         final BigInteger a = new BigInteger(curveParams[1]);
148         final BigInteger b = new BigInteger(curveParams[2]);
149 
150         final ECField field;
151         final int type = NativeCrypto.get_EC_GROUP_type(groupCtx);
152         if (type == NativeCrypto.EC_CURVE_GFP) {
153             field = new ECFieldFp(p);
154         } else if (type == NativeCrypto.EC_CURVE_GF2M) {
155             field = new ECFieldF2m(p.bitLength() - 1, p);
156         } else {
157             throw new RuntimeException("unknown curve type " + type);
158         }
159 
160         final EllipticCurve curve = new EllipticCurve(field, a, b);
161 
162         final OpenSSLECPointContext generatorCtx = new OpenSSLECPointContext(this,
163                 NativeCrypto.EC_GROUP_get_generator(groupCtx));
164         final ECPoint generator = generatorCtx.getECPoint();
165 
166         final BigInteger order = new BigInteger(NativeCrypto.EC_GROUP_get_order(groupCtx));
167         final BigInteger cofactor = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(groupCtx));
168 
169         ECParameterSpec spec = new ECParameterSpec(curve, generator, order, cofactor.intValue());
170         Platform.setCurveName(spec, curveName);
171         return spec;
172     }
173 }
174