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