| package org.bouncycastle.openssl; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.security.AlgorithmParameters; |
| import java.security.KeyFactory; |
| import java.security.KeyPair; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.security.PublicKey; |
| import java.security.cert.CertificateFactory; |
| import java.security.spec.DSAPrivateKeySpec; |
| import java.security.spec.DSAPublicKeySpec; |
| import java.security.spec.InvalidKeySpecException; |
| import java.security.spec.KeySpec; |
| import java.security.spec.PKCS8EncodedKeySpec; |
| import java.security.spec.RSAPrivateCrtKeySpec; |
| import java.security.spec.RSAPublicKeySpec; |
| import java.security.spec.X509EncodedKeySpec; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| |
| import javax.crypto.Cipher; |
| import javax.crypto.SecretKey; |
| import javax.crypto.SecretKeyFactory; |
| import javax.crypto.spec.PBEKeySpec; |
| import javax.crypto.spec.PBEParameterSpec; |
| |
| import org.bouncycastle.asn1.ASN1InputStream; |
| import org.bouncycastle.asn1.ASN1Object; |
| import org.bouncycastle.asn1.ASN1Sequence; |
| import org.bouncycastle.asn1.DERInteger; |
| import org.bouncycastle.asn1.DERObjectIdentifier; |
| import org.bouncycastle.asn1.cms.ContentInfo; |
| import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; |
| import org.bouncycastle.asn1.pkcs.EncryptionScheme; |
| import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; |
| import org.bouncycastle.asn1.pkcs.PBEParameter; |
| import org.bouncycastle.asn1.pkcs.PBES2Parameters; |
| import org.bouncycastle.asn1.pkcs.PBKDF2Params; |
| import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; |
| import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; |
| import org.bouncycastle.asn1.sec.ECPrivateKeyStructure; |
| import org.bouncycastle.asn1.x509.AlgorithmIdentifier; |
| import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; |
| import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; |
| import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; |
| import org.bouncycastle.jce.ECNamedCurveTable; |
| import org.bouncycastle.jce.PKCS10CertificationRequest; |
| import org.bouncycastle.util.encoders.Hex; |
| import org.bouncycastle.util.io.pem.PemHeader; |
| import org.bouncycastle.util.io.pem.PemObject; |
| import org.bouncycastle.util.io.pem.PemObjectParser; |
| import org.bouncycastle.util.io.pem.PemReader; |
| import org.bouncycastle.x509.X509V2AttributeCertificate; |
| |
| /** |
| * Class for reading OpenSSL PEM encoded streams containing |
| * X509 certificates, PKCS8 encoded keys and PKCS7 objects. |
| * <p> |
| * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and |
| * Certificates will be returned using the appropriate java.security type (KeyPair, PublicKey, X509Certificate, |
| * or X509CRL). In the case of a Certificate Request a PKCS10CertificationRequest will be returned. |
| * </p> |
| */ |
| public class PEMReader |
| extends PemReader |
| { |
| private final Map parsers = new HashMap(); |
| |
| private PasswordFinder pFinder; |
| |
| |
| /** |
| * Create a new PEMReader |
| * |
| * @param reader the Reader |
| */ |
| public PEMReader( |
| Reader reader) |
| { |
| this(reader, null, "BC"); |
| } |
| |
| /** |
| * Create a new PEMReader with a password finder |
| * |
| * @param reader the Reader |
| * @param pFinder the password finder |
| */ |
| public PEMReader( |
| Reader reader, |
| PasswordFinder pFinder) |
| { |
| this(reader, pFinder, "BC"); |
| } |
| |
| /** |
| * Create a new PEMReader with a password finder |
| * |
| * @param reader the Reader |
| * @param pFinder the password finder |
| * @param provider the cryptography provider to use |
| */ |
| public PEMReader( |
| Reader reader, |
| PasswordFinder pFinder, |
| String provider) |
| { |
| this(reader, pFinder, provider, provider); |
| } |
| |
| /** |
| * Create a new PEMReader with a password finder and differing providers for secret and public key |
| * operations. |
| * |
| * @param reader the Reader |
| * @param pFinder the password finder |
| * @param symProvider provider to use for symmetric operations |
| * @param asymProvider provider to use for asymmetric (public/private key) operations |
| */ |
| public PEMReader( |
| Reader reader, |
| PasswordFinder pFinder, |
| String symProvider, |
| String asymProvider) |
| { |
| super(reader); |
| |
| this.pFinder = pFinder; |
| |
| parsers.put("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser()); |
| parsers.put("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser()); |
| parsers.put("CERTIFICATE", new X509CertificateParser(asymProvider)); |
| parsers.put("X509 CERTIFICATE", new X509CertificateParser(asymProvider)); |
| parsers.put("X509 CRL", new X509CRLParser(asymProvider)); |
| parsers.put("PKCS7", new PKCS7Parser()); |
| parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser()); |
| parsers.put("EC PARAMETERS", new ECNamedCurveSpecParser()); |
| parsers.put("PUBLIC KEY", new PublicKeyParser(asymProvider)); |
| parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser(asymProvider)); |
| parsers.put("RSA PRIVATE KEY", new RSAKeyPairParser(asymProvider)); |
| parsers.put("DSA PRIVATE KEY", new DSAKeyPairParser(asymProvider)); |
| parsers.put("EC PRIVATE KEY", new ECDSAKeyPairParser(asymProvider)); |
| parsers.put("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser(symProvider, asymProvider)); |
| parsers.put("PRIVATE KEY", new PrivateKeyParser(asymProvider)); |
| } |
| |
| public Object readObject() |
| throws IOException |
| { |
| PemObject obj = readPemObject(); |
| |
| if (obj != null) |
| { |
| String type = obj.getType(); |
| if (parsers.containsKey(type)) |
| { |
| return ((PemObjectParser)parsers.get(type)).parseObject(obj); |
| } |
| else |
| { |
| throw new IOException("unrecognised object: " + type); |
| } |
| } |
| |
| return null; |
| } |
| |
| private abstract class KeyPairParser |
| implements PemObjectParser |
| { |
| protected String provider; |
| |
| public KeyPairParser(String provider) |
| { |
| this.provider = provider; |
| } |
| |
| /** |
| * Read a Key Pair |
| */ |
| protected ASN1Sequence readKeyPair( |
| PemObject obj) |
| throws IOException |
| { |
| boolean isEncrypted = false; |
| String dekInfo = null; |
| List headers = obj.getHeaders(); |
| |
| for (Iterator it = headers.iterator(); it.hasNext();) |
| { |
| PemHeader hdr = (PemHeader)it.next(); |
| |
| if (hdr.getName().equals("Proc-Type") && hdr.getValue().equals("4,ENCRYPTED")) |
| { |
| isEncrypted = true; |
| } |
| else if (hdr.getName().equals("DEK-Info")) |
| { |
| dekInfo = hdr.getValue(); |
| } |
| } |
| |
| // |
| // extract the key |
| // |
| byte[] keyBytes = obj.getContent(); |
| |
| if (isEncrypted) |
| { |
| if (pFinder == null) |
| { |
| throw new PasswordException("No password finder specified, but a password is required"); |
| } |
| |
| char[] password = pFinder.getPassword(); |
| |
| if (password == null) |
| { |
| throw new PasswordException("Password is null, but a password is required"); |
| } |
| |
| StringTokenizer tknz = new StringTokenizer(dekInfo, ","); |
| String dekAlgName = tknz.nextToken(); |
| byte[] iv = Hex.decode(tknz.nextToken()); |
| |
| keyBytes = PEMUtilities.crypt(false, provider, keyBytes, password, dekAlgName, iv); |
| } |
| |
| try |
| { |
| return (ASN1Sequence)ASN1Object.fromByteArray(keyBytes); |
| } |
| catch (IOException e) |
| { |
| if (isEncrypted) |
| { |
| throw new PEMException("exception decoding - please check password and data.", e); |
| } |
| else |
| { |
| throw new PEMException(e.getMessage(), e); |
| } |
| } |
| catch (ClassCastException e) |
| { |
| if (isEncrypted) |
| { |
| throw new PEMException("exception decoding - please check password and data.", e); |
| } |
| else |
| { |
| throw new PEMException(e.getMessage(), e); |
| } |
| } |
| } |
| } |
| |
| private class DSAKeyPairParser |
| extends KeyPairParser |
| { |
| public DSAKeyPairParser(String provider) |
| { |
| super(provider); |
| } |
| |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| ASN1Sequence seq = readKeyPair(obj); |
| |
| if (seq.size() != 6) |
| { |
| throw new PEMException("malformed sequence in DSA private key"); |
| } |
| |
| // DERInteger v = (DERInteger)seq.getObjectAt(0); |
| DERInteger p = (DERInteger)seq.getObjectAt(1); |
| DERInteger q = (DERInteger)seq.getObjectAt(2); |
| DERInteger g = (DERInteger)seq.getObjectAt(3); |
| DERInteger y = (DERInteger)seq.getObjectAt(4); |
| DERInteger x = (DERInteger)seq.getObjectAt(5); |
| |
| DSAPrivateKeySpec privSpec = new DSAPrivateKeySpec( |
| x.getValue(), p.getValue(), |
| q.getValue(), g.getValue()); |
| DSAPublicKeySpec pubSpec = new DSAPublicKeySpec( |
| y.getValue(), p.getValue(), |
| q.getValue(), g.getValue()); |
| |
| KeyFactory fact = KeyFactory.getInstance("DSA", provider); |
| |
| return new KeyPair( |
| fact.generatePublic(pubSpec), |
| fact.generatePrivate(privSpec)); |
| } |
| catch (IOException e) |
| { |
| throw e; |
| } |
| catch (Exception e) |
| { |
| throw new PEMException( |
| "problem creating DSA private key: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class ECDSAKeyPairParser |
| extends KeyPairParser |
| { |
| public ECDSAKeyPairParser(String provider) |
| { |
| super(provider); |
| } |
| |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| ASN1Sequence seq = readKeyPair(obj); |
| |
| ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(seq); |
| AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters()); |
| PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.getDERObject()); |
| SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes()); |
| |
| PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privInfo.getEncoded()); |
| X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded()); |
| |
| |
| KeyFactory fact = KeyFactory.getInstance("ECDSA", provider); |
| |
| |
| return new KeyPair( |
| fact.generatePublic(pubSpec), |
| fact.generatePrivate(privSpec)); |
| } |
| catch (IOException e) |
| { |
| throw e; |
| } |
| catch (Exception e) |
| { |
| throw new PEMException( |
| "problem creating EC private key: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class RSAKeyPairParser |
| extends KeyPairParser |
| { |
| public RSAKeyPairParser(String provider) |
| { |
| super(provider); |
| } |
| |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| ASN1Sequence seq = readKeyPair(obj); |
| |
| if (seq.size() != 9) |
| { |
| throw new PEMException("malformed sequence in RSA private key"); |
| } |
| |
| // DERInteger v = (DERInteger)seq.getObjectAt(0); |
| DERInteger mod = (DERInteger)seq.getObjectAt(1); |
| DERInteger pubExp = (DERInteger)seq.getObjectAt(2); |
| DERInteger privExp = (DERInteger)seq.getObjectAt(3); |
| DERInteger p1 = (DERInteger)seq.getObjectAt(4); |
| DERInteger p2 = (DERInteger)seq.getObjectAt(5); |
| DERInteger exp1 = (DERInteger)seq.getObjectAt(6); |
| DERInteger exp2 = (DERInteger)seq.getObjectAt(7); |
| DERInteger crtCoef = (DERInteger)seq.getObjectAt(8); |
| |
| RSAPublicKeySpec pubSpec = new RSAPublicKeySpec( |
| mod.getValue(), pubExp.getValue()); |
| RSAPrivateCrtKeySpec privSpec = new RSAPrivateCrtKeySpec( |
| mod.getValue(), pubExp.getValue(), privExp.getValue(), |
| p1.getValue(), p2.getValue(), |
| exp1.getValue(), exp2.getValue(), |
| crtCoef.getValue()); |
| |
| |
| KeyFactory fact = KeyFactory.getInstance("RSA", provider); |
| |
| |
| return new KeyPair( |
| fact.generatePublic(pubSpec), |
| fact.generatePrivate(privSpec)); |
| } |
| catch (IOException e) |
| { |
| throw e; |
| } |
| catch (Exception e) |
| { |
| throw new PEMException( |
| "problem creating RSA private key: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class PublicKeyParser |
| implements PemObjectParser |
| { |
| private String provider; |
| |
| public PublicKeyParser(String provider) |
| { |
| this.provider = provider; |
| } |
| |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| KeySpec keySpec = new X509EncodedKeySpec(obj.getContent()); |
| String[] algorithms = {"DSA", "RSA"}; |
| for (int i = 0; i < algorithms.length; i++) |
| { |
| try |
| { |
| KeyFactory keyFact = KeyFactory.getInstance(algorithms[i], provider); |
| PublicKey pubKey = keyFact.generatePublic(keySpec); |
| |
| return pubKey; |
| } |
| catch (NoSuchAlgorithmException e) |
| { |
| // ignore |
| } |
| catch (InvalidKeySpecException e) |
| { |
| // ignore |
| } |
| catch (NoSuchProviderException e) |
| { |
| throw new RuntimeException("can't find provider " + provider); |
| } |
| } |
| |
| return null; |
| } |
| } |
| |
| private class RSAPublicKeyParser |
| implements PemObjectParser |
| { |
| private String provider; |
| |
| public RSAPublicKeyParser(String provider) |
| { |
| this.provider = provider; |
| } |
| |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| ASN1InputStream ais = new ASN1InputStream(obj.getContent()); |
| Object asnObject = ais.readObject(); |
| ASN1Sequence sequence = (ASN1Sequence)asnObject; |
| RSAPublicKeyStructure rsaPubStructure = new RSAPublicKeyStructure(sequence); |
| RSAPublicKeySpec keySpec = new RSAPublicKeySpec( |
| rsaPubStructure.getModulus(), |
| rsaPubStructure.getPublicExponent()); |
| |
| |
| KeyFactory keyFact = KeyFactory.getInstance("RSA", provider); |
| |
| return keyFact.generatePublic(keySpec); |
| } |
| catch (IOException e) |
| { |
| throw e; |
| } |
| catch (NoSuchProviderException e) |
| { |
| throw new IOException("can't find provider " + provider); |
| } |
| catch (Exception e) |
| { |
| throw new PEMException("problem extracting key: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class X509CertificateParser |
| implements PemObjectParser |
| { |
| private String provider; |
| |
| public X509CertificateParser(String provider) |
| { |
| this.provider = provider; |
| } |
| |
| /** |
| * Reads in a X509Certificate. |
| * |
| * @return the X509Certificate |
| * @throws IOException if an I/O error occured |
| */ |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent()); |
| |
| try |
| { |
| CertificateFactory certFact |
| = CertificateFactory.getInstance("X.509", provider); |
| |
| return certFact.generateCertificate(bIn); |
| } |
| catch (Exception e) |
| { |
| throw new PEMException("problem parsing cert: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class X509CRLParser |
| implements PemObjectParser |
| { |
| private String provider; |
| |
| public X509CRLParser(String provider) |
| { |
| this.provider = provider; |
| } |
| |
| /** |
| * Reads in a X509CRL. |
| * |
| * @return the X509Certificate |
| * @throws IOException if an I/O error occured |
| */ |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| ByteArrayInputStream bIn = new ByteArrayInputStream(obj.getContent()); |
| |
| try |
| { |
| CertificateFactory certFact |
| = CertificateFactory.getInstance("X.509", provider); |
| |
| return certFact.generateCRL(bIn); |
| } |
| catch (Exception e) |
| { |
| throw new PEMException("problem parsing cert: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class PKCS10CertificationRequestParser |
| implements PemObjectParser |
| { |
| /** |
| * Reads in a PKCS10 certification request. |
| * |
| * @return the certificate request. |
| * @throws IOException if an I/O error occured |
| */ |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| return new PKCS10CertificationRequest(obj.getContent()); |
| } |
| catch (Exception e) |
| { |
| throw new PEMException("problem parsing certrequest: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class PKCS7Parser |
| implements PemObjectParser |
| { |
| /** |
| * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS |
| * API. |
| * |
| * @return the X509Certificate |
| * @throws IOException if an I/O error occured |
| */ |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| ASN1InputStream aIn = new ASN1InputStream(obj.getContent()); |
| |
| return ContentInfo.getInstance(aIn.readObject()); |
| } |
| catch (Exception e) |
| { |
| throw new PEMException("problem parsing PKCS7 object: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class X509AttributeCertificateParser |
| implements PemObjectParser |
| { |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| return new X509V2AttributeCertificate(obj.getContent()); |
| } |
| } |
| |
| private class ECNamedCurveSpecParser |
| implements PemObjectParser |
| { |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| DERObjectIdentifier oid = (DERObjectIdentifier)ASN1Object.fromByteArray(obj.getContent()); |
| |
| Object params = ECNamedCurveTable.getParameterSpec(oid.getId()); |
| |
| if (params == null) |
| { |
| throw new IOException("object ID not found in EC curve table"); |
| } |
| |
| return params; |
| } |
| catch (IOException e) |
| { |
| throw e; |
| } |
| catch (Exception e) |
| { |
| throw new PEMException("exception extracting EC named curve: " + e.toString()); |
| } |
| } |
| } |
| |
| private class EncryptedPrivateKeyParser |
| implements PemObjectParser |
| { |
| private String symProvider; |
| private String asymProvider; |
| |
| public EncryptedPrivateKeyParser(String symProvider, String asymProvider) |
| { |
| this.symProvider = symProvider; |
| this.asymProvider = asymProvider; |
| } |
| |
| /** |
| * Reads in a X509CRL. |
| * |
| * @return the X509Certificate |
| * @throws IOException if an I/O error occured |
| */ |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| EncryptedPrivateKeyInfo info = EncryptedPrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent())); |
| AlgorithmIdentifier algId = info.getEncryptionAlgorithm(); |
| |
| if (pFinder == null) |
| { |
| throw new PEMException("no PasswordFinder specified"); |
| } |
| |
| if (PEMUtilities.isPKCS5Scheme2(algId.getAlgorithm())) |
| { |
| PBES2Parameters params = PBES2Parameters.getInstance(algId.getParameters()); |
| KeyDerivationFunc func = params.getKeyDerivationFunc(); |
| EncryptionScheme scheme = params.getEncryptionScheme(); |
| PBKDF2Params defParams = (PBKDF2Params)func.getParameters(); |
| |
| int iterationCount = defParams.getIterationCount().intValue(); |
| byte[] salt = defParams.getSalt(); |
| |
| String algorithm = scheme.getAlgorithm().getId(); |
| |
| SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algorithm, pFinder.getPassword(), salt, iterationCount); |
| |
| Cipher cipher = Cipher.getInstance(algorithm, symProvider); |
| AlgorithmParameters algParams = AlgorithmParameters.getInstance(algorithm, symProvider); |
| |
| algParams.init(scheme.getParameters().getDERObject().getEncoded()); |
| |
| cipher.init(Cipher.DECRYPT_MODE, key, algParams); |
| |
| PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData()))); |
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded()); |
| |
| KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider); |
| |
| return keyFact.generatePrivate(keySpec); |
| } |
| else if (PEMUtilities.isPKCS12(algId.getAlgorithm())) |
| { |
| PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters()); |
| String algorithm = algId.getAlgorithm().getId(); |
| PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword()); |
| |
| SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider); |
| PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue()); |
| |
| Cipher cipher = Cipher.getInstance(algorithm, symProvider); |
| |
| cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); |
| |
| PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData()))); |
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded()); |
| |
| KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider); |
| |
| return keyFact.generatePrivate(keySpec); |
| } |
| else if (PEMUtilities.isPKCS5Scheme1(algId.getAlgorithm())) |
| { |
| PBEParameter params = PBEParameter.getInstance(algId.getParameters()); |
| String algorithm = algId.getAlgorithm().getId(); |
| PBEKeySpec pbeSpec = new PBEKeySpec(pFinder.getPassword()); |
| |
| SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm, symProvider); |
| PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue()); |
| |
| Cipher cipher = Cipher.getInstance(algorithm, symProvider); |
| |
| cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); |
| |
| PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(cipher.doFinal(info.getEncryptedData()))); |
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded()); |
| |
| KeyFactory keyFact = KeyFactory.getInstance(pInfo.getAlgorithmId().getAlgorithm().getId(), asymProvider); |
| |
| return keyFact.generatePrivate(keySpec); |
| } |
| else |
| { |
| throw new PEMException("Unknown algorithm: " + algId.getAlgorithm()); |
| } |
| } |
| catch (IOException e) |
| { |
| throw e; |
| } |
| catch (Exception e) |
| { |
| throw new PEMException("problem parsing ENCRYPTED PRIVATE KEY: " + e.toString(), e); |
| } |
| } |
| } |
| |
| private class PrivateKeyParser |
| implements PemObjectParser |
| { |
| private String provider; |
| |
| public PrivateKeyParser(String provider) |
| { |
| this.provider = provider; |
| } |
| |
| public Object parseObject(PemObject obj) |
| throws IOException |
| { |
| try |
| { |
| PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(obj.getContent())); |
| PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(obj.getContent()); |
| |
| KeyFactory keyFact = KeyFactory.getInstance(info.getAlgorithmId().getAlgorithm().getId(), provider); |
| |
| return keyFact.generatePrivate(keySpec); |
| } |
| catch (Exception e) |
| { |
| throw new PEMException("problem parsing PRIVATE KEY: " + e.toString(), e); |
| } |
| } |
| } |
| } |