BCECPublicKey.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.jcajce.provider.asymmetric.ec; 2 3import java.io.IOException; 4import java.io.ObjectInputStream; 5import java.io.ObjectOutputStream; 6import java.math.BigInteger; 7import java.security.interfaces.ECPublicKey; 8import java.security.spec.ECParameterSpec; 9import java.security.spec.ECPoint; 10import java.security.spec.ECPublicKeySpec; 11import java.security.spec.EllipticCurve; 12 13import org.bouncycastle.asn1.ASN1Encodable; 14import org.bouncycastle.asn1.ASN1ObjectIdentifier; 15import org.bouncycastle.asn1.ASN1OctetString; 16import org.bouncycastle.asn1.ASN1Primitive; 17import org.bouncycastle.asn1.DERBitString; 18import org.bouncycastle.asn1.DERNull; 19import org.bouncycastle.asn1.DEROctetString; 20import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 21import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 22import org.bouncycastle.asn1.x9.X962Parameters; 23import org.bouncycastle.asn1.x9.X9ECParameters; 24import org.bouncycastle.asn1.x9.X9ECPoint; 25import org.bouncycastle.asn1.x9.X9IntegerConverter; 26import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 27import org.bouncycastle.crypto.params.ECDomainParameters; 28import org.bouncycastle.crypto.params.ECPublicKeyParameters; 29import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; 30import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; 31import org.bouncycastle.jce.interfaces.ECPointEncoder; 32import org.bouncycastle.jce.provider.BouncyCastleProvider; 33import org.bouncycastle.jce.spec.ECNamedCurveSpec; 34import org.bouncycastle.math.ec.ECCurve; 35 36public class BCECPublicKey 37 implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder 38{ 39 static final long serialVersionUID = 2422789860422731812L; 40 41 private String algorithm = "EC"; 42 private boolean withCompression; 43 44 private transient org.bouncycastle.math.ec.ECPoint q; 45 private transient ECParameterSpec ecSpec; 46 private transient ProviderConfiguration configuration; 47 48 public BCECPublicKey( 49 String algorithm, 50 BCECPublicKey key) 51 { 52 this.algorithm = algorithm; 53 this.q = key.q; 54 this.ecSpec = key.ecSpec; 55 this.withCompression = key.withCompression; 56 this.configuration = key.configuration; 57 } 58 59 public BCECPublicKey( 60 String algorithm, 61 ECPublicKeySpec spec, 62 ProviderConfiguration configuration) 63 { 64 this.algorithm = algorithm; 65 this.ecSpec = spec.getParams(); 66 this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false); 67 this.configuration = configuration; 68 } 69 70 public BCECPublicKey( 71 String algorithm, 72 org.bouncycastle.jce.spec.ECPublicKeySpec spec, 73 ProviderConfiguration configuration) 74 { 75 this.algorithm = algorithm; 76 this.q = spec.getQ(); 77 78 if (spec.getParams() != null) // can be null if implictlyCa 79 { 80 ECCurve curve = spec.getParams().getCurve(); 81 EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed()); 82 83 this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams()); 84 } 85 else 86 { 87 if (q.getCurve() == null) 88 { 89 org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa(); 90 91 q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false); 92 } 93 this.ecSpec = null; 94 } 95 96 this.configuration = configuration; 97 } 98 99 public BCECPublicKey( 100 String algorithm, 101 ECPublicKeyParameters params, 102 ECParameterSpec spec, 103 ProviderConfiguration configuration) 104 { 105 ECDomainParameters dp = params.getParameters(); 106 107 this.algorithm = algorithm; 108 this.q = params.getQ(); 109 110 if (spec == null) 111 { 112 EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); 113 114 this.ecSpec = createSpec(ellipticCurve, dp); 115 } 116 else 117 { 118 this.ecSpec = spec; 119 } 120 121 this.configuration = configuration; 122 } 123 124 public BCECPublicKey( 125 String algorithm, 126 ECPublicKeyParameters params, 127 org.bouncycastle.jce.spec.ECParameterSpec spec, 128 ProviderConfiguration configuration) 129 { 130 ECDomainParameters dp = params.getParameters(); 131 132 this.algorithm = algorithm; 133 this.q = params.getQ(); 134 135 if (spec == null) 136 { 137 EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); 138 139 this.ecSpec = createSpec(ellipticCurve, dp); 140 } 141 else 142 { 143 EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed()); 144 145 this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec); 146 } 147 148 this.configuration = configuration; 149 } 150 151 /* 152 * called for implicitCA 153 */ 154 public BCECPublicKey( 155 String algorithm, 156 ECPublicKeyParameters params, 157 ProviderConfiguration configuration) 158 { 159 this.algorithm = algorithm; 160 this.q = params.getQ(); 161 this.ecSpec = null; 162 this.configuration = configuration; 163 } 164 165 public BCECPublicKey( 166 ECPublicKey key, 167 ProviderConfiguration configuration) 168 { 169 this.algorithm = key.getAlgorithm(); 170 this.ecSpec = key.getParams(); 171 this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false); 172 } 173 174 BCECPublicKey( 175 String algorithm, 176 SubjectPublicKeyInfo info, 177 ProviderConfiguration configuration) 178 { 179 this.algorithm = algorithm; 180 this.configuration = configuration; 181 populateFromPubKeyInfo(info); 182 } 183 184 private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp) 185 { 186 return new ECParameterSpec( 187 ellipticCurve, 188 new ECPoint( 189 dp.getG().getX().toBigInteger(), 190 dp.getG().getY().toBigInteger()), 191 dp.getN(), 192 dp.getH().intValue()); 193 } 194 195 private void populateFromPubKeyInfo(SubjectPublicKeyInfo info) 196 { 197 X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithm().getParameters()); 198 ECCurve curve; 199 EllipticCurve ellipticCurve; 200 201 if (params.isNamedCurve()) 202 { 203 ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters(); 204 X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); 205 206 curve = ecP.getCurve(); 207 ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed()); 208 209 ecSpec = new ECNamedCurveSpec( 210 ECUtil.getCurveName(oid), 211 ellipticCurve, 212 new ECPoint( 213 ecP.getG().getX().toBigInteger(), 214 ecP.getG().getY().toBigInteger()), 215 ecP.getN(), 216 ecP.getH()); 217 } 218 else if (params.isImplicitlyCA()) 219 { 220 ecSpec = null; 221 curve = configuration.getEcImplicitlyCa().getCurve(); 222 } 223 else 224 { 225 X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); 226 227 curve = ecP.getCurve(); 228 ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed()); 229 230 this.ecSpec = new ECParameterSpec( 231 ellipticCurve, 232 new ECPoint( 233 ecP.getG().getX().toBigInteger(), 234 ecP.getG().getY().toBigInteger()), 235 ecP.getN(), 236 ecP.getH().intValue()); 237 } 238 239 DERBitString bits = info.getPublicKeyData(); 240 byte[] data = bits.getBytes(); 241 ASN1OctetString key = new DEROctetString(data); 242 243 // 244 // extra octet string - one of our old certs... 245 // 246 if (data[0] == 0x04 && data[1] == data.length - 2 247 && (data[2] == 0x02 || data[2] == 0x03)) 248 { 249 int qLength = new X9IntegerConverter().getByteLength(curve); 250 251 if (qLength >= data.length - 3) 252 { 253 try 254 { 255 key = (ASN1OctetString) ASN1Primitive.fromByteArray(data); 256 } 257 catch (IOException ex) 258 { 259 throw new IllegalArgumentException("error recovering public key"); 260 } 261 } 262 } 263 X9ECPoint derQ = new X9ECPoint(curve, key); 264 265 this.q = derQ.getPoint(); 266 } 267 268 public String getAlgorithm() 269 { 270 return algorithm; 271 } 272 273 public String getFormat() 274 { 275 return "X.509"; 276 } 277 278 public byte[] getEncoded() 279 { 280 ASN1Encodable params; 281 SubjectPublicKeyInfo info; 282 283 if (ecSpec instanceof ECNamedCurveSpec) 284 { 285 ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); 286 if (curveOid == null) 287 { 288 curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); 289 } 290 params = new X962Parameters(curveOid); 291 } 292 else if (ecSpec == null) 293 { 294 params = new X962Parameters(DERNull.INSTANCE); 295 } 296 else 297 { 298 ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); 299 300 X9ECParameters ecP = new X9ECParameters( 301 curve, 302 EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), 303 ecSpec.getOrder(), 304 BigInteger.valueOf(ecSpec.getCofactor()), 305 ecSpec.getCurve().getSeed()); 306 307 params = new X962Parameters(ecP); 308 } 309 310 ECCurve curve = this.engineGetQ().getCurve(); 311 ASN1OctetString p = (ASN1OctetString) 312 new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive(); 313 314 info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); 315 316 return KeyUtil.getEncodedSubjectPublicKeyInfo(info); 317 } 318 319 private void extractBytes(byte[] encKey, int offSet, BigInteger bI) 320 { 321 byte[] val = bI.toByteArray(); 322 if (val.length < 32) 323 { 324 byte[] tmp = new byte[32]; 325 System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length); 326 val = tmp; 327 } 328 329 for (int i = 0; i != 32; i++) 330 { 331 encKey[offSet + i] = val[val.length - 1 - i]; 332 } 333 } 334 335 public ECParameterSpec getParams() 336 { 337 return ecSpec; 338 } 339 340 public org.bouncycastle.jce.spec.ECParameterSpec getParameters() 341 { 342 if (ecSpec == null) // implictlyCA 343 { 344 return null; 345 } 346 347 return EC5Util.convertSpec(ecSpec, withCompression); 348 } 349 350 public ECPoint getW() 351 { 352 return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger()); 353 } 354 355 public org.bouncycastle.math.ec.ECPoint getQ() 356 { 357 if (ecSpec == null) 358 { 359 if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp) 360 { 361 return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY()); 362 } 363 else 364 { 365 return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY()); 366 } 367 } 368 369 return q; 370 } 371 372 public org.bouncycastle.math.ec.ECPoint engineGetQ() 373 { 374 return q; 375 } 376 377 org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() 378 { 379 if (ecSpec != null) 380 { 381 return EC5Util.convertSpec(ecSpec, withCompression); 382 } 383 384 return configuration.getEcImplicitlyCa(); 385 } 386 387 public String toString() 388 { 389 StringBuffer buf = new StringBuffer(); 390 String nl = System.getProperty("line.separator"); 391 392 buf.append("EC Public Key").append(nl); 393 buf.append(" X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl); 394 buf.append(" Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl); 395 396 return buf.toString(); 397 398 } 399 400 public void setPointFormat(String style) 401 { 402 withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style)); 403 } 404 405 public boolean equals(Object o) 406 { 407 if (!(o instanceof BCECPublicKey)) 408 { 409 return false; 410 } 411 412 BCECPublicKey other = (BCECPublicKey)o; 413 414 return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec())); 415 } 416 417 public int hashCode() 418 { 419 return engineGetQ().hashCode() ^ engineGetSpec().hashCode(); 420 } 421 422 private void readObject( 423 ObjectInputStream in) 424 throws IOException, ClassNotFoundException 425 { 426 in.defaultReadObject(); 427 428 byte[] enc = (byte[])in.readObject(); 429 430 populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc))); 431 432 this.configuration = BouncyCastleProvider.CONFIGURATION; 433 } 434 435 private void writeObject( 436 ObjectOutputStream out) 437 throws IOException 438 { 439 out.defaultWriteObject(); 440 441 out.writeObject(this.getEncoded()); 442 } 443} 444