001: package org.bouncycastle.jce.provider;
002:
003: import org.bouncycastle.asn1.ASN1Encodable;
004: import org.bouncycastle.asn1.ASN1InputStream;
005: import org.bouncycastle.asn1.ASN1OctetString;
006: import org.bouncycastle.asn1.ASN1Sequence;
007: import org.bouncycastle.asn1.DERBitString;
008: import org.bouncycastle.asn1.DERNull;
009: import org.bouncycastle.asn1.DERObject;
010: import org.bouncycastle.asn1.DERObjectIdentifier;
011: import org.bouncycastle.asn1.DEROctetString;
012: import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
013: import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
014: import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
015: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
016: import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
017: import org.bouncycastle.asn1.x9.X962Parameters;
018: import org.bouncycastle.asn1.x9.X9ECParameters;
019: import org.bouncycastle.asn1.x9.X9ECPoint;
020: import org.bouncycastle.asn1.x9.X9IntegerConverter;
021: import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
022: import org.bouncycastle.crypto.params.ECDomainParameters;
023: import org.bouncycastle.crypto.params.ECPublicKeyParameters;
024: import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
025: import org.bouncycastle.jce.interfaces.ECPointEncoder;
026: import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
027: import org.bouncycastle.jce.spec.ECNamedCurveSpec;
028: import org.bouncycastle.math.ec.ECCurve;
029:
030: import java.io.IOException;
031: import java.math.BigInteger;
032: import java.security.interfaces.ECPublicKey;
033: import java.security.spec.ECParameterSpec;
034: import java.security.spec.ECPoint;
035: import java.security.spec.ECPublicKeySpec;
036: import java.security.spec.EllipticCurve;
037:
038: public class JCEECPublicKey implements ECPublicKey,
039: org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder {
040: private String algorithm = "EC";
041: private org.bouncycastle.math.ec.ECPoint q;
042: private ECParameterSpec ecSpec;
043: private boolean withCompression;
044: private GOST3410PublicKeyAlgParameters gostParams;
045:
046: JCEECPublicKey(String algorithm, JCEECPublicKey key) {
047: this .algorithm = algorithm;
048: this .q = key.q;
049: this .ecSpec = key.ecSpec;
050: this .withCompression = key.withCompression;
051: this .gostParams = key.gostParams;
052: }
053:
054: JCEECPublicKey(String algorithm, ECPublicKeySpec spec) {
055: this .algorithm = algorithm;
056: this .ecSpec = spec.getParams();
057: this .q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
058: }
059:
060: JCEECPublicKey(String algorithm,
061: org.bouncycastle.jce.spec.ECPublicKeySpec spec) {
062: this .algorithm = algorithm;
063: this .q = spec.getQ();
064:
065: if (spec.getParams() != null) // can be null if implictlyCa
066: {
067: ECCurve curve = spec.getParams().getCurve();
068: EllipticCurve ellipticCurve = EC5Util.convertCurve(curve,
069: spec.getParams().getSeed());
070:
071: this .ecSpec = EC5Util.convertSpec(ellipticCurve, spec
072: .getParams());
073: } else {
074: if (q.getCurve() == null) {
075: org.bouncycastle.jce.spec.ECParameterSpec s = ProviderUtil
076: .getEcImplicitlyCa();
077:
078: q = s.getCurve().createPoint(q.getX().toBigInteger(),
079: q.getY().toBigInteger(), false);
080: }
081: this .ecSpec = null;
082: }
083: }
084:
085: JCEECPublicKey(String algorithm, ECPublicKeyParameters params,
086: ECParameterSpec spec) {
087: ECDomainParameters dp = params.getParameters();
088:
089: this .algorithm = algorithm;
090: this .q = params.getQ();
091:
092: if (spec == null) {
093: EllipticCurve ellipticCurve = EC5Util.convertCurve(dp
094: .getCurve(), dp.getSeed());
095:
096: this .ecSpec = createSpec(ellipticCurve, dp);
097: } else {
098: this .ecSpec = spec;
099: }
100: }
101:
102: JCEECPublicKey(String algorithm, ECPublicKeyParameters params,
103: org.bouncycastle.jce.spec.ECParameterSpec spec) {
104: ECDomainParameters dp = params.getParameters();
105:
106: this .algorithm = algorithm;
107: this .q = params.getQ();
108:
109: if (spec == null) {
110: EllipticCurve ellipticCurve = EC5Util.convertCurve(dp
111: .getCurve(), dp.getSeed());
112:
113: this .ecSpec = createSpec(ellipticCurve, dp);
114: } else {
115: EllipticCurve ellipticCurve = EC5Util.convertCurve(spec
116: .getCurve(), spec.getSeed());
117:
118: this .ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
119: }
120: }
121:
122: /*
123: * called for implicitCA
124: */
125: JCEECPublicKey(String algorithm, ECPublicKeyParameters params) {
126: this .algorithm = algorithm;
127: this .q = params.getQ();
128: this .ecSpec = null;
129: }
130:
131: private ECParameterSpec createSpec(EllipticCurve ellipticCurve,
132: ECDomainParameters dp) {
133: return new ECParameterSpec(ellipticCurve,
134: new ECPoint(dp.getG().getX().toBigInteger(), dp.getG()
135: .getY().toBigInteger()), dp.getN(), dp.getH()
136: .intValue());
137: }
138:
139: JCEECPublicKey(ECPublicKey key) {
140: this .algorithm = key.getAlgorithm();
141: this .ecSpec = key.getParams();
142: this .q = EC5Util.convertPoint(this .ecSpec, key.getW(), false);
143: }
144:
145: JCEECPublicKey(SubjectPublicKeyInfo info) {
146: if (info.getAlgorithmId().getObjectId().equals(
147: CryptoProObjectIdentifiers.gostR3410_2001)) {
148: DERBitString bits = info.getPublicKeyData();
149: ASN1OctetString key;
150: this .algorithm = "ECGOST3410";
151:
152: try {
153: ASN1InputStream aIn = new ASN1InputStream(bits
154: .getBytes());
155:
156: key = (ASN1OctetString) aIn.readObject();
157: } catch (IOException ex) {
158: throw new IllegalArgumentException(
159: "error recovering public key");
160: }
161:
162: byte[] keyEnc = key.getOctets();
163: byte[] x = new byte[32];
164: byte[] y = new byte[32];
165:
166: for (int i = 0; i != y.length; i++) {
167: x[i] = keyEnc[32 - 1 - i];
168: }
169:
170: for (int i = 0; i != x.length; i++) {
171: y[i] = keyEnc[64 - 1 - i];
172: }
173:
174: gostParams = new GOST3410PublicKeyAlgParameters(
175: (ASN1Sequence) info.getAlgorithmId()
176: .getParameters());
177:
178: ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable
179: .getParameterSpec(ECGOST3410NamedCurves
180: .getName(gostParams.getPublicKeyParamSet()));
181:
182: ECCurve curve = spec.getCurve();
183: EllipticCurve ellipticCurve = EC5Util.convertCurve(curve,
184: spec.getSeed());
185:
186: this .q = curve.createPoint(new BigInteger(1, x),
187: new BigInteger(1, y), false);
188:
189: ecSpec = new ECNamedCurveSpec(ECGOST3410NamedCurves
190: .getName(gostParams.getPublicKeyParamSet()),
191: ellipticCurve, new ECPoint(spec.getG().getX()
192: .toBigInteger(), spec.getG().getY()
193: .toBigInteger()), spec.getN(), spec.getH());
194:
195: } else {
196: X962Parameters params = new X962Parameters((DERObject) info
197: .getAlgorithmId().getParameters());
198: ECCurve curve;
199: EllipticCurve ellipticCurve;
200:
201: if (params.isNamedCurve()) {
202: DERObjectIdentifier oid = (DERObjectIdentifier) params
203: .getParameters();
204: X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
205:
206: curve = ecP.getCurve();
207: ellipticCurve = EC5Util.convertCurve(curve, ecP
208: .getSeed());
209:
210: ecSpec = new ECNamedCurveSpec(ECUtil.getCurveName(oid),
211: ellipticCurve, new ECPoint(ecP.getG().getX()
212: .toBigInteger(), ecP.getG().getY()
213: .toBigInteger()), ecP.getN(), ecP
214: .getH());
215: } else if (params.isImplicitlyCA()) {
216: ecSpec = null;
217: curve = ProviderUtil.getEcImplicitlyCa().getCurve();
218: } else {
219: X9ECParameters ecP = new X9ECParameters(
220: (ASN1Sequence) params.getParameters());
221:
222: curve = ecP.getCurve();
223: ellipticCurve = EC5Util.convertCurve(curve, ecP
224: .getSeed());
225:
226: this .ecSpec = new ECParameterSpec(ellipticCurve,
227: new ECPoint(ecP.getG().getX().toBigInteger(),
228: ecP.getG().getY().toBigInteger()), ecP
229: .getN(), ecP.getH().intValue());
230: }
231:
232: DERBitString bits = info.getPublicKeyData();
233: byte[] data = bits.getBytes();
234: ASN1OctetString key = new DEROctetString(data);
235:
236: //
237: // extra octet string - one of our old certs...
238: //
239: if (data[0] == 0x04 && data[1] == data.length - 2
240: && (data[2] == 0x02 || data[2] == 0x03)) {
241: int qLength = new X9IntegerConverter()
242: .getByteLength(curve);
243:
244: if (qLength >= data.length - 3) {
245: try {
246: ASN1InputStream aIn = new ASN1InputStream(data);
247:
248: key = (ASN1OctetString) aIn.readObject();
249: } catch (IOException ex) {
250: throw new IllegalArgumentException(
251: "error recovering public key");
252: }
253: }
254: }
255: X9ECPoint derQ = new X9ECPoint(curve, key);
256:
257: this .q = derQ.getPoint();
258: }
259: }
260:
261: public String getAlgorithm() {
262: return algorithm;
263: }
264:
265: public String getFormat() {
266: return "X.509";
267: }
268:
269: public byte[] getEncoded() {
270: ASN1Encodable params;
271: SubjectPublicKeyInfo info;
272:
273: if (algorithm.equals("ECGOST3410")) {
274: if (gostParams != null) {
275: params = gostParams;
276: } else {
277: params = new GOST3410PublicKeyAlgParameters(
278: ECGOST3410NamedCurves
279: .getOID(((ECNamedCurveSpec) ecSpec)
280: .getName()),
281: CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
282: }
283:
284: BigInteger bX = this .q.getX().toBigInteger();
285: BigInteger bY = this .q.getY().toBigInteger();
286: byte[] encKey = new byte[64];
287:
288: extractBytes(encKey, 0, bX);
289: extractBytes(encKey, 32, bY);
290:
291: info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(
292: CryptoProObjectIdentifiers.gostR3410_2001, params
293: .getDERObject()),
294: new DEROctetString(encKey));
295: } else {
296: if (ecSpec instanceof ECNamedCurveSpec) {
297: DERObjectIdentifier curveOid = ECUtil
298: .getNamedCurveOid(((ECNamedCurveSpec) ecSpec)
299: .getName());
300:
301: params = new X962Parameters(curveOid);
302: } else if (ecSpec == null) {
303: params = new X962Parameters(DERNull.INSTANCE);
304: } else {
305: ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
306:
307: X9ECParameters ecP = new X9ECParameters(curve, EC5Util
308: .convertPoint(curve, ecSpec.getGenerator(),
309: withCompression), ecSpec.getOrder(),
310: BigInteger.valueOf(ecSpec.getCofactor()),
311: ecSpec.getCurve().getSeed());
312:
313: params = new X962Parameters(ecP);
314: }
315:
316: ECCurve curve = this .engineGetQ().getCurve();
317: ASN1OctetString p = (ASN1OctetString) new X9ECPoint(curve
318: .createPoint(this .getQ().getX().toBigInteger(),
319: this .getQ().getY().toBigInteger(),
320: withCompression)).getDERObject();
321:
322: info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(
323: X9ObjectIdentifiers.id_ecPublicKey, params
324: .getDERObject()), p.getOctets());
325: }
326:
327: return info.getDEREncoded();
328: }
329:
330: private void extractBytes(byte[] encKey, int offSet, BigInteger bI) {
331: byte[] val = bI.toByteArray();
332: if (val.length < 32) {
333: byte[] tmp = new byte[32];
334: System.arraycopy(val, 0, tmp, tmp.length - val.length,
335: val.length);
336: }
337:
338: for (int i = 0; i != 32; i++) {
339: encKey[offSet + i] = val[val.length - 1 - i];
340: }
341: }
342:
343: public ECParameterSpec getParams() {
344: return ecSpec;
345: }
346:
347: public org.bouncycastle.jce.spec.ECParameterSpec getParameters() {
348: if (ecSpec == null) // implictlyCA
349: {
350: return null;
351: }
352:
353: return EC5Util.convertSpec(ecSpec, withCompression);
354: }
355:
356: public ECPoint getW() {
357: return new ECPoint(q.getX().toBigInteger(), q.getY()
358: .toBigInteger());
359: }
360:
361: public org.bouncycastle.math.ec.ECPoint getQ() {
362: if (ecSpec == null) {
363: if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp) {
364: return new org.bouncycastle.math.ec.ECPoint.Fp(null, q
365: .getX(), q.getY());
366: } else {
367: return new org.bouncycastle.math.ec.ECPoint.F2m(null, q
368: .getX(), q.getY());
369: }
370: }
371:
372: return q;
373: }
374:
375: org.bouncycastle.math.ec.ECPoint engineGetQ() {
376: return q;
377: }
378:
379: org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() {
380: if (ecSpec != null) {
381: return EC5Util.convertSpec(ecSpec, withCompression);
382: }
383:
384: return ProviderUtil.getEcImplicitlyCa();
385: }
386:
387: public String toString() {
388: StringBuffer buf = new StringBuffer();
389: String nl = System.getProperty("line.separator");
390:
391: buf.append("EC Public Key").append(nl);
392: buf.append(" X: ").append(
393: this .q.getX().toBigInteger().toString(16)).append(nl);
394: buf.append(" Y: ").append(
395: this .q.getY().toBigInteger().toString(16)).append(nl);
396:
397: return buf.toString();
398:
399: }
400:
401: public void setPointFormat(String style) {
402: withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
403: }
404:
405: public boolean equals(Object o) {
406: if (!(o instanceof JCEECPublicKey)) {
407: return false;
408: }
409:
410: JCEECPublicKey other = (JCEECPublicKey) o;
411:
412: return engineGetQ().equals(other.engineGetQ())
413: && (engineGetSpec().equals(other.engineGetSpec()));
414: }
415:
416: public int hashCode() {
417: return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
418: }
419: }
|