1 package org.bouncycastle.openssl; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.IOException; 5 import java.io.Reader; 6 import java.security.AlgorithmParameters; 7 import java.security.KeyFactory; 8 import java.security.KeyPair; 9 import java.security.NoSuchAlgorithmException; 10 import java.security.NoSuchProviderException; 11 import java.security.PublicKey; 12 import java.security.cert.CertificateFactory; 13 import java.security.spec.DSAPrivateKeySpec; 14 import java.security.spec.DSAPublicKeySpec; 15 import java.security.spec.InvalidKeySpecException; 16 import java.security.spec.KeySpec; 17 import java.security.spec.PKCS8EncodedKeySpec; 18 import java.security.spec.RSAPrivateCrtKeySpec; 19 import java.security.spec.RSAPublicKeySpec; 20 import java.security.spec.X509EncodedKeySpec; 21 import java.util.HashMap; 22 import java.util.Iterator; 23 import java.util.List; 24 import java.util.Map; 25 import java.util.StringTokenizer; 26 27 import javax.crypto.Cipher; 28 import javax.crypto.SecretKey; 29 import javax.crypto.SecretKeyFactory; 30 import javax.crypto.spec.PBEKeySpec; 31 import javax.crypto.spec.PBEParameterSpec; 32 33 import org.bouncycastle.asn1.ASN1InputStream; 34 import org.bouncycastle.asn1.ASN1Object; 35 import org.bouncycastle.asn1.ASN1Sequence; 36 import org.bouncycastle.asn1.DERInteger; 37 import org.bouncycastle.asn1.DERObjectIdentifier; 38 import org.bouncycastle.asn1.cms.ContentInfo; 39 import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; 40 import org.bouncycastle.asn1.pkcs.EncryptionScheme; 41 import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; 42 import org.bouncycastle.asn1.pkcs.PBEParameter; 43 import org.bouncycastle.asn1.pkcs.PBES2Parameters; 44 import org.bouncycastle.asn1.pkcs.PBKDF2Params; 45 import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; 46 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 47 import org.bouncycastle.asn1.sec.ECPrivateKeyStructure; 48 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 49 import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; 50 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 51 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 52 import org.bouncycastle.jce.ECNamedCurveTable; 53 import org.bouncycastle.jce.PKCS10CertificationRequest; 54 import org.bouncycastle.util.encoders.Hex; 55 import org.bouncycastle.util.io.pem.PemHeader; 56 import org.bouncycastle.util.io.pem.PemObject; 57 import org.bouncycastle.util.io.pem.PemObjectParser; 58 import org.bouncycastle.util.io.pem.PemReader; 59 import org.bouncycastle.x509.X509V2AttributeCertificate; 60 61 /** 62 * Class for reading OpenSSL PEM encoded streams containing 63 * X509 certificates, PKCS8 encoded keys and PKCS7 objects. 64 * <p> 65 * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and 66 * Certificates will be returned using the appropriate java.security type (KeyPair, PublicKey, X509Certificate, 67 * or X509CRL). In the case of a Certificate Request a PKCS10CertificationRequest will be returned. 68 * </p> 69 */ 70 public class PEMReader 71 extends PemReader 72 { 73 private final Map parsers = new HashMap(); 74 75 private PasswordFinder pFinder; 76 77 78 /** 79 * Create a new PEMReader 80 * 81 * @param reader the Reader 82 */ 83 public PEMReader( 84 Reader reader) 85 { 86 this(reader, null, "BC"); 87 } 88 89 /** 90 * Create a new PEMReader with a password finder 91 * 92 * @param reader the Reader 93 * @param pFinder the password finder 94 */ 95 public PEMReader( 96 Reader reader, 97 PasswordFinder pFinder) 98 { 99 this(reader, pFinder, "BC"); 100 } 101 102 /** 103 * Create a new PEMReader with a password finder 104 * 105 * @param reader the Reader 106 * @param pFinder the password finder 107 * @param provider the cryptography provider to use 108 */ 109 public PEMReader( 110 Reader reader, 111 PasswordFinder pFinder, 112 String provider) 113 { 114 this(reader, pFinder, provider, provider); 115 } 116 117 /** 118 * Create a new PEMReader with a password finder and differing providers for secret and public key 119 * operations. 120 * 121 * @param reader the Reader 122 * @param pFinder the password finder 123 * @param symProvider provider to use for symmetric operations 124 * @param asymProvider provider to use for asymmetric (public/private key) operations 125 */ 126 public PEMReader( 127 Reader reader, 128 PasswordFinder pFinder, 129 String symProvider, 130 String asymProvider) 131 { 132 super(reader); 133 134 this.pFinder = pFinder; 135 136 parsers.put("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser()); 137 parsers.put("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser()); 138 parsers.put("CERTIFICATE", new X509CertificateParser(asymProvider)); 139 parsers.put("X509 CERTIFICATE", new X509CertificateParser(asymProvider)); 140 parsers.put("X509 CRL", new X509CRLParser(asymProvider)); 141 parsers.put("PKCS7", new PKCS7Parser()); 142 parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser()); 143 parsers.put("EC PARAMETERS", new ECNamedCurveSpecParser()); 144 parsers.put("PUBLIC KEY", new PublicKeyParser(asymProvider)); 145 parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser(asymProvider)); 146 parsers.put("RSA PRIVATE KEY", new RSAKeyPairParser(asymProvider)); 147 parsers.put("DSA PRIVATE KEY", new DSAKeyPairParser(asymProvider)); 148 parsers.put("EC PRIVATE KEY", new ECDSAKeyPairParser(asymProvider)); 149 parsers.put("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser(symProvider, asymProvider)); 150 parsers.put("PRIVATE KEY", new PrivateKeyParser(asymProvider)); 151 } 152 153 public Object readObject() 154 throws IOException 155 { 156 PemObject obj = readPemObject(); 157 158 if (obj != null) 159 { 160 String type = obj.getType(); 161 if (parsers.containsKey(type)) 162 { 163 return ((PemObjectParser)parsers.get(type)).parseObject(obj); 164 } 165 else 166 { 167 throw new IOException("unrecognised object: " + type); 168 } 169 } 170 171 return null; 172 } 173 174 private abstract class KeyPairParser 175 implements PemObjectParser 176 { 177 protected String provider; 178 179 public KeyPairParser(String provider) 180 { 181 this.provider = provider; 182 } 183 184 /** 185 * Read a Key Pair 186 */ 187 protected ASN1Sequence readKeyPair( 188 PemObject obj) 189 throws IOException 190 { 191 boolean isEncrypted = false; 192 String dekInfo = null; 193 List headers = obj.getHeaders(); 194 195 for (Iterator it = headers.iterator(); it.hasNext();) 196 { 197 PemHeader hdr = (PemHeader)it.next(); 198 199 if (hdr.getName().equals("Proc-Type") && hdr.getValue().equals("4,ENCRYPTED")) 200 { 201 isEncrypted = true; 202 } 203 else if (hdr.getName().equals("DEK-Info")) 204 { 205 dekInfo = hdr.getValue(); 206 } 207 } 208 209 // 210 // extract the key 211 // 212 byte[] keyBytes = obj.getContent(); 213 214 if (isEncrypted) 215 { 216 if (pFinder == null) 217 { 218 throw new PasswordException("No password finder specified, but a password is required"); 219 } 220 221 char[] password = pFinder.getPassword(); 222 223 if (password == null) 224 { 225 throw new PasswordException("Password is null, but a password is required"); 226 } 227 228 StringTokenizer tknz = new StringTokenizer(dekInfo, ","); 229 String dekAlgName = tknz.nextToken(); 230 byte[] iv = Hex.decode(tknz.nextToken()); 231 232 keyBytes = PEMUtilities.crypt(false, provider, keyBytes, password, dekAlgName, iv); 233 } 234 235 try 236 { 237 return (ASN1Sequence)ASN1Object.fromByteArray(keyBytes); 238 } 239 catch (IOException e) 240 { 241 if (isEncrypted) 242 { 243 throw new PEMException("exception decoding - please check password and data.", e); 244 } 245 else 246 { 247 throw new PEMException(e.getMessage(), e); 248 } 249 } 250 catch (ClassCastException e) 251 { 252 if (isEncrypted) 253 { 254 throw new PEMException("exception decoding - please check password and data.", e); 255 } 256 else 257 { 258 throw new PEMException(e.getMessage(), e); 259 } 260 } 261 } 262 } 263 264 private class DSAKeyPairParser 265 extends KeyPairParser 266 { 267 public DSAKeyPairParser(String provider) 268 { 269 super(provider); 270 } 271 272 public Object parseObject(PemObject obj) 273 throws IOException 274 { 275 try 276 { 277 ASN1Sequence seq = readKeyPair(obj); 278 279 if (seq.size() != 6) 280 { 281 throw new PEMException("malformed sequence in DSA private key"); 282 } 283 284 // DERInteger v = (DERInteger)seq.getObjectAt(0); 285 DERInteger p = (DERInteger)seq.getObjectAt(1); 286 DERInteger q = (DERInteger)seq.getObjectAt(2); 287 DERInteger g = (DERInteger)seq.getObjectAt(3); 288 DERInteger y = (DERInteger)seq.getObjectAt(4); 289 DERInteger x = (DERInteger)seq.getObjectAt(5); 290 291 DSAPrivateKeySpec privSpec = new DSAPrivateKeySpec( 292 x.getValue(), p.getValue(), 293 q.getValue(), g.getValue()); 294 DSAPublicKeySpec pubSpec = new DSAPublicKeySpec( 295 y.getValue(), p.getValue(), 296 q.getValue(), g.getValue()); 297 298 KeyFactory fact = KeyFactory.getInstance("DSA", provider); 299 300 return new KeyPair( 301 fact.generatePublic(pubSpec), 302 fact.generatePrivate(privSpec)); 303 } 304 catch (IOException e) 305 { 306 throw e; 307 } 308 catch (Exception e) 309 { 310 throw new PEMException( 311 "problem creating DSA private key: " + e.toString(), e); 312 } 313 } 314 } 315 316 private class ECDSAKeyPairParser 317 extends KeyPairParser 318 { 319 public ECDSAKeyPairParser(String provider) 320 { 321 super(provider); 322 } 323 324 public Object parseObject(PemObject obj) 325 throws IOException 326 { 327 try 328 { 329 ASN1Sequence seq = readKeyPair(obj); 330 331 ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(seq); 332 AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters()); 333 PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.getDERObject()); 334 SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes()); 335 336 PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privInfo.getEncoded()); 337 X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded()); 338 339 340 KeyFactory fact = KeyFactory.getInstance("ECDSA", provider); 341 342 343 return new KeyPair( 344 fact.generatePublic(pubSpec), 345 fact.generatePrivate(privSpec)); 346 } 347 catch (IOException e) 348 { 349 throw e; 350 } 351 catch (Exception e) 352 { 353 throw new PEMException( 354 "problem creating EC private key: " + e.toString(), e); 355 } 356 } 357 } 358 359 private class RSAKeyPairParser 360 extends KeyPairParser 361 { 362 public RSAKeyPairParser(String provider) 363 { 364 super(provider); 365 } 366 367 public Object parseObject(PemObject obj) 368 throws IOException 369 { 370 try 371 { 372 ASN1Sequence seq = readKeyPair(obj); 373 374 if (seq.size() != 9) 375 { 376 throw new PEMException("malformed sequence in RSA private key"); 377 } 378 379 // DERInteger v = (DERInteger)seq.getObjectAt(0); 380 DERInteger mod = (DERInteger)seq.getObjectAt(1); 381 DERInteger pubExp = (DERInteger)seq.getObjectAt(2); 382 DERInteger privExp = (DERInteger)seq.getObjectAt(3); 383 DERInteger p1 = (DERInteger)seq.getObjectAt(4); 384 DERInteger p2 = (DERInteger)seq.getObjectAt(5); 385 DERInteger exp1 = (DERInteger)seq.getObjectAt(6); 386 DERInteger exp2 = (DERInteger)seq.getObjectAt(7); 387 DERInteger crtCoef = (DERInteger)seq.getObjectAt(8); 388 389 RSAPublicKeySpec pubSpec = new RSAPublicKeySpec( 390 mod.getValue(), pubExp.getValue()); 391 RSAPrivateCrtKeySpec privSpec = new RSAPrivateCrtKeySpec( 392 mod.getValue(), pubExp.getValue(), privExp.getValue(), 393 p1.getValue(), p2.getValue(), 394 exp1.getValue(), exp2.getValue(), 395 crtCoef.getValue()); 396 397 398 KeyFactory fact = KeyFactory.getInstance("RSA", provider); 399 400 401 return new KeyPair( 402 fact.generatePublic(pubSpec), 403 fact.generatePrivate(privSpec)); 404 } 405 catch (IOException e) 406 { 407 throw e; 408 } 409 catch (Exception e) 410 { 411 throw new PEMException( 412 "problem creating RSA private key: " + e.toString(), e); 413 } 414 } 415 } 416 417 private class PublicKeyParser 418 implements PemObjectParser 419 { 420 private String provider; 421 422 public PublicKeyParser(String provider) 423 { 424 this.provider = provider; 425 } 426 427 public Object parseObject(PemObject obj) 428 throws IOException 429 { 430 KeySpec keySpec = new X509EncodedKeySpec(obj.getContent()); 431 String[] algorithms = {"DSA", "RSA"}; 432 for (int i = 0; i < algorithms.length; i++) 433 { 434 try 435 { 436 KeyFactory keyFact = KeyFactory.getInstance(algorithms[i], provider); 437 PublicKey pubKey = keyFact.generatePublic(keySpec); 438 439 return pubKey; 440 } 441 catch (NoSuchAlgorithmException e) 442 { 443 // ignore 444 } 445 catch (InvalidKeySpecException e) 446 { 447 // ignore 448 } 449 catch (NoSuchProviderException e) 450 { 451 throw new RuntimeException("can't find provider " + provider); 452 } 453 } 454 455 return null; 456 } 457 } 458 459 private class RSAPublicKeyParser 460 implements PemObjectParser 461 { 462 private String provider; 463 464 public RSAPublicKeyParser(String provider) 465 { 466 this.provider = provider; 467 } 468 469 public Object parseObject(PemObject obj) 470 throws IOException 471 { 472 try 473 { 474 ASN1InputStream ais = new ASN1InputStream(obj.getContent()); 475 Object asnObject = ais.readObject(); 476 ASN1Sequence sequence = (ASN1Sequence)asnObject; 477 RSAPublicKeyStructure rsaPubStructure = new RSAPublicKeyStructure(sequence); 478 RSAPublicKeySpec keySpec = new RSAPublicKeySpec( 479 rsaPubStructure.getModulus(), 480 rsaPubStructure.getPublicExponent()); 481 482 483 KeyFactory keyFact = KeyFactory.getInstance("RSA", provider); 484 485 return keyFact.generatePublic(keySpec); 486 } 487 catch (IOException e) 488 { 489 throw e; 490 } 491 catch (NoSuchProviderException e) 492 { 493 throw new IOException("can't find provider " + provider); 494 } 495 catch (Exception e) 496 { 497 throw new PEMException("problem extracting key: " + e.toString(), e); 498 } 499 } 500 } 501 502 private class X509CertificateParser 503 implements PemObjectParser 504 { 505 private String provider; 506 507 public X509CertificateParser(String provider) 508 { 509 this.provider = provider; 510 } 511 512 /** 513 * Reads in a X509Certificate. 514 * 515 * @return the X509Certificate 516 * @throws IOException if an I/O error occured 517 */ 518 public Object parseObject(PemObject obj) 519 throws IOException 520 { 521 ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent()); 522 523 try 524 { 525 CertificateFactory certFact 526 = CertificateFactory.getInstance("X.509", provider); 527 528 return certFact.generateCertificate(bIn); 529 } 530 catch (Exception e) 531 { 532 throw new PEMException("problem parsing cert: " + e.toString(), e); 533 } 534 } 535 } 536 537 private class X509CRLParser 538 implements PemObjectParser 539 { 540 private String provider; 541 542 public X509CRLParser(String provider) 543 { 544 this.provider = provider; 545 } 546 547 /** 548 * Reads in a X509CRL. 549 * 550 * @return the X509Certificate 551 * @throws IOException if an I/O error occured 552 */ 553 public Object parseObject(PemObject obj) 554 throws IOException 555 { 556 ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent()); 557 558 try 559 { 560 CertificateFactory certFact 561 = CertificateFactory.getInstance("X.509", provider); 562 563 return certFact.generateCRL(bIn); 564 } 565 catch (Exception e) 566 { 567 throw new PEMException("problem parsing cert: " + e.toString(), e); 568 } 569 } 570 } 571 572 private class PKCS10CertificationRequestParser 573 implements PemObjectParser 574 { 575 /** 576 * Reads in a PKCS10 certification request. 577 * 578 * @return the certificate request. 579 * @throws IOException if an I/O error occured 580 */ 581 public Object parseObject(PemObject obj) 582 throws IOException 583 { 584 try 585 { 586 return new PKCS10CertificationRequest(obj.getContent()); 587 } 588 catch (Exception e) 589 { 590 throw new PEMException("problem parsing certrequest: " + e.toString(), e); 591 } 592 } 593 } 594 595 private class PKCS7Parser 596 implements PemObjectParser 597 { 598 /** 599 * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS 600 * API. 601 * 602 * @return the X509Certificate 603 * @throws IOException if an I/O error occured 604 */ 605 public Object parseObject(PemObject obj) 606 throws IOException 607 { 608 try 609 { 610 ASN1InputStream aIn = new ASN1InputStream(obj.getContent()); 611 612 return ContentInfo.getInstance(aIn.readObject()); 613 } 614 catch (Exception e) 615 { 616 throw new PEMException("problem parsing PKCS7 object: " + e.toString(), e); 617 } 618 } 619 } 620 621 private class X509AttributeCertificateParser 622 implements PemObjectParser 623 { 624 public Object parseObject(PemObject obj) 625 throws IOException 626 { 627 return new X509V2AttributeCertificate(obj.getContent()); 628 } 629 } 630 631 private class ECNamedCurveSpecParser 632 implements PemObjectParser 633 { 634 public Object parseObject(PemObject obj) 635 throws IOException 636 { 637 try 638 { 639 DERObjectIdentifier oid = (DERObjectIdentifier)ASN1Object.fromByteArray(obj.getContent()); 640 641 Object params = ECNamedCurveTable.getParameterSpec(oid.getId()); 642 643 if (params == null) 644 { 645 throw new IOException("object ID not found in EC curve table"); 646 } 647 648 return params; 649 } 650 catch (IOException e) 651 { 652 throw e; 653 } 654 catch (Exception e) 655 { 656 throw new PEMException("exception extracting EC named curve: " + e.toString()); 657 } 658 } 659 } 660 661 private class EncryptedPrivateKeyParser 662 implements PemObjectParser 663 { 664 private String symProvider; 665 private String asymProvider; 666 667 public EncryptedPrivateKeyParser(String symProvider, String asymProvider) 668 { 669 this.symProvider = symProvider; 670 this.asymProvider = asymProvider; 671 } 672 673 /** 674 * Reads in a X509CRL. 675 * 676 * @return the X509Certificate 677 * @throws IOException if an I/O error occured 678 */ 679 public Object parseObject(PemObject obj) 680 throws IOException 681 { 682 try 683 { 684 EncryptedPrivateKeyInfo info = EncryptedPrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent())); 685 AlgorithmIdentifier algId = info.getEncryptionAlgorithm(); 686 687 if (pFinder == null) 688 { 689 throw new PEMException("no PasswordFinder specified"); 690 } 691 692 if (PEMUtilities.isPKCS5Scheme2(algId.getAlgorithm())) 693 { 694 PBES2Parameters params = PBES2Parameters.getInstance(algId.getParameters()); 695 KeyDerivationFunc func = params.getKeyDerivationFunc(); 696 EncryptionScheme scheme = params.getEncryptionScheme(); 697 PBKDF2Params defParams = (PBKDF2Params)func.getParameters(); 698 699 int iterationCount = defParams.getIterationCount().intValue(); 700 byte[] salt = defParams.getSalt(); 701 702 String algorithm = scheme.getAlgorithm().getId(); 703 704 SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algorithm, pFinder.getPassword(), salt, iterationCount); 705 706 Cipher cipher = Cipher.getInstance(algorithm, symProvider); 707 AlgorithmParameters algParams = AlgorithmParameters.getInstance(algorithm, symProvider); 708 709 algParams.init(scheme.getParameters().getDERObject().getEncoded()); 710 711 cipher.init(Cipher.DECRYPT_MODE, key, algParams); 712 713 PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData()))); 714 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded()); 715 716 KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider); 717 718 return keyFact.generatePrivate(keySpec); 719 } 720 else if (PEMUtilities.isPKCS12(algId.getAlgorithm())) 721 { 722 PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters()); 723 String algorithm = algId.getAlgorithm().getId(); 724 PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword()); 725 726 SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider); 727 PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue()); 728 729 Cipher cipher = Cipher.getInstance(algorithm, symProvider); 730 731 cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); 732 733 PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData()))); 734 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded()); 735 736 KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider); 737 738 return keyFact.generatePrivate(keySpec); 739 } 740 else if (PEMUtilities.isPKCS5Scheme1(algId.getAlgorithm())) 741 { 742 PBEParameter params = PBEParameter.getInstance(algId.getParameters()); 743 String algorithm = algId.getAlgorithm().getId(); 744 PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword()); 745 746 SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider); 747 PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue()); 748 749 Cipher cipher = Cipher.getInstance(algorithm, symProvider); 750 751 cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); 752 753 PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData()))); 754 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded()); 755 756 KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider); 757 758 return keyFact.generatePrivate(keySpec); 759 } 760 else 761 { 762 throw new PEMException("Unknown algorithm: " + algId.getAlgorithm()); 763 } 764 } 765 catch (IOException e) 766 { 767 throw e; 768 } 769 catch (Exception e) 770 { 771 throw new PEMException("problem parsing ENCRYPTED PRIVATE KEY: " + e.toString(), e); 772 } 773 } 774 } 775 776 private class PrivateKeyParser 777 implements PemObjectParser 778 { 779 private String provider; 780 781 public PrivateKeyParser(String provider) 782 { 783 this.provider = provider; 784 } 785 786 public Object parseObject(PemObject obj) 787 throws IOException 788 { 789 try 790 { 791 PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent())); 792 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(obj.getContent()); 793 794 KeyFactory keyFact = KeyFactory.getInstance(info.getAlgorithmId().getAlgorithm().getId(), provider); 795 796 return keyFact.generatePrivate(keySpec); 797 } 798 catch (Exception e) 799 { 800 throw new PEMException("problem parsing PRIVATE KEY: " + e.toString(), e); 801 } 802 } 803 } 804 } 805