package org.bouncycastle.openssl.jcajce; import java.io.IOException; import java.io.InputStream; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.InvalidKeyException; import java.security.Provider; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; import org.bouncycastle.asn1.pkcs.EncryptionScheme; 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.x509.AlgorithmIdentifier; import org.bouncycastle.jcajce.DefaultJcaJceHelper; import org.bouncycastle.jcajce.JcaJceHelper; import org.bouncycastle.jcajce.NamedJcaJceHelper; import org.bouncycastle.jcajce.ProviderJcaJceHelper; import org.bouncycastle.openssl.PEMException; import org.bouncycastle.operator.InputDecryptor; import org.bouncycastle.operator.InputDecryptorProvider; import org.bouncycastle.operator.OperatorCreationException; public class JceOpenSSLPKCS8DecryptorProviderBuilder { private JcaJceHelper helper = new DefaultJcaJceHelper(); public JceOpenSSLPKCS8DecryptorProviderBuilder() { helper = new DefaultJcaJceHelper(); } public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(String providerName) { helper = new NamedJcaJceHelper(providerName); return this; } public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(Provider provider) { helper = new ProviderJcaJceHelper(provider); return this; } public InputDecryptorProvider build(final char[] password) throws OperatorCreationException { return new InputDecryptorProvider() { public InputDecryptor get(final AlgorithmIdentifier algorithm) throws OperatorCreationException { final Cipher cipher; try { if (PEMUtilities.isPKCS5Scheme2(algorithm.getAlgorithm())) { PBES2Parameters params = PBES2Parameters.getInstance(algorithm.getParameters()); KeyDerivationFunc func = params.getKeyDerivationFunc(); EncryptionScheme scheme = params.getEncryptionScheme(); PBKDF2Params defParams = (PBKDF2Params)func.getParameters(); int iterationCount = defParams.getIterationCount().intValue(); byte[] salt = defParams.getSalt(); String oid = scheme.getAlgorithm().getId(); SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(oid, password, salt, iterationCount); cipher = helper.createCipher(oid); AlgorithmParameters algParams = helper.createAlgorithmParameters(oid); algParams.init(scheme.getParameters().toASN1Primitive().getEncoded()); cipher.init(Cipher.DECRYPT_MODE, key, algParams); } else if (PEMUtilities.isPKCS12(algorithm.getAlgorithm())) { PKCS12PBEParams params = PKCS12PBEParams.getInstance(algorithm.getParameters()); PBEKeySpec pbeSpec = new PBEKeySpec(password); SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId()); PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue()); cipher = helper.createCipher(algorithm.getAlgorithm().getId()); cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); } else if (PEMUtilities.isPKCS5Scheme1(algorithm.getAlgorithm())) { PBEParameter params = PBEParameter.getInstance(algorithm.getParameters()); PBEKeySpec pbeSpec = new PBEKeySpec(password); SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId()); PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue()); cipher = helper.createCipher(algorithm.getAlgorithm().getId()); cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); } else { throw new PEMException("Unknown algorithm: " + algorithm.getAlgorithm()); } return new InputDecryptor() { public AlgorithmIdentifier getAlgorithmIdentifier() { return algorithm; } public InputStream getInputStream(InputStream encIn) { return new CipherInputStream(encIn, cipher); } }; } catch (IOException e) { throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); } catch (InvalidKeyException e) { throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); } catch (NoSuchProviderException e) { throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); } catch (NoSuchAlgorithmException e) { throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); } catch (GeneralSecurityException e) { throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); } }; }; } }