package org.bouncycastle.jce.provider; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERInputStream; import org.bouncycastle.asn1.DERObject; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DEROutputStream; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X962NamedCurves; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECPoint; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jce.interfaces.ECPublicKey; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.jce.spec.ECPublicKeySpec; import org.bouncycastle.math.ec.ECPoint; public class JCEECPublicKey implements ECPublicKey { private String algorithm = "EC"; private ECPoint q; private ECParameterSpec ecSpec; JCEECPublicKey( String algorithm, ECPublicKeySpec spec) { this.algorithm = algorithm; this.q = spec.getQ(); this.ecSpec = spec.getParams(); } JCEECPublicKey( String algorithm, ECPublicKeyParameters params, ECParameterSpec spec) { ECDomainParameters dp = params.getParameters(); this.algorithm = algorithm; this.q = params.getQ(); if (spec == null) { this.ecSpec = new ECParameterSpec( dp.getCurve(), dp.getG(), dp.getN(), dp.getH(), dp.getSeed()); } else { this.ecSpec = spec; } } JCEECPublicKey( String algorithm, ECPublicKey key) { this.q = key.getQ(); this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParams(); } JCEECPublicKey( String algorithm, ECPoint q, ECParameterSpec ecSpec) { this.algorithm = algorithm; this.q = q; this.ecSpec = ecSpec; } JCEECPublicKey( SubjectPublicKeyInfo info) { X962Parameters params = new X962Parameters((DERObject)info.getAlgorithmId().getParameters()); if (params.isNamedCurve()) { DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters(); X9ECParameters ecP = X962NamedCurves.getByOID(oid); ecSpec = new ECNamedCurveParameterSpec( X962NamedCurves.getName(oid), ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); } else { X9ECParameters ecP = new X9ECParameters( (ASN1Sequence)params.getParameters()); ecSpec = new ECParameterSpec( ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); } DERBitString bits = info.getPublicKeyData(); byte[] data = bits.getBytes(); ASN1OctetString key = new DEROctetString(data); // // extra octet string - one of our old certs... // if (data[0] == 0x04 && data[1] == data.length - 2 && (data[2] == 0x02 || data[2] == 0x03)) { try { ByteArrayInputStream bIn = new ByteArrayInputStream(data); DERInputStream dIn = new DERInputStream(bIn); key = (ASN1OctetString)dIn.readObject(); } catch (IOException ex) { throw new IllegalArgumentException("error recovering public key"); } } X9ECPoint derQ = new X9ECPoint(ecSpec.getCurve(), key); this.q = derQ.getPoint(); } public String getAlgorithm() { return algorithm; } public String getFormat() { return "X.509"; } public byte[] getEncoded() { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); DEROutputStream dOut = new DEROutputStream(bOut); X962Parameters params = null; if (ecSpec instanceof ECNamedCurveParameterSpec) { params = new X962Parameters(X962NamedCurves.getOID(((ECNamedCurveParameterSpec)ecSpec).getName())); } else { X9ECParameters ecP = new X9ECParameters( ecSpec.getCurve(), ecSpec.getG(), ecSpec.getN(), ecSpec.getH(), ecSpec.getSeed()); params = new X962Parameters(ecP); } ASN1OctetString p = (ASN1OctetString)(new X9ECPoint(this.getQ()).getDERObject()); SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.getDERObject()), p.getOctets()); try { dOut.writeObject(info); dOut.close(); } catch (IOException e) { throw new RuntimeException("Error encoding EC public key"); } return bOut.toByteArray(); } public ECParameterSpec getParams() { return ecSpec; } public ECPoint getQ() { return q; } public String toString() { StringBuffer buf = new StringBuffer(); String nl = System.getProperty("line.separator"); buf.append("EC Public Key" + nl); buf.append(" X: " + this.getQ().getX().toBigInteger().toString(16) + nl); buf.append(" Y: " + this.getQ().getY().toBigInteger().toString(16) + nl); return buf.toString(); } /* private void readObject( ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); boolean named = in.readBoolean(); if (named) { ecSpec = new ECNamedCurveParameterSpec( in.readUTF(), (ECCurve)in.readObject(), (ECPoint)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject(), (byte[])in.readObject()); } else { ecSpec = new ECParameterSpec( (ECCurve)in.readObject(), (ECPoint)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject(), (byte[])in.readObject()); } } private void writeObject( ObjectOutputStream out) throws IOException { out.defaultWriteObject(); if (this.ecSpec instanceof ECNamedCurveParameterSpec) { ECNamedCurveParameterSpec namedSpec = (ECNamedCurveParameterSpec)ecSpec; out.writeBoolean(true); out.writeUTF(namedSpec.getName()); } else { out.writeBoolean(false); } out.writeObject(ecSpec.getCurve()); out.writeObject(ecSpec.getG()); out.writeObject(ecSpec.getN()); out.writeObject(ecSpec.getH()); out.writeObject(ecSpec.getSeed()); } */ }