1d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com/* 2d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * Copyright (C) 2012 The Android Open Source Project 3d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * 4d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * Licensed under the Apache License, Version 2.0 (the "License"); 5d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * you may not use this file except in compliance with the License. 6d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * You may obtain a copy of the License at 7d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com * 8d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * http://www.apache.org/licenses/LICENSE-2.0 9d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * 10d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * Unless required by applicable law or agreed to in writing, software 11d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * distributed under the License is distributed on an "AS IS" BASIS, 12d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * See the License for the specific language governing permissions and 14d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com * limitations under the License. 15d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com */ 16a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 17a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.compackage org.conscrypt; 189a6eb0e1e8a8de7371cd9604f34619b8f87de66fsenorblanco@chromium.org 19a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.math.BigInteger; 203f2d45aff69260fcf39d4eea8586387ed44402bbsenorblanco@chromium.orgimport java.security.InvalidAlgorithmParameterException; 21d912ca419927e8548e9e931156bbbc81f26969aesenorblanco@chromium.orgimport java.security.InvalidParameterException; 22a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.ECField; 23a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.ECFieldF2m; 24a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.ECFieldFp; 25a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.ECParameterSpec; 26392e14eaaf952565e25e11b8e5133507e4e7d0d8senorblanco@chromium.orgimport java.security.spec.ECPoint; 27a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comimport java.security.spec.EllipticCurve; 28a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 291c4c9ef43747b42d2c31b5f17fe5e054fb3fee64commit-bot@chromium.orgpublic final class OpenSSLECGroupContext { 30b3c0f4886e22b6d2041c1049a1f295943959fff1scroggo private final long groupCtx; 31a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 32a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com public OpenSSLECGroupContext(long groupCtx) { 33a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com this.groupCtx = groupCtx; 34781cc76e0f1ebb06e0796a9237045ae9d4bddd21sugoi@google.com } 35f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org 36a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com public static OpenSSLECGroupContext getCurveByName(String curveName) { 3772ae6bd24eb72be13d5745129c16058e4d54e2f4scroggo@google.com // Workaround for OpenSSL not supporting SECG names for NIST P-192 and P-256 38a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com // (aka ANSI X9.62 prime192v1 and prime256v1) curve names. 39a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com if ("secp256r1".equals(curveName)) { 405a7c6be72b940dde8ff6ad2485a09aecd56a2660scroggo@google.com curveName = "prime256v1"; 41a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com } else if ("secp192r1".equals(curveName)) { 42a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com curveName = "prime192v1"; 438c6411a603266e94dd87445ac30e0b1abc36b0afreed@google.com } 440833777df1f05adafd9b70c666a72d80defa4f6bdjsollen@google.com 456c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org final long ctx = NativeCrypto.EC_GROUP_new_by_curve_name(curveName); 4635c5ff0be81f2bbba9a7f31b055124a51e6168f4senorblanco@chromium.org if (ctx == 0) { 47b4ca9df976951adf632388371f9a8a9219d93014senorblanco@chromium.org return null; 484a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org } 49a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 504a9a612b5200597cca0bda0a356250835cbdc7d6senorblanco@chromium.org NativeCrypto.EC_GROUP_set_point_conversion_form(ctx, 51c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org NativeCrypto.POINT_CONVERSION_UNCOMPRESSED); 52e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com NativeCrypto.EC_GROUP_set_asn1_flag(ctx, NativeCrypto.OPENSSL_EC_NAMED_CURVE); 539e5f85e89d03a850d435fc951e74e9861a0c1bddcommit-bot@chromium.org 54a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com return new OpenSSLECGroupContext(ctx); 55cf292b7b32732330f7e0a55e6dd323426e466f80commit-bot@chromium.org } 56a612d4c5134655fe6703c8d2f63be710aa1e2767senorblanco@chromium.org 57088719ecdc89b399dd3a3a65f8cced262e50d951robertphillips@google.com public static OpenSSLECGroupContext getInstance(int type, BigInteger p, BigInteger a, 58a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com BigInteger b, BigInteger x, BigInteger y, BigInteger n, BigInteger h) { 59a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com final long ctx = NativeCrypto.EC_GROUP_new_curve(type, p.toByteArray(), a.toByteArray(), 600ac74b2c0d0f740bdf1c0dcba2bef77bc33f77e9sugoi@google.com b.toByteArray()); 61fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org if (ctx == 0) { 6286fc266eda887920e3dd104bee8121ae19729cf5senorblanco@chromium.org return null; 63a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com } 64c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org 65a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com NativeCrypto.EC_GROUP_set_point_conversion_form(ctx, 663f2d45aff69260fcf39d4eea8586387ed44402bbsenorblanco@chromium.org NativeCrypto.POINT_CONVERSION_UNCOMPRESSED); 67a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 68d912ca419927e8548e9e931156bbbc81f26969aesenorblanco@chromium.org OpenSSLECGroupContext group = new OpenSSLECGroupContext(ctx); 69a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 70a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com OpenSSLECPointContext generator = new OpenSSLECPointContext(group, 71a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com NativeCrypto.EC_POINT_new(ctx)); 72a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 73a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com NativeCrypto.EC_POINT_set_affine_coordinates(ctx, generator.getContext(), 74b3c0f4886e22b6d2041c1049a1f295943959fff1scroggo x.toByteArray(), y.toByteArray()); 75a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 76a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com NativeCrypto.EC_GROUP_set_generator(ctx, generator.getContext(), n.toByteArray(), 77a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com h.toByteArray()); 78a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 79781cc76e0f1ebb06e0796a9237045ae9d4bddd21sugoi@google.com return group; 80f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org } 8172ae6bd24eb72be13d5745129c16058e4d54e2f4scroggo@google.com 82a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com @Override 83a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com protected void finalize() throws Throwable { 84a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com try { 85a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com if (groupCtx != 0) { 868c6411a603266e94dd87445ac30e0b1abc36b0afreed@google.com NativeCrypto.EC_GROUP_clear_free(groupCtx); 876c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org } 88a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com } finally { 89d8a6cc814f1a0a8faaddad05ae765ad2f6b11aacscroggo@google.com super.finalize(); 90d8a6cc814f1a0a8faaddad05ae765ad2f6b11aacscroggo@google.com } 91a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com } 92e3b4c5097a6fd9b6c09d2ffbc3db170a287fdd99sugoi@google.com 939e5f85e89d03a850d435fc951e74e9861a0c1bddcommit-bot@chromium.org @Override 94a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com public boolean equals(Object o) { 95cf292b7b32732330f7e0a55e6dd323426e466f80commit-bot@chromium.org if (!(o instanceof OpenSSLECGroupContext)) { 96a612d4c5134655fe6703c8d2f63be710aa1e2767senorblanco@chromium.org return false; 97941ee9303b62163ae08bbdcd7ad514e1a6389bdarobertphillips@google.com } 98a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 990ac74b2c0d0f740bdf1c0dcba2bef77bc33f77e9sugoi@google.com final OpenSSLECGroupContext other = (OpenSSLECGroupContext) o; 100fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org return NativeCrypto.EC_GROUP_cmp(groupCtx, other.groupCtx); 10186fc266eda887920e3dd104bee8121ae19729cf5senorblanco@chromium.org } 10282aa7482cbf55ce6d42c692550cadee5e23146e4bsalomon@google.com 103b4ca9df976951adf632388371f9a8a9219d93014senorblanco@chromium.org @Override 104a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com public int hashCode() { 105a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com // TODO Auto-generated method stub 106a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com return super.hashCode(); 107a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com } 108a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 109a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com public long getContext() { 1105370cd969d8f3957e4306068e6195ac1bca3d6cddjsollen@google.com return groupCtx; 1115370cd969d8f3957e4306068e6195ac1bca3d6cddjsollen@google.com } 1129a6eb0e1e8a8de7371cd9604f34619b8f87de66fsenorblanco@chromium.org 113a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com public static OpenSSLECGroupContext getInstance(ECParameterSpec params) 114a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com throws InvalidAlgorithmParameterException { 115a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com final String curveName = Platform.getCurveName(params); 1165a7c6be72b940dde8ff6ad2485a09aecd56a2660scroggo@google.com if (curveName != null) { 1170833777df1f05adafd9b70c666a72d80defa4f6bdjsollen@google.com return OpenSSLECGroupContext.getCurveByName(curveName); 118a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com } 119a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com 120d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com final EllipticCurve curve = params.getCurve(); 121c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org final ECField field = curve.getField(); 122c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org 123c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org final int type; 124c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org final BigInteger p; 125c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org if (field instanceof ECFieldFp) { 126c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org 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 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