JCEECPublicKey.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
122144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughespackage org.bouncycastle.jce.provider; 222144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes 322144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.io.IOException; 422144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.io.ObjectInputStream; 522144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.io.ObjectOutputStream; 622144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.math.BigInteger; 722144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.security.interfaces.ECPublicKey; 822144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.security.spec.ECParameterSpec; 922144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.security.spec.ECPoint; 1022144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.security.spec.ECPublicKeySpec; 1122144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport java.security.spec.EllipticCurve; 1222144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes 1322144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport org.bouncycastle.asn1.ASN1Encodable; 1422144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport org.bouncycastle.asn1.ASN1ObjectIdentifier; 1522144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport org.bouncycastle.asn1.ASN1OctetString; 1622144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport org.bouncycastle.asn1.ASN1Primitive; 1722144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport org.bouncycastle.asn1.ASN1Sequence; 1822144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport org.bouncycastle.asn1.DERBitString; 1922144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport org.bouncycastle.asn1.DERNull; 2022144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughesimport org.bouncycastle.asn1.DEROctetString; 2122144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes// BEGIN android-removed 2222144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; 2322144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; 2422144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; 256dc85575000127630489b407c50a4b3ea87c9acbKeith Whitwell// END android-removed 266dc85575000127630489b407c50a4b3ea87c9acbKeith Whitwellimport org.bouncycastle.asn1.x509.AlgorithmIdentifier; 27b014986fdb259eb60bd3e5a3fbcfcb218969f5f5Keith Whitwellimport org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 28b014986fdb259eb60bd3e5a3fbcfcb218969f5f5Keith Whitwellimport org.bouncycastle.asn1.x9.X962Parameters; 29b014986fdb259eb60bd3e5a3fbcfcb218969f5f5Keith Whitwellimport org.bouncycastle.asn1.x9.X9ECParameters; 30af12de279ea36fa5bc985bbe27ca9e93529cd82fVinson Leeimport org.bouncycastle.asn1.x9.X9ECPoint; 31af12de279ea36fa5bc985bbe27ca9e93529cd82fVinson Leeimport org.bouncycastle.asn1.x9.X9IntegerConverter; 32af12de279ea36fa5bc985bbe27ca9e93529cd82fVinson Leeimport org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 33af12de279ea36fa5bc985bbe27ca9e93529cd82fVinson Leeimport org.bouncycastle.crypto.params.ECDomainParameters; 34b014986fdb259eb60bd3e5a3fbcfcb218969f5f5Keith Whitwellimport org.bouncycastle.crypto.params.ECPublicKeyParameters; 35cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wuimport org.bouncycastle.jcajce.provider.asymmetric.ec.EC5Util; 36b014986fdb259eb60bd3e5a3fbcfcb218969f5f5Keith Whitwellimport org.bouncycastle.jcajce.provider.asymmetric.ec.ECUtil; 370dc989ea5b54a35bbafb00a0d40a799f8cdf0facIan Romanickimport org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; 380dc989ea5b54a35bbafb00a0d40a799f8cdf0facIan Romanick// BEGIN android-removed 390dc989ea5b54a35bbafb00a0d40a799f8cdf0facIan Romanick// import org.bouncycastle.jce.ECGOST3410NamedCurveTable; 40b014986fdb259eb60bd3e5a3fbcfcb218969f5f5Keith Whitwell// END android-removed 41cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wuimport org.bouncycastle.jce.interfaces.ECPointEncoder; 42cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wu// BEGIN android-removed 439520f483b8f1e45fa474674b415554988de5d8d3Brian Paul// import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; 44cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wu// END android-removed 45cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wuimport org.bouncycastle.jce.spec.ECNamedCurveSpec; 46cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wuimport org.bouncycastle.math.ec.ECCurve; 47cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wu 48cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wupublic class JCEECPublicKey 49cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wu implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder 50cef97267d696d37f4dccb22951499ca25d5d87adChia-I Wu{ 51 private String algorithm = "EC"; 52 private org.bouncycastle.math.ec.ECPoint q; 53 private ECParameterSpec ecSpec; 54 private boolean withCompression; 55 // BEGIN android-removed 56 // private GOST3410PublicKeyAlgParameters gostParams; 57 // END android-removed 58 59 public JCEECPublicKey( 60 String algorithm, 61 JCEECPublicKey key) 62 { 63 this.algorithm = algorithm; 64 this.q = key.q; 65 this.ecSpec = key.ecSpec; 66 this.withCompression = key.withCompression; 67 // BEGIN android-removed 68 // this.gostParams = key.gostParams; 69 // END android-removed 70 } 71 72 public JCEECPublicKey( 73 String algorithm, 74 ECPublicKeySpec spec) 75 { 76 this.algorithm = algorithm; 77 this.ecSpec = spec.getParams(); 78 this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false); 79 } 80 81 public JCEECPublicKey( 82 String algorithm, 83 org.bouncycastle.jce.spec.ECPublicKeySpec spec) 84 { 85 this.algorithm = algorithm; 86 this.q = spec.getQ(); 87 88 if (spec.getParams() != null) // can be null if implictlyCa 89 { 90 ECCurve curve = spec.getParams().getCurve(); 91 EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed()); 92 93 this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams()); 94 } 95 else 96 { 97 if (q.getCurve() == null) 98 { 99 org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); 100 101 q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false); 102 } 103 this.ecSpec = null; 104 } 105 } 106 107 public JCEECPublicKey( 108 String algorithm, 109 ECPublicKeyParameters params, 110 ECParameterSpec spec) 111 { 112 ECDomainParameters dp = params.getParameters(); 113 114 this.algorithm = algorithm; 115 this.q = params.getQ(); 116 117 if (spec == null) 118 { 119 EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); 120 121 this.ecSpec = createSpec(ellipticCurve, dp); 122 } 123 else 124 { 125 this.ecSpec = spec; 126 } 127 } 128 129 public JCEECPublicKey( 130 String algorithm, 131 ECPublicKeyParameters params, 132 org.bouncycastle.jce.spec.ECParameterSpec spec) 133 { 134 ECDomainParameters dp = params.getParameters(); 135 136 this.algorithm = algorithm; 137 this.q = params.getQ(); 138 139 if (spec == null) 140 { 141 EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); 142 143 this.ecSpec = createSpec(ellipticCurve, dp); 144 } 145 else 146 { 147 EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed()); 148 149 this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec); 150 } 151 } 152 153 /* 154 * called for implicitCA 155 */ 156 public JCEECPublicKey( 157 String algorithm, 158 ECPublicKeyParameters params) 159 { 160 this.algorithm = algorithm; 161 this.q = params.getQ(); 162 this.ecSpec = null; 163 } 164 165 private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp) 166 { 167 return new ECParameterSpec( 168 ellipticCurve, 169 new ECPoint( 170 dp.getG().getX().toBigInteger(), 171 dp.getG().getY().toBigInteger()), 172 dp.getN(), 173 dp.getH().intValue()); 174 } 175 176 public JCEECPublicKey( 177 ECPublicKey key) 178 { 179 this.algorithm = key.getAlgorithm(); 180 this.ecSpec = key.getParams(); 181 this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false); 182 } 183 184 JCEECPublicKey( 185 SubjectPublicKeyInfo info) 186 { 187 populateFromPubKeyInfo(info); 188 } 189 190 private void populateFromPubKeyInfo(SubjectPublicKeyInfo info) 191 { 192 // BEGIN android-removed 193 // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001)) 194 // { 195 // DERBitString bits = info.getPublicKeyData(); 196 // ASN1OctetString key; 197 // this.algorithm = "ECGOST3410"; 198 // 199 // try 200 // { 201 // key = (ASN1OctetString) ASN1Primitive.fromByteArray(bits.getBytes()); 202 // } 203 // catch (IOException ex) 204 // { 205 // throw new IllegalArgumentException("error recovering public key"); 206 // } 207 // 208 // byte[] keyEnc = key.getOctets(); 209 // byte[] x = new byte[32]; 210 // byte[] y = new byte[32]; 211 // 212 // for (int i = 0; i != x.length; i++) 213 // { 214 // x[i] = keyEnc[32 - 1 - i]; 215 // } 216 // 217 // for (int i = 0; i != y.length; i++) 218 // { 219 // y[i] = keyEnc[64 - 1 - i]; 220 // } 221 // 222 // gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters()); 223 // 224 // ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet())); 225 // 226 // ECCurve curve = spec.getCurve(); 227 // EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed()); 228 // 229 // this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false); 230 // 231 // ecSpec = new ECNamedCurveSpec( 232 // ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()), 233 // ellipticCurve, 234 // new ECPoint( 235 // spec.getG().getX().toBigInteger(), 236 // spec.getG().getY().toBigInteger()), 237 // spec.getN(), spec.getH()); 238 // 239 // } 240 // else 241 // END android-removed 242 { 243 X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithmId().getParameters()); 244 ECCurve curve; 245 EllipticCurve ellipticCurve; 246 247 if (params.isNamedCurve()) 248 { 249 ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters(); 250 X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); 251 252 curve = ecP.getCurve(); 253 ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed()); 254 255 ecSpec = new ECNamedCurveSpec( 256 ECUtil.getCurveName(oid), 257 ellipticCurve, 258 new ECPoint( 259 ecP.getG().getX().toBigInteger(), 260 ecP.getG().getY().toBigInteger()), 261 ecP.getN(), 262 ecP.getH()); 263 } 264 else if (params.isImplicitlyCA()) 265 { 266 ecSpec = null; 267 curve = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(); 268 } 269 else 270 { 271 X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); 272 273 curve = ecP.getCurve(); 274 ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed()); 275 276 this.ecSpec = new ECParameterSpec( 277 ellipticCurve, 278 new ECPoint( 279 ecP.getG().getX().toBigInteger(), 280 ecP.getG().getY().toBigInteger()), 281 ecP.getN(), 282 ecP.getH().intValue()); 283 } 284 285 DERBitString bits = info.getPublicKeyData(); 286 byte[] data = bits.getBytes(); 287 ASN1OctetString key = new DEROctetString(data); 288 289 // 290 // extra octet string - one of our old certs... 291 // 292 if (data[0] == 0x04 && data[1] == data.length - 2 293 && (data[2] == 0x02 || data[2] == 0x03)) 294 { 295 int qLength = new X9IntegerConverter().getByteLength(curve); 296 297 if (qLength >= data.length - 3) 298 { 299 try 300 { 301 key = (ASN1OctetString) ASN1Primitive.fromByteArray(data); 302 } 303 catch (IOException ex) 304 { 305 throw new IllegalArgumentException("error recovering public key"); 306 } 307 } 308 } 309 X9ECPoint derQ = new X9ECPoint(curve, key); 310 311 this.q = derQ.getPoint(); 312 } 313 } 314 315 public String getAlgorithm() 316 { 317 return algorithm; 318 } 319 320 public String getFormat() 321 { 322 return "X.509"; 323 } 324 325 public byte[] getEncoded() 326 { 327 ASN1Encodable params; 328 SubjectPublicKeyInfo info; 329 330 // BEGIN android-removed 331 // if (algorithm.equals("ECGOST3410")) 332 // { 333 // if (gostParams != null) 334 // { 335 // params = gostParams; 336 // } 337 // else 338 // { 339 // if (ecSpec instanceof ECNamedCurveSpec) 340 // { 341 // params = new GOST3410PublicKeyAlgParameters( 342 // ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()), 343 // CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet); 344 // } 345 // else 346 // { // strictly speaking this may not be applicable... 347 // ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); 348 // 349 // X9ECParameters ecP = new X9ECParameters( 350 // curve, 351 // EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), 352 // ecSpec.getOrder(), 353 // BigInteger.valueOf(ecSpec.getCofactor()), 354 // ecSpec.getCurve().getSeed()); 355 // 356 // params = new X962Parameters(ecP); 357 // } 358 // } 359 // 360 // BigInteger bX = this.q.getX().toBigInteger(); 361 // BigInteger bY = this.q.getY().toBigInteger(); 362 // byte[] encKey = new byte[64]; 363 // 364 // extractBytes(encKey, 0, bX); 365 // extractBytes(encKey, 32, bY); 366 // 367 // info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey)); 368 // } 369 // else 370 // END android-removed 371 { 372 if (ecSpec instanceof ECNamedCurveSpec) 373 { 374 ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); 375 if (curveOid == null) 376 { 377 curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); 378 } 379 params = new X962Parameters(curveOid); 380 } 381 else if (ecSpec == null) 382 { 383 params = new X962Parameters(DERNull.INSTANCE); 384 } 385 else 386 { 387 ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); 388 389 X9ECParameters ecP = new X9ECParameters( 390 curve, 391 EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), 392 ecSpec.getOrder(), 393 BigInteger.valueOf(ecSpec.getCofactor()), 394 ecSpec.getCurve().getSeed()); 395 396 params = new X962Parameters(ecP); 397 } 398 399 ECCurve curve = this.engineGetQ().getCurve(); 400 ASN1OctetString p = (ASN1OctetString) 401 new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive(); 402 403 info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); 404 } 405 406 return KeyUtil.getEncodedSubjectPublicKeyInfo(info); 407 } 408 409 private void extractBytes(byte[] encKey, int offSet, BigInteger bI) 410 { 411 byte[] val = bI.toByteArray(); 412 if (val.length < 32) 413 { 414 byte[] tmp = new byte[32]; 415 System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length); 416 val = tmp; 417 } 418 419 for (int i = 0; i != 32; i++) 420 { 421 encKey[offSet + i] = val[val.length - 1 - i]; 422 } 423 } 424 425 public ECParameterSpec getParams() 426 { 427 return ecSpec; 428 } 429 430 public org.bouncycastle.jce.spec.ECParameterSpec getParameters() 431 { 432 if (ecSpec == null) // implictlyCA 433 { 434 return null; 435 } 436 437 return EC5Util.convertSpec(ecSpec, withCompression); 438 } 439 440 public ECPoint getW() 441 { 442 return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger()); 443 } 444 445 public org.bouncycastle.math.ec.ECPoint getQ() 446 { 447 if (ecSpec == null) 448 { 449 if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp) 450 { 451 return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY()); 452 } 453 else 454 { 455 return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY()); 456 } 457 } 458 459 return q; 460 } 461 462 public org.bouncycastle.math.ec.ECPoint engineGetQ() 463 { 464 return q; 465 } 466 467 org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() 468 { 469 if (ecSpec != null) 470 { 471 return EC5Util.convertSpec(ecSpec, withCompression); 472 } 473 474 return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); 475 } 476 477 public String toString() 478 { 479 StringBuffer buf = new StringBuffer(); 480 String nl = System.getProperty("line.separator"); 481 482 buf.append("EC Public Key").append(nl); 483 buf.append(" X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl); 484 buf.append(" Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl); 485 486 return buf.toString(); 487 488 } 489 490 public void setPointFormat(String style) 491 { 492 withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style)); 493 } 494 495 public boolean equals(Object o) 496 { 497 if (!(o instanceof JCEECPublicKey)) 498 { 499 return false; 500 } 501 502 JCEECPublicKey other = (JCEECPublicKey)o; 503 504 return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec())); 505 } 506 507 public int hashCode() 508 { 509 return engineGetQ().hashCode() ^ engineGetSpec().hashCode(); 510 } 511 512 private void readObject( 513 ObjectInputStream in) 514 throws IOException, ClassNotFoundException 515 { 516 byte[] enc = (byte[])in.readObject(); 517 518 populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc))); 519 520 this.algorithm = (String)in.readObject(); 521 this.withCompression = in.readBoolean(); 522 } 523 524 private void writeObject( 525 ObjectOutputStream out) 526 throws IOException 527 { 528 out.writeObject(this.getEncoded()); 529 out.writeObject(algorithm); 530 out.writeBoolean(withCompression); 531 } 532} 533