| package org.bouncycastle.eac.jcajce; |
| |
| import java.math.BigInteger; |
| import java.security.KeyFactory; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.security.Provider; |
| import java.security.PublicKey; |
| import java.security.interfaces.ECPublicKey; |
| import java.security.spec.ECField; |
| import java.security.spec.ECFieldF2m; |
| import java.security.spec.ECFieldFp; |
| import java.security.spec.ECParameterSpec; |
| import java.security.spec.ECPublicKeySpec; |
| import java.security.spec.EllipticCurve; |
| import java.security.spec.InvalidKeySpecException; |
| import java.security.spec.RSAPublicKeySpec; |
| |
| import org.bouncycastle.asn1.ASN1ObjectIdentifier; |
| import org.bouncycastle.asn1.eac.EACObjectIdentifiers; |
| import org.bouncycastle.asn1.eac.ECDSAPublicKey; |
| import org.bouncycastle.asn1.eac.PublicKeyDataObject; |
| import org.bouncycastle.asn1.eac.RSAPublicKey; |
| import org.bouncycastle.eac.EACException; |
| import org.bouncycastle.math.ec.ECAlgorithms; |
| import org.bouncycastle.math.ec.ECCurve; |
| import org.bouncycastle.math.ec.ECPoint; |
| 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 JcaPublicKeyConverter |
| { |
| private EACHelper helper = new DefaultEACHelper(); |
| |
| public JcaPublicKeyConverter setProvider(String providerName) |
| { |
| this.helper = new NamedEACHelper(providerName); |
| |
| return this; |
| } |
| |
| public JcaPublicKeyConverter setProvider(Provider provider) |
| { |
| this.helper = new ProviderEACHelper(provider); |
| |
| return this; |
| } |
| |
| public PublicKey getKey(PublicKeyDataObject publicKeyDataObject) |
| throws EACException, InvalidKeySpecException |
| { |
| if (publicKeyDataObject.getUsage().on(EACObjectIdentifiers.id_TA_ECDSA)) |
| { |
| return getECPublicKeyPublicKey((ECDSAPublicKey)publicKeyDataObject); |
| } |
| else |
| { |
| RSAPublicKey pubKey = (RSAPublicKey)publicKeyDataObject; |
| RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(pubKey.getModulus(), pubKey.getPublicExponent()); |
| |
| try |
| { |
| KeyFactory factk = helper.createKeyFactory("RSA"); |
| |
| return factk.generatePublic(pubKeySpec); |
| } |
| catch (NoSuchProviderException e) |
| { |
| throw new EACException("cannot find provider: " + e.getMessage(), e); |
| } |
| catch (NoSuchAlgorithmException e) |
| { |
| throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e); |
| } |
| } |
| } |
| |
| private PublicKey getECPublicKeyPublicKey(ECDSAPublicKey key) |
| throws EACException, InvalidKeySpecException |
| { |
| ECParameterSpec spec = getParams(key); |
| java.security.spec.ECPoint publicPoint = getPublicPoint(key); |
| ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(publicPoint, spec); |
| |
| KeyFactory factk; |
| try |
| { |
| factk = helper.createKeyFactory("ECDSA"); |
| } |
| catch (NoSuchProviderException e) |
| { |
| throw new EACException("cannot find provider: " + e.getMessage(), e); |
| } |
| catch (NoSuchAlgorithmException e) |
| { |
| throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e); |
| } |
| |
| return factk.generatePublic(pubKeySpec); |
| } |
| |
| private java.security.spec.ECPoint getPublicPoint(ECDSAPublicKey key) |
| { |
| if (!key.hasParameters()) |
| { |
| throw new IllegalArgumentException("Public key does not contains EC Params"); |
| } |
| |
| BigInteger p = key.getPrimeModulusP(); |
| ECCurve.Fp curve = new ECCurve.Fp(p, key.getFirstCoefA(), key.getSecondCoefB(), key.getOrderOfBasePointR(), key.getCofactorF()); |
| |
| ECPoint.Fp pubY = (ECPoint.Fp)curve.decodePoint(key.getPublicPointY()); |
| |
| return new java.security.spec.ECPoint(pubY.getAffineXCoord().toBigInteger(), pubY.getAffineYCoord().toBigInteger()); |
| } |
| |
| private ECParameterSpec getParams(ECDSAPublicKey key) |
| { |
| if (!key.hasParameters()) |
| { |
| throw new IllegalArgumentException("Public key does not contains EC Params"); |
| } |
| |
| BigInteger p = key.getPrimeModulusP(); |
| ECCurve.Fp curve = new ECCurve.Fp(p, key.getFirstCoefA(), key.getSecondCoefB(), key.getOrderOfBasePointR(), key.getCofactorF()); |
| |
| ECPoint G = curve.decodePoint(key.getBasePointG()); |
| |
| BigInteger order = key.getOrderOfBasePointR(); |
| BigInteger coFactor = key.getCofactorF(); |
| |
| EllipticCurve jcaCurve = convertCurve(curve); |
| |
| return new ECParameterSpec(jcaCurve, new java.security.spec.ECPoint(G.getAffineXCoord().toBigInteger(), G.getAffineYCoord().toBigInteger()), order, coFactor.intValue()); |
| } |
| |
| public PublicKeyDataObject getPublicKeyDataObject(ASN1ObjectIdentifier usage, PublicKey publicKey) |
| { |
| if (publicKey instanceof java.security.interfaces.RSAPublicKey) |
| { |
| java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey)publicKey; |
| |
| return new RSAPublicKey(usage, pubKey.getModulus(), pubKey.getPublicExponent()); |
| } |
| else |
| { |
| ECPublicKey pubKey = (ECPublicKey)publicKey; |
| java.security.spec.ECParameterSpec params = pubKey.getParams(); |
| |
| return new ECDSAPublicKey( |
| usage, |
| ((ECFieldFp)params.getCurve().getField()).getP(), |
| params.getCurve().getA(), params.getCurve().getB(), |
| convertPoint(convertCurve(params.getCurve(), params.getOrder(), params.getCofactor()), params.getGenerator()).getEncoded(), |
| params.getOrder(), |
| convertPoint(convertCurve(params.getCurve(), params.getOrder(), params.getCofactor()), pubKey.getW()).getEncoded(), |
| params.getCofactor()); |
| } |
| } |
| |
| private static org.bouncycastle.math.ec.ECPoint convertPoint( |
| ECCurve curve, |
| java.security.spec.ECPoint point) |
| { |
| return curve.createPoint(point.getAffineX(), point.getAffineY()); |
| } |
| |
| private static ECCurve convertCurve( |
| EllipticCurve ec, BigInteger order, int coFactor) |
| { |
| ECField field = ec.getField(); |
| BigInteger a = ec.getA(); |
| BigInteger b = ec.getB(); |
| |
| if (field instanceof ECFieldFp) |
| { |
| return new ECCurve.Fp(((ECFieldFp)field).getP(), a, b, order, BigInteger.valueOf(coFactor)); |
| } |
| else |
| { |
| throw new IllegalStateException("not implemented yet!!!"); |
| } |
| } |
| |
| private static EllipticCurve convertCurve( |
| ECCurve curve) |
| { |
| 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); |
| } |
| |
| private 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); |
| } |
| } |
| } |