blob: de7536b453ecc7893e7a760fbde8231049430424 [file] [log] [blame]
package org.bouncycastle.jcajce.provider.asymmetric.util;
import java.math.BigInteger;
import java.security.spec.ECField;
import java.security.spec.ECFieldF2m;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.field.FiniteField;
import org.bouncycastle.math.field.Polynomial;
import org.bouncycastle.math.field.PolynomialExtensionField;
import org.bouncycastle.util.Arrays;
public class EC5Util
{
private static Map customCurves = new HashMap();
static
{
Enumeration e = CustomNamedCurves.getNames();
while (e.hasMoreElements())
{
String name = (String)e.nextElement();
X9ECParameters curveParams = ECNamedCurveTable.getByName(name);
if (curveParams != null) // there may not be a regular curve, may just be a custom curve.
{
customCurves.put(curveParams.getCurve(), CustomNamedCurves.getByName(name).getCurve());
}
}
X9ECParameters x9_25519 = CustomNamedCurves.getByName("Curve25519");
ECCurve c_25519 = x9_25519.getCurve();
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);
}
public static ECCurve getCurve(
ProviderConfiguration configuration,
X962Parameters params)
{
ECCurve curve;
Set acceptableCurves = configuration.getAcceptableNamedCurves();
if (params.isNamedCurve())
{
ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
if (acceptableCurves.isEmpty() || acceptableCurves.contains(oid))
{
X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
if (ecP == null)
{
ecP = (X9ECParameters)configuration.getAdditionalECParameters().get(oid);
}
curve = ecP.getCurve();
}
else
{
throw new IllegalStateException("named curve not acceptable");
}
}
else if (params.isImplicitlyCA())
{
curve = configuration.getEcImplicitlyCa().getCurve();
}
else if (acceptableCurves.isEmpty())
{
X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
curve = ecP.getCurve();
}
else
{
throw new IllegalStateException("encoded parameters not acceptable");
}
return curve;
}
public static ECDomainParameters getDomainParameters(
ProviderConfiguration configuration,
java.security.spec.ECParameterSpec params)
{
ECDomainParameters domainParameters;
if (params == null)
{
org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa();
domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed());
}
else
{
domainParameters = ECUtil.getDomainParameters(configuration, convertSpec(params, false));
}
return domainParameters;
}
public static ECParameterSpec convertToSpec(
X962Parameters params, ECCurve curve)
{
ECParameterSpec ecSpec;
EllipticCurve ellipticCurve;
if (params.isNamedCurve())
{
ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
if (ecP == null)
{
Map additionalECParameters = BouncyCastleProvider.CONFIGURATION.getAdditionalECParameters();
if (!additionalECParameters.isEmpty())
{
ecP = (X9ECParameters)additionalECParameters.get(oid);
}
}
ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
ecSpec = new ECNamedCurveSpec(
ECUtil.getCurveName(oid),
ellipticCurve,
convertPoint(ecP.getG()),
ecP.getN(),
ecP.getH());
}
else if (params.isImplicitlyCA())
{
ecSpec = null;
}
else
{
X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
if (ecP.getH() != null)
{
ecSpec = new ECParameterSpec(
ellipticCurve,
convertPoint(ecP.getG()),
ecP.getN(),
ecP.getH().intValue());
}
else
{
ecSpec = new ECParameterSpec(
ellipticCurve,
convertPoint(ecP.getG()),
ecP.getN(),
1); // TODO: not strictly correct... need to fix the test data...
}
}
return ecSpec;
}
public static ECParameterSpec convertToSpec(
X9ECParameters domainParameters)
{
return new ECParameterSpec(
convertCurve(domainParameters.getCurve(), null), // JDK 1.5 has trouble with this if it's not null...
EC5Util.convertPoint(domainParameters.getG()),
domainParameters.getN(),
domainParameters.getH().intValue());
}
public static ECParameterSpec convertToSpec(
ECDomainParameters domainParameters)
{
return new ECParameterSpec(
convertCurve(domainParameters.getCurve(), null), // JDK 1.5 has trouble with this if it's not null...
EC5Util.convertPoint(domainParameters.getG()),
domainParameters.getN(),
domainParameters.getH().intValue());
}
public static EllipticCurve convertCurve(
ECCurve curve,
byte[] seed)
{
ECField field = convertField(curve.getField());
BigInteger a = curve.getA().toBigInteger(), b = curve.getB().toBigInteger();
// TODO: the Sun EC implementation doesn't currently handle the seed properly
// so at the moment it's set to null. Should probably look at making this configurable
return new EllipticCurve(field, a, b, null);
}
public static ECCurve convertCurve(
EllipticCurve ec)
{
ECField field = ec.getField();
BigInteger a = ec.getA();
BigInteger b = ec.getB();
if (field instanceof ECFieldFp)
{
ECCurve.Fp curve = new ECCurve.Fp(((ECFieldFp)field).getP(), a, b);
if (customCurves.containsKey(curve))
{
return (ECCurve)customCurves.get(curve);
}
return curve;
}
else
{
ECFieldF2m fieldF2m = (ECFieldF2m)field;
int m = fieldF2m.getM();
int ks[] = ECUtil.convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
return new ECCurve.F2m(m, ks[0], ks[1], ks[2], a, b);
}
}
public static ECField convertField(FiniteField field)
{
if (ECAlgorithms.isFpField(field))
{
return new ECFieldFp(field.getCharacteristic());
}
else //if (ECAlgorithms.isF2mField(curveField))
{
Polynomial poly = ((PolynomialExtensionField)field).getMinimalPolynomial();
int[] exponents = poly.getExponentsPresent();
int[] ks = Arrays.reverse(Arrays.copyOfRange(exponents, 1, exponents.length - 1));
return new ECFieldF2m(poly.getDegree(), ks);
}
}
public static ECParameterSpec convertSpec(
EllipticCurve ellipticCurve,
org.bouncycastle.jce.spec.ECParameterSpec spec)
{
if (spec instanceof ECNamedCurveParameterSpec)
{
return new ECNamedCurveSpec(
((ECNamedCurveParameterSpec)spec).getName(),
ellipticCurve,
convertPoint(spec.getG()),
spec.getN(),
spec.getH());
}
else
{
return new ECParameterSpec(
ellipticCurve,
convertPoint(spec.getG()),
spec.getN(),
spec.getH().intValue());
}
}
public static org.bouncycastle.jce.spec.ECParameterSpec convertSpec(
ECParameterSpec ecSpec,
boolean withCompression)
{
ECCurve curve = convertCurve(ecSpec.getCurve());
if (ecSpec instanceof ECNamedCurveSpec)
{
return new org.bouncycastle.jce.spec.ECNamedCurveParameterSpec(
((ECNamedCurveSpec)ecSpec).getName(),
curve,
convertPoint(curve, ecSpec.getGenerator(), withCompression),
ecSpec.getOrder(),
BigInteger.valueOf(ecSpec.getCofactor()),
ecSpec.getCurve().getSeed());
}
else
{
return new org.bouncycastle.jce.spec.ECParameterSpec(
curve,
convertPoint(curve, ecSpec.getGenerator(), withCompression),
ecSpec.getOrder(),
BigInteger.valueOf(ecSpec.getCofactor()),
ecSpec.getCurve().getSeed());
}
}
public static org.bouncycastle.math.ec.ECPoint convertPoint(
ECParameterSpec ecSpec,
ECPoint point,
boolean withCompression)
{
return convertPoint(convertCurve(ecSpec.getCurve()), point, withCompression);
}
public static org.bouncycastle.math.ec.ECPoint convertPoint(
ECCurve curve,
ECPoint point,
boolean withCompression)
{
return curve.createPoint(point.getAffineX(), point.getAffineY());
}
public static ECPoint convertPoint(org.bouncycastle.math.ec.ECPoint point)
{
point = point.normalize();
return new ECPoint(
point.getAffineXCoord().toBigInteger(),
point.getAffineYCoord().toBigInteger());
}
}