package org.bouncycastle.pkcs.jcajce;

import java.io.InputStream;
import java.security.Provider;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.ScryptParams;
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.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.PasswordConverter;
import org.bouncycastle.jcajce.PBKDF1Key;
import org.bouncycastle.jcajce.PKCS12KeyWithParameters;
import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
import org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
import org.bouncycastle.jcajce.spec.ScryptKeySpec;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
import org.bouncycastle.operator.DefaultSecretKeySizeProvider;
import org.bouncycastle.operator.InputDecryptor;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.SecretKeySizeProvider;

public class JcePKCSPBEInputDecryptorProviderBuilder
{
    private JcaJceHelper helper = new DefaultJcaJceHelper();
    private boolean      wrongPKCS12Zero = false;
    private SecretKeySizeProvider keySizeProvider = DefaultSecretKeySizeProvider.INSTANCE;

    public JcePKCSPBEInputDecryptorProviderBuilder()
    {
    }

    public JcePKCSPBEInputDecryptorProviderBuilder setProvider(Provider provider)
    {
        this.helper = new ProviderJcaJceHelper(provider);

        return this;
    }

    public JcePKCSPBEInputDecryptorProviderBuilder setProvider(String providerName)
    {
        this.helper = new NamedJcaJceHelper(providerName);

        return this;
    }

    public JcePKCSPBEInputDecryptorProviderBuilder setTryWrongPKCS12Zero(boolean tryWrong)
    {
        this.wrongPKCS12Zero = tryWrong;

        return this;
    }

    
Set the lookup provider of AlgorithmIdentifier returning key_size_in_bits used to handle PKCS5 decryption.
Params:
  • keySizeProvider – a provider of integer secret key sizes.
Returns:the current builder.
/** * Set the lookup provider of AlgorithmIdentifier returning key_size_in_bits used to * handle PKCS5 decryption. * * @param keySizeProvider a provider of integer secret key sizes. * * @return the current builder. */
public JcePKCSPBEInputDecryptorProviderBuilder setKeySizeProvider(SecretKeySizeProvider keySizeProvider) { this.keySizeProvider = keySizeProvider; return this; } public InputDecryptorProvider build(final char[] password) { return new InputDecryptorProvider() { private Cipher cipher; private AlgorithmIdentifier encryptionAlg; public InputDecryptor get(final AlgorithmIdentifier algorithmIdentifier) throws OperatorCreationException { SecretKey key; ASN1ObjectIdentifier algorithm = algorithmIdentifier.getAlgorithm(); try { if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)) { PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); cipher = helper.createCipher(algorithm.getId()); cipher.init(Cipher.DECRYPT_MODE, new PKCS12KeyWithParameters(password, wrongPKCS12Zero, pbeParams.getIV(), pbeParams.getIterations().intValue())); encryptionAlg = algorithmIdentifier; } else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) { PBES2Parameters alg = PBES2Parameters.getInstance(algorithmIdentifier.getParameters()); if (MiscObjectIdentifiers.id_scrypt.equals(alg.getKeyDerivationFunc().getAlgorithm())) { ScryptParams params = ScryptParams.getInstance(alg.getKeyDerivationFunc().getParameters()); AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); SecretKeyFactory keyFact = helper.createSecretKeyFactory("SCRYPT"); key = keyFact.generateSecret(new ScryptKeySpec(password, params.getSalt(), params.getCostParameter().intValue(), params.getBlockSize().intValue(), params.getParallelizationParameter().intValue(), keySizeProvider.getKeySize(encScheme))); } else { SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId()); PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters()); AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); if (func.isDefaultPrf()) { key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme))); } else { key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme), func.getPrf())); } } cipher = helper.createCipher(alg.getEncryptionScheme().getAlgorithm().getId()); encryptionAlg = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); ASN1Encodable encParams = alg.getEncryptionScheme().getParameters(); if (encParams instanceof ASN1OctetString) { cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets())); } else { // TODO: at the moment it's just GOST, but... GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams); cipher.init(Cipher.DECRYPT_MODE, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV())); } } else if (algorithm.equals(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC) || algorithm.equals(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC)) { PBEParameter pbeParams = PBEParameter.getInstance(algorithmIdentifier.getParameters()); cipher = helper.createCipher(algorithm.getId()); cipher.init(Cipher.DECRYPT_MODE, new PBKDF1Key(password, PasswordConverter.ASCII), new PBEParameterSpec(pbeParams.getSalt(), pbeParams.getIterationCount().intValue())); } else { throw new OperatorCreationException("unable to create InputDecryptor: algorithm " + algorithm + " unknown."); } } catch (Exception e) { throw new OperatorCreationException("unable to create InputDecryptor: " + e.getMessage(), e); } return new InputDecryptor() { public AlgorithmIdentifier getAlgorithmIdentifier() { return encryptionAlg; } public InputStream getInputStream(InputStream input) { return new CipherInputStream(input, cipher); } }; } }; } }