1package org.bouncycastle.jce.provider; 2 3import java.io.IOException; 4import java.io.ObjectInputStream; 5import java.io.ObjectOutputStream; 6import java.math.BigInteger; 7import java.security.interfaces.ECPrivateKey; 8import java.security.spec.ECParameterSpec; 9import java.security.spec.ECPoint; 10import java.security.spec.ECPrivateKeySpec; 11import java.security.spec.EllipticCurve; 12import java.util.Enumeration; 13 14import org.bouncycastle.asn1.ASN1Encodable; 15import org.bouncycastle.asn1.ASN1Encoding; 16import org.bouncycastle.asn1.ASN1Integer; 17import org.bouncycastle.asn1.ASN1ObjectIdentifier; 18import org.bouncycastle.asn1.ASN1Primitive; 19import org.bouncycastle.asn1.ASN1Sequence; 20import org.bouncycastle.asn1.DERBitString; 21import org.bouncycastle.asn1.DERNull; 22// BEGIN android-removed 23// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; 24// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; 25// END android-removed 26import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 27import org.bouncycastle.asn1.sec.ECPrivateKeyStructure; 28import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 29import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 30import org.bouncycastle.asn1.x9.X962Parameters; 31import org.bouncycastle.asn1.x9.X9ECParameters; 32import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 33import org.bouncycastle.crypto.params.ECDomainParameters; 34import org.bouncycastle.crypto.params.ECPrivateKeyParameters; 35import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; 36import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; 37import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; 38import org.bouncycastle.jce.interfaces.ECPointEncoder; 39import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; 40import org.bouncycastle.jce.spec.ECNamedCurveSpec; 41import org.bouncycastle.math.ec.ECCurve; 42 43public class JCEECPrivateKey 44 implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder 45{ 46 private String algorithm = "EC"; 47 private BigInteger d; 48 private ECParameterSpec ecSpec; 49 private boolean withCompression; 50 51 private DERBitString publicKey; 52 53 private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl(); 54 55 protected JCEECPrivateKey() 56 { 57 } 58 59 public JCEECPrivateKey( 60 ECPrivateKey key) 61 { 62 this.d = key.getS(); 63 this.algorithm = key.getAlgorithm(); 64 this.ecSpec = key.getParams(); 65 } 66 67 public JCEECPrivateKey( 68 String algorithm, 69 org.bouncycastle.jce.spec.ECPrivateKeySpec spec) 70 { 71 this.algorithm = algorithm; 72 this.d = spec.getD(); 73 74 if (spec.getParams() != null) // can be null if implicitlyCA 75 { 76 ECCurve curve = spec.getParams().getCurve(); 77 EllipticCurve ellipticCurve; 78 79 ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed()); 80 81 this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams()); 82 } 83 else 84 { 85 this.ecSpec = null; 86 } 87 } 88 89 90 public JCEECPrivateKey( 91 String algorithm, 92 ECPrivateKeySpec spec) 93 { 94 this.algorithm = algorithm; 95 this.d = spec.getS(); 96 this.ecSpec = spec.getParams(); 97 } 98 99 public JCEECPrivateKey( 100 String algorithm, 101 JCEECPrivateKey key) 102 { 103 this.algorithm = algorithm; 104 this.d = key.d; 105 this.ecSpec = key.ecSpec; 106 this.withCompression = key.withCompression; 107 this.attrCarrier = key.attrCarrier; 108 this.publicKey = key.publicKey; 109 } 110 111 public JCEECPrivateKey( 112 String algorithm, 113 ECPrivateKeyParameters params, 114 JCEECPublicKey pubKey, 115 ECParameterSpec spec) 116 { 117 ECDomainParameters dp = params.getParameters(); 118 119 this.algorithm = algorithm; 120 this.d = params.getD(); 121 122 if (spec == null) 123 { 124 EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); 125 126 this.ecSpec = new ECParameterSpec( 127 ellipticCurve, 128 new ECPoint( 129 dp.getG().getAffineXCoord().toBigInteger(), 130 dp.getG().getAffineYCoord().toBigInteger()), 131 dp.getN(), 132 dp.getH().intValue()); 133 } 134 else 135 { 136 this.ecSpec = spec; 137 } 138 139 publicKey = getPublicKeyDetails(pubKey); 140 } 141 142 public JCEECPrivateKey( 143 String algorithm, 144 ECPrivateKeyParameters params, 145 JCEECPublicKey pubKey, 146 org.bouncycastle.jce.spec.ECParameterSpec spec) 147 { 148 ECDomainParameters dp = params.getParameters(); 149 150 this.algorithm = algorithm; 151 this.d = params.getD(); 152 153 if (spec == null) 154 { 155 EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); 156 157 this.ecSpec = new ECParameterSpec( 158 ellipticCurve, 159 new ECPoint( 160 dp.getG().getAffineXCoord().toBigInteger(), 161 dp.getG().getAffineYCoord().toBigInteger()), 162 dp.getN(), 163 dp.getH().intValue()); 164 } 165 else 166 { 167 EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed()); 168 169 this.ecSpec = new ECParameterSpec( 170 ellipticCurve, 171 new ECPoint( 172 spec.getG().getAffineXCoord().toBigInteger(), 173 spec.getG().getAffineYCoord().toBigInteger()), 174 spec.getN(), 175 spec.getH().intValue()); 176 } 177 178 publicKey = getPublicKeyDetails(pubKey); 179 } 180 181 public JCEECPrivateKey( 182 String algorithm, 183 ECPrivateKeyParameters params) 184 { 185 this.algorithm = algorithm; 186 this.d = params.getD(); 187 this.ecSpec = null; 188 } 189 190 JCEECPrivateKey( 191 PrivateKeyInfo info) 192 throws IOException 193 { 194 populateFromPrivKeyInfo(info); 195 } 196 197 private void populateFromPrivKeyInfo(PrivateKeyInfo info) 198 throws IOException 199 { 200 X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters()); 201 202 if (params.isNamedCurve()) 203 { 204 ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); 205 X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); 206 207 // BEGIN android-removed 208 // if (ecP == null) // GOST Curve 209 // { 210 // ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid); 211 // EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed()); 212 // 213 // ecSpec = new ECNamedCurveSpec( 214 // ECGOST3410NamedCurves.getName(oid), 215 // ellipticCurve, 216 // new ECPoint( 217 // gParam.getG().getAffineXCoord().toBigInteger(), 218 // gParam.getG().getAffineYCoord().toBigInteger()), 219 // gParam.getN(), 220 // gParam.getH()); 221 // } 222 // else 223 // END android-removed 224 { 225 EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed()); 226 227 ecSpec = new ECNamedCurveSpec( 228 ECUtil.getCurveName(oid), 229 ellipticCurve, 230 new ECPoint( 231 ecP.getG().getAffineXCoord().toBigInteger(), 232 ecP.getG().getAffineYCoord().toBigInteger()), 233 ecP.getN(), 234 ecP.getH()); 235 } 236 } 237 else if (params.isImplicitlyCA()) 238 { 239 ecSpec = null; 240 } 241 else 242 { 243 X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); 244 EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed()); 245 246 this.ecSpec = new ECParameterSpec( 247 ellipticCurve, 248 new ECPoint( 249 ecP.getG().getAffineXCoord().toBigInteger(), 250 ecP.getG().getAffineYCoord().toBigInteger()), 251 ecP.getN(), 252 ecP.getH().intValue()); 253 } 254 255 ASN1Encodable privKey = info.parsePrivateKey(); 256 if (privKey instanceof ASN1Integer) 257 { 258 ASN1Integer derD = ASN1Integer.getInstance(privKey); 259 260 this.d = derD.getValue(); 261 } 262 else 263 { 264 ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)privKey); 265 266 this.d = ec.getKey(); 267 this.publicKey = ec.getPublicKey(); 268 } 269 } 270 271 public String getAlgorithm() 272 { 273 return algorithm; 274 } 275 276 /** 277 * return the encoding format we produce in getEncoded(). 278 * 279 * @return the string "PKCS#8" 280 */ 281 public String getFormat() 282 { 283 return "PKCS#8"; 284 } 285 286 /** 287 * Return a PKCS8 representation of the key. The sequence returned 288 * represents a full PrivateKeyInfo object. 289 * 290 * @return a PKCS8 representation of the key. 291 */ 292 public byte[] getEncoded() 293 { 294 X962Parameters params; 295 296 if (ecSpec instanceof ECNamedCurveSpec) 297 { 298 ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); 299 if (curveOid == null) // guess it's the OID 300 { 301 curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); 302 } 303 params = new X962Parameters(curveOid); 304 } 305 else if (ecSpec == null) 306 { 307 params = new X962Parameters(DERNull.INSTANCE); 308 } 309 else 310 { 311 ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve()); 312 313 X9ECParameters ecP = new X9ECParameters( 314 curve, 315 EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), 316 ecSpec.getOrder(), 317 BigInteger.valueOf(ecSpec.getCofactor()), 318 ecSpec.getCurve().getSeed()); 319 320 params = new X962Parameters(ecP); 321 } 322 323 PrivateKeyInfo info; 324 ECPrivateKeyStructure keyStructure; 325 326 if (publicKey != null) 327 { 328 keyStructure = new ECPrivateKeyStructure(this.getS(), publicKey, params); 329 } 330 else 331 { 332 keyStructure = new ECPrivateKeyStructure(this.getS(), params); 333 } 334 335 try 336 { 337 // BEGIN android-removed 338 // if (algorithm.equals("ECGOST3410")) 339 // { 340 // info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive()); 341 // } 342 // else 343 // END android-removed 344 { 345 346 info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive()); 347 } 348 349 return info.getEncoded(ASN1Encoding.DER); 350 } 351 catch (IOException e) 352 { 353 return null; 354 } 355 } 356 357 public ECParameterSpec getParams() 358 { 359 return ecSpec; 360 } 361 362 public org.bouncycastle.jce.spec.ECParameterSpec getParameters() 363 { 364 if (ecSpec == null) 365 { 366 return null; 367 } 368 369 return EC5Util.convertSpec(ecSpec, withCompression); 370 } 371 372 org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() 373 { 374 if (ecSpec != null) 375 { 376 return EC5Util.convertSpec(ecSpec, withCompression); 377 } 378 379 return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); 380 } 381 382 public BigInteger getS() 383 { 384 return d; 385 } 386 387 public BigInteger getD() 388 { 389 return d; 390 } 391 392 public void setBagAttribute( 393 ASN1ObjectIdentifier oid, 394 ASN1Encodable attribute) 395 { 396 attrCarrier.setBagAttribute(oid, attribute); 397 } 398 399 public ASN1Encodable getBagAttribute( 400 ASN1ObjectIdentifier oid) 401 { 402 return attrCarrier.getBagAttribute(oid); 403 } 404 405 public Enumeration getBagAttributeKeys() 406 { 407 return attrCarrier.getBagAttributeKeys(); 408 } 409 410 public void setPointFormat(String style) 411 { 412 withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style)); 413 } 414 415 public boolean equals(Object o) 416 { 417 if (!(o instanceof JCEECPrivateKey)) 418 { 419 return false; 420 } 421 422 JCEECPrivateKey other = (JCEECPrivateKey)o; 423 424 return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec())); 425 } 426 427 public int hashCode() 428 { 429 return getD().hashCode() ^ engineGetSpec().hashCode(); 430 } 431 432 public String toString() 433 { 434 StringBuffer buf = new StringBuffer(); 435 String nl = System.getProperty("line.separator"); 436 437 buf.append("EC Private Key").append(nl); 438 buf.append(" S: ").append(this.d.toString(16)).append(nl); 439 440 return buf.toString(); 441 442 } 443 444 private DERBitString getPublicKeyDetails(JCEECPublicKey pub) 445 { 446 try 447 { 448 SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded())); 449 450 return info.getPublicKeyData(); 451 } 452 catch (IOException e) 453 { // should never happen 454 return null; 455 } 456 } 457 458 private void readObject( 459 ObjectInputStream in) 460 throws IOException, ClassNotFoundException 461 { 462 byte[] enc = (byte[])in.readObject(); 463 464 populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc))); 465 466 this.algorithm = (String)in.readObject(); 467 this.withCompression = in.readBoolean(); 468 this.attrCarrier = new PKCS12BagAttributeCarrierImpl(); 469 470 attrCarrier.readObject(in); 471 } 472 473 private void writeObject( 474 ObjectOutputStream out) 475 throws IOException 476 { 477 out.writeObject(this.getEncoded()); 478 out.writeObject(algorithm); 479 out.writeBoolean(withCompression); 480 481 attrCarrier.writeObject(out); 482 } 483} 484