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