OpenSSLECGroupContext.java revision c9acbf1c80d90952f7a4bce83e37c2540e42f6fc
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
17package org.apache.harmony.xnet.provider.jsse;
18
19import java.math.BigInteger;
20import java.security.InvalidAlgorithmParameterException;
21import java.security.InvalidParameterException;
22import java.security.spec.ECField;
23import java.security.spec.ECFieldF2m;
24import java.security.spec.ECFieldFp;
25import java.security.spec.ECParameterSpec;
26import java.security.spec.ECPoint;
27import java.security.spec.EllipticCurve;
28
29final class OpenSSLECGroupContext {
30    private final int groupCtx;
31
32    private OpenSSLECGroupContext(int groupCtx) {
33        this.groupCtx = groupCtx;
34    }
35
36    public static OpenSSLECGroupContext getCurveByName(String curveName) {
37        final int ctx = NativeCrypto.EC_GROUP_new_by_curve_name(curveName);
38        if (ctx == 0) {
39            return null;
40        }
41
42        NativeCrypto.EC_GROUP_set_point_conversion_form(ctx,
43                NativeCrypto.POINT_CONVERSION_UNCOMPRESSED);
44        NativeCrypto.EC_GROUP_set_asn1_flag(ctx, NativeCrypto.OPENSSL_EC_NAMED_CURVE);
45
46        return new OpenSSLECGroupContext(ctx);
47    }
48
49    public static OpenSSLECGroupContext getInstance(int type, BigInteger p, BigInteger a,
50            BigInteger b, BigInteger x, BigInteger y, BigInteger n, BigInteger h) {
51        final int ctx = NativeCrypto.EC_GROUP_new_curve(type, p.toByteArray(), a.toByteArray(),
52                b.toByteArray());
53        if (ctx == 0) {
54            return null;
55        }
56
57        NativeCrypto.EC_GROUP_set_point_conversion_form(ctx,
58                NativeCrypto.POINT_CONVERSION_UNCOMPRESSED);
59
60        OpenSSLECGroupContext group = new OpenSSLECGroupContext(ctx);
61
62        OpenSSLECPointContext generator = new OpenSSLECPointContext(group,
63                NativeCrypto.EC_POINT_new(ctx));
64
65        NativeCrypto.EC_POINT_set_affine_coordinates(ctx, generator.getContext(),
66                x.toByteArray(), y.toByteArray());
67
68        NativeCrypto.EC_GROUP_set_generator(ctx, generator.getContext(), n.toByteArray(),
69                h.toByteArray());
70
71        return group;
72    }
73
74    @Override
75    protected void finalize() throws Throwable {
76        try {
77            if (groupCtx != 0) {
78                NativeCrypto.EC_GROUP_clear_free(groupCtx);
79            }
80        } finally {
81            super.finalize();
82        }
83    }
84
85    @Override
86    public boolean equals(Object o) {
87        if (!(o instanceof OpenSSLECGroupContext)) {
88            return false;
89        }
90
91        final OpenSSLECGroupContext other = (OpenSSLECGroupContext) o;
92        return NativeCrypto.EC_GROUP_cmp(groupCtx, other.groupCtx);
93    }
94
95    @Override
96    public int hashCode() {
97        // TODO Auto-generated method stub
98        return super.hashCode();
99    }
100
101    public int getContext() {
102        return groupCtx;
103    }
104
105    public static OpenSSLECGroupContext getInstance(ECParameterSpec params)
106            throws InvalidAlgorithmParameterException {
107        final EllipticCurve curve = params.getCurve();
108        final ECField field = curve.getField();
109
110        final int type;
111        final BigInteger p;
112        if (field instanceof ECFieldFp) {
113            type = NativeCrypto.EC_CURVE_GFP;
114            p = ((ECFieldFp) field).getP();
115        } else if (field instanceof ECFieldF2m) {
116            type = NativeCrypto.EC_CURVE_GF2M;
117            p = ((ECFieldF2m) field).getReductionPolynomial();
118        } else {
119            throw new InvalidParameterException("unhandled field class "
120                    + field.getClass().getName());
121        }
122
123        final ECPoint generator = params.getGenerator();
124        return OpenSSLECGroupContext.getInstance(type, p, curve.getA(), curve.getB(),
125                generator.getAffineX(), generator.getAffineY(), params.getOrder(),
126                BigInteger.valueOf(params.getCofactor()));
127    }
128
129    public ECParameterSpec getECParameterSpec() {
130        final int curveType = NativeCrypto.get_EC_GROUP_type(groupCtx);
131        final byte[][] curveParams = NativeCrypto.EC_GROUP_get_curve(groupCtx);
132        final BigInteger p = new BigInteger(curveParams[0]);
133        final BigInteger a = new BigInteger(curveParams[1]);
134        final BigInteger b = new BigInteger(curveParams[2]);
135
136        final ECField field;
137        final int type = NativeCrypto.get_EC_GROUP_type(groupCtx);
138        if (type == NativeCrypto.EC_CURVE_GFP) {
139            field = new ECFieldFp(p);
140        } else if (type == NativeCrypto.EC_CURVE_GF2M) {
141            field = new ECFieldF2m(p.bitLength() - 1, p);
142        } else {
143            throw new RuntimeException("unknown curve type " + type);
144        }
145
146        final EllipticCurve curve = new EllipticCurve(field, a, b);
147
148        final OpenSSLECPointContext generatorCtx = new OpenSSLECPointContext(this,
149                NativeCrypto.EC_GROUP_get_generator(groupCtx));
150        final ECPoint generator = generatorCtx.getECPoint();
151
152        final BigInteger order = new BigInteger(NativeCrypto.EC_GROUP_get_order(groupCtx));
153        final BigInteger cofactor = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(groupCtx));
154
155        return new ECParameterSpec(curve, generator, order, cofactor.intValue());
156    }
157}
158