19d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root/* 29d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * Copyright (C) 2012 The Android Open Source Project 39d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * 49d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 59d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * you may not use this file except in compliance with the License. 69d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * You may obtain a copy of the License at 79d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * 89d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * http://www.apache.org/licenses/LICENSE-2.0 99d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * 109d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * Unless required by applicable law or agreed to in writing, software 119d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * distributed under the License is distributed on an "AS IS" BASIS, 129d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * See the License for the specific language governing permissions and 149d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root * limitations under the License. 159d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root */ 169d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1738375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootpackage org.conscrypt; 189d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 199d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.math.BigInteger; 209d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.security.InvalidAlgorithmParameterException; 219d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.security.InvalidParameterException; 229d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.security.spec.ECField; 239d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.security.spec.ECFieldF2m; 249d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.security.spec.ECFieldFp; 259d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.security.spec.ECParameterSpec; 269d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.security.spec.ECPoint; 279d2fb535e5d43ad34af09195d490da18a7694a48Kenny Rootimport java.security.spec.EllipticCurve; 289d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 297245d2ec05c8488f0bd82720eedac6a2dda17059Kenny Rootpublic final class OpenSSLECGroupContext { 308acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice private final long groupCtx; 319d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 328acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice public OpenSSLECGroupContext(long groupCtx) { 339d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root this.groupCtx = groupCtx; 349d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 359d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 369d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root public static OpenSSLECGroupContext getCurveByName(String curveName) { 37004df9b49863d5449c0c70d0ade0203813f4e676Alex Klyubin // Workaround for OpenSSL not supporting SECG names for NIST P-192 and P-256 38004df9b49863d5449c0c70d0ade0203813f4e676Alex Klyubin // (aka ANSI X9.62 prime192v1 and prime256v1) curve names. 39004df9b49863d5449c0c70d0ade0203813f4e676Alex Klyubin if ("secp256r1".equals(curveName)) { 40004df9b49863d5449c0c70d0ade0203813f4e676Alex Klyubin curveName = "prime256v1"; 41004df9b49863d5449c0c70d0ade0203813f4e676Alex Klyubin } else if ("secp192r1".equals(curveName)) { 42004df9b49863d5449c0c70d0ade0203813f4e676Alex Klyubin curveName = "prime192v1"; 43004df9b49863d5449c0c70d0ade0203813f4e676Alex Klyubin } 44004df9b49863d5449c0c70d0ade0203813f4e676Alex Klyubin 458acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice final long ctx = NativeCrypto.EC_GROUP_new_by_curve_name(curveName); 469d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root if (ctx == 0) { 479d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return null; 489d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 499d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 50c9acbf1c80d90952f7a4bce83e37c2540e42f6fcKenny Root NativeCrypto.EC_GROUP_set_point_conversion_form(ctx, 51c9acbf1c80d90952f7a4bce83e37c2540e42f6fcKenny Root NativeCrypto.POINT_CONVERSION_UNCOMPRESSED); 52c9acbf1c80d90952f7a4bce83e37c2540e42f6fcKenny Root NativeCrypto.EC_GROUP_set_asn1_flag(ctx, NativeCrypto.OPENSSL_EC_NAMED_CURVE); 53c9acbf1c80d90952f7a4bce83e37c2540e42f6fcKenny Root 549d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return new OpenSSLECGroupContext(ctx); 559d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 569d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 579d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root public static OpenSSLECGroupContext getInstance(int type, BigInteger p, BigInteger a, 589d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root BigInteger b, BigInteger x, BigInteger y, BigInteger n, BigInteger h) { 598acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice final long ctx = NativeCrypto.EC_GROUP_new_curve(type, p.toByteArray(), a.toByteArray(), 609d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root b.toByteArray()); 619d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root if (ctx == 0) { 629d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return null; 639d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 649d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 65c9acbf1c80d90952f7a4bce83e37c2540e42f6fcKenny Root NativeCrypto.EC_GROUP_set_point_conversion_form(ctx, 66c9acbf1c80d90952f7a4bce83e37c2540e42f6fcKenny Root NativeCrypto.POINT_CONVERSION_UNCOMPRESSED); 67c9acbf1c80d90952f7a4bce83e37c2540e42f6fcKenny Root 689d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root OpenSSLECGroupContext group = new OpenSSLECGroupContext(ctx); 699d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 709d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root OpenSSLECPointContext generator = new OpenSSLECPointContext(group, 719d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root NativeCrypto.EC_POINT_new(ctx)); 729d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 739d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root NativeCrypto.EC_POINT_set_affine_coordinates(ctx, generator.getContext(), 749d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root x.toByteArray(), y.toByteArray()); 759d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 769d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root NativeCrypto.EC_GROUP_set_generator(ctx, generator.getContext(), n.toByteArray(), 779d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root h.toByteArray()); 789d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 799d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return group; 809d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 819d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 829d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root @Override 839d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root protected void finalize() throws Throwable { 849d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root try { 859d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root if (groupCtx != 0) { 869d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root NativeCrypto.EC_GROUP_clear_free(groupCtx); 879d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 889d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } finally { 899d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root super.finalize(); 909d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 919d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 929d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 939d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root @Override 949d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root public boolean equals(Object o) { 959d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root if (!(o instanceof OpenSSLECGroupContext)) { 969d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return false; 979d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 989d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 999d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final OpenSSLECGroupContext other = (OpenSSLECGroupContext) o; 1009d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return NativeCrypto.EC_GROUP_cmp(groupCtx, other.groupCtx); 1019d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 1029d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1039d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root @Override 1049d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root public int hashCode() { 1059d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root // TODO Auto-generated method stub 1069d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return super.hashCode(); 1079d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 1089d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1098acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice public long getContext() { 1109d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return groupCtx; 1119d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 1129d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1139d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root public static OpenSSLECGroupContext getInstance(ECParameterSpec params) 1149d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root throws InvalidAlgorithmParameterException { 115a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root final String curveName = params.getCurveName(); 116a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root if (curveName != null) { 117a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root return OpenSSLECGroupContext.getCurveByName(curveName); 118a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root } 119a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root 1209d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final EllipticCurve curve = params.getCurve(); 1219d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final ECField field = curve.getField(); 1229d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1239d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final int type; 1249d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final BigInteger p; 1259d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root if (field instanceof ECFieldFp) { 1269d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root type = NativeCrypto.EC_CURVE_GFP; 1279d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root p = ((ECFieldFp) field).getP(); 1289d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } else if (field instanceof ECFieldF2m) { 1299d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root type = NativeCrypto.EC_CURVE_GF2M; 1309d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root p = ((ECFieldF2m) field).getReductionPolynomial(); 1319d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } else { 1329d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root throw new InvalidParameterException("unhandled field class " 1339d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root + field.getClass().getName()); 1349d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 1359d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1369d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final ECPoint generator = params.getGenerator(); 1379d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root return OpenSSLECGroupContext.getInstance(type, p, curve.getA(), curve.getB(), 1389d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root generator.getAffineX(), generator.getAffineY(), params.getOrder(), 1399d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root BigInteger.valueOf(params.getCofactor())); 1409d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 1419d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1429d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root public ECParameterSpec getECParameterSpec() { 143a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root final String curveName = NativeCrypto.EC_GROUP_get_curve_name(groupCtx); 144a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root 1459d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final byte[][] curveParams = NativeCrypto.EC_GROUP_get_curve(groupCtx); 1469d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final BigInteger p = new BigInteger(curveParams[0]); 1479d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final BigInteger a = new BigInteger(curveParams[1]); 1489d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final BigInteger b = new BigInteger(curveParams[2]); 1499d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1509d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final ECField field; 1519d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final int type = NativeCrypto.get_EC_GROUP_type(groupCtx); 1529d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root if (type == NativeCrypto.EC_CURVE_GFP) { 1539d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root field = new ECFieldFp(p); 1549d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } else if (type == NativeCrypto.EC_CURVE_GF2M) { 1559d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root field = new ECFieldF2m(p.bitLength() - 1, p); 1569d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } else { 1579d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root throw new RuntimeException("unknown curve type " + type); 1589d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 1599d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1609d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final EllipticCurve curve = new EllipticCurve(field, a, b); 1619d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1629d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final OpenSSLECPointContext generatorCtx = new OpenSSLECPointContext(this, 1639d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root NativeCrypto.EC_GROUP_get_generator(groupCtx)); 1649d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final ECPoint generator = generatorCtx.getECPoint(); 1659d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 1669d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final BigInteger order = new BigInteger(NativeCrypto.EC_GROUP_get_order(groupCtx)); 1679d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root final BigInteger cofactor = new BigInteger(NativeCrypto.EC_GROUP_get_cofactor(groupCtx)); 1689d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root 169a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root return new ECParameterSpec(curve, generator, order, cofactor.intValue(), curveName); 1709d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root } 1719d2fb535e5d43ad34af09195d490da18a7694a48Kenny Root} 172