All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.bouncycastle.pkcs.jcajce.JcePKCSPBEOutputEncryptorBuilder Maven / Gradle / Ivy
package org.bouncycastle.pkcs.jcajce;
import java.io.OutputStream;
import java.security.AlgorithmParameters;
import java.security.Provider;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.ScryptParams;
import org.bouncycastle.asn1.pkcs.EncryptionScheme;
import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
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.util.PBKDF2Config;
import org.bouncycastle.crypto.util.PBKDFConfig;
import org.bouncycastle.crypto.util.ScryptConfig;
import org.bouncycastle.jcajce.PKCS12KeyWithParameters;
import org.bouncycastle.jcajce.io.CipherOutputStream;
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.AlgorithmNameFinder;
import org.bouncycastle.operator.DefaultAlgorithmNameFinder;
import org.bouncycastle.operator.DefaultSecretKeySizeProvider;
import org.bouncycastle.operator.GenericKey;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.operator.SecretKeySizeProvider;
public class JcePKCSPBEOutputEncryptorBuilder
{
private final PBKDFConfig pbkdf;
private JcaJceHelper helper = new DefaultJcaJceHelper();
private ASN1ObjectIdentifier algorithm;
private ASN1ObjectIdentifier keyEncAlgorithm;
private SecureRandom random;
private SecretKeySizeProvider keySizeProvider = DefaultSecretKeySizeProvider.INSTANCE;
private AlgorithmNameFinder algorithmNameFinder = new DefaultAlgorithmNameFinder();
private int iterationCount = 1024;
private PBKDF2Config.Builder pbkdfBuilder = new PBKDF2Config.Builder();
public JcePKCSPBEOutputEncryptorBuilder(ASN1ObjectIdentifier keyEncryptionAlg)
{
this.pbkdf = null;
if (isPKCS12(keyEncryptionAlg))
{
this.algorithm = keyEncryptionAlg;
this.keyEncAlgorithm = keyEncryptionAlg;
}
else
{
this.algorithm = PKCSObjectIdentifiers.id_PBES2;
this.keyEncAlgorithm = keyEncryptionAlg;
}
}
/**
* Constructor allowing different derivation functions such as PBKDF2 and scrypt.
*
* @param pbkdfAlgorithm key derivation algorithm definition to use.
* @param keyEncryptionAlg encryption algorithm to apply the derived key with.
*/
public JcePKCSPBEOutputEncryptorBuilder(PBKDFConfig pbkdfAlgorithm, ASN1ObjectIdentifier keyEncryptionAlg)
{
this.algorithm = PKCSObjectIdentifiers.id_PBES2;
this.pbkdf = pbkdfAlgorithm;
this.keyEncAlgorithm = keyEncryptionAlg;
}
public JcePKCSPBEOutputEncryptorBuilder setProvider(Provider provider)
{
this.helper = new ProviderJcaJceHelper(provider);
return this;
}
public JcePKCSPBEOutputEncryptorBuilder setProvider(String providerName)
{
this.helper = new NamedJcaJceHelper(providerName);
return this;
}
public JcePKCSPBEOutputEncryptorBuilder setRandom(SecureRandom random)
{
this.random = random;
return this;
}
/**
* 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 JcePKCSPBEOutputEncryptorBuilder setKeySizeProvider(SecretKeySizeProvider keySizeProvider)
{
this.keySizeProvider = keySizeProvider;
return this;
}
/**
* Set the PRF to use for key generation. By default this is HmacSHA1.
*
* @param prf algorithm id for PRF.
* @return the current builder.
* @throws IllegalStateException if this builder was intialised with a PBKDFDef
*/
public JcePKCSPBEOutputEncryptorBuilder setPRF(AlgorithmIdentifier prf)
{
if (pbkdf != null)
{
throw new IllegalStateException("set PRF count using PBKDFDef");
}
this.pbkdfBuilder.withPRF(prf);
return this;
}
/**
* Set the iteration count for the PBE calculation.
*
* @param iterationCount the iteration count to apply to the key creation.
* @return the current builder.
* @throws IllegalStateException if this builder was intialised with a PBKDFDef
*/
public JcePKCSPBEOutputEncryptorBuilder setIterationCount(int iterationCount)
{
if (pbkdf != null)
{
throw new IllegalStateException("set iteration count using PBKDFDef");
}
this.iterationCount = iterationCount;
this.pbkdfBuilder.withIterationCount(iterationCount);
return this;
}
public OutputEncryptor build(final char[] password)
throws OperatorCreationException
{
final Cipher cipher;
SecretKey key;
if (random == null)
{
random = new SecureRandom();
}
final AlgorithmIdentifier encryptionAlg;
try
{
if (isPKCS12(algorithm))
{
byte[] salt = new byte[20];
random.nextBytes(salt);
cipher = helper.createCipher(algorithm.getId());
cipher.init(Cipher.ENCRYPT_MODE, new PKCS12KeyWithParameters(password, salt, iterationCount));
encryptionAlg = new AlgorithmIdentifier(algorithm, new PKCS12PBEParams(salt, iterationCount));
}
else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
{
PBKDFConfig pbkDef = (pbkdf == null) ? pbkdfBuilder.build() : pbkdf;
if (MiscObjectIdentifiers.id_scrypt.equals(pbkDef.getAlgorithm()))
{
ScryptConfig skdf = (ScryptConfig)pbkDef;
byte[] salt = new byte[skdf.getSaltLength()];
random.nextBytes(salt);
ScryptParams params = new ScryptParams(
salt,
skdf.getCostParameter(),
skdf.getBlockSize(),
skdf.getParallelizationParameter());
SecretKeyFactory keyFact = helper.createSecretKeyFactory("SCRYPT");
key = keyFact.generateSecret(new ScryptKeySpec(password,
salt, skdf.getCostParameter(), skdf.getBlockSize(), skdf.getParallelizationParameter(),
keySizeProvider.getKeySize(new AlgorithmIdentifier(keyEncAlgorithm))));
cipher = helper.createCipher(keyEncAlgorithm.getId());
cipher.init(Cipher.ENCRYPT_MODE, simplifyPbeKey(key), random);
AlgorithmParameters algP = cipher.getParameters();
PBES2Parameters algParams;
if (algP != null)
{
algParams = new PBES2Parameters(
new KeyDerivationFunc(MiscObjectIdentifiers.id_scrypt, params),
new EncryptionScheme(keyEncAlgorithm, ASN1Primitive.fromByteArray(cipher.getParameters().getEncoded())));
}
else
{
algParams = new PBES2Parameters(
new KeyDerivationFunc(MiscObjectIdentifiers.id_scrypt, params),
new EncryptionScheme(keyEncAlgorithm));
}
encryptionAlg = new AlgorithmIdentifier(algorithm, algParams);
}
else
{
PBKDF2Config pkdf = (PBKDF2Config)pbkDef;
byte[] salt = new byte[pkdf.getSaltLength()];
random.nextBytes(salt);
SecretKeyFactory keyFact = helper.createSecretKeyFactory(JceUtils.getAlgorithm(pkdf.getPRF().getAlgorithm()));
key = keyFact.generateSecret(new PBEKeySpec(password, salt, pkdf.getIterationCount(),
keySizeProvider.getKeySize(new AlgorithmIdentifier(keyEncAlgorithm))));
cipher = helper.createCipher(keyEncAlgorithm.getId());
cipher.init(Cipher.ENCRYPT_MODE, simplifyPbeKey(key), random);
AlgorithmParameters algP = cipher.getParameters();
PBES2Parameters algParams;
if (algP != null)
{
algParams = new PBES2Parameters(
new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, pkdf.getIterationCount(), pkdf.getPRF())),
new EncryptionScheme(keyEncAlgorithm, ASN1Primitive.fromByteArray(cipher.getParameters().getEncoded())));
}
else
{
algParams = new PBES2Parameters(
new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, pkdf.getIterationCount(), pkdf.getPRF())),
new EncryptionScheme(keyEncAlgorithm));
}
encryptionAlg = new AlgorithmIdentifier(algorithm, algParams);
}
}
else
{
throw new OperatorCreationException("unrecognised algorithm");
}
return new OutputEncryptor()
{
public AlgorithmIdentifier getAlgorithmIdentifier()
{
return encryptionAlg;
}
public OutputStream getOutputStream(OutputStream out)
{
return new CipherOutputStream(out, cipher);
}
public GenericKey getKey()
{
if (isPKCS12(encryptionAlg.getAlgorithm()))
{
return new GenericKey(encryptionAlg, PKCS12PasswordToBytes(password));
}
else
{
return new GenericKey(encryptionAlg, PKCS5PasswordToBytes(password));
}
}
};
}
catch (Exception e)
{
throw new OperatorCreationException("unable to create OutputEncryptor: " + e.getMessage(), e);
}
}
// some providers struggle with generic algorithm names in keys.
private SecretKey simplifyPbeKey(SecretKey key)
{
if (algorithmNameFinder.hasAlgorithmName(keyEncAlgorithm))
{
String algName = algorithmNameFinder.getAlgorithmName(keyEncAlgorithm);
if (algName.indexOf("AES") >= 0)
{
key = new SecretKeySpec(key.getEncoded(), "AES");
}
}
return key;
}
private boolean isPKCS12(ASN1ObjectIdentifier algorithm)
{
return algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)
|| algorithm.on(BCObjectIdentifiers.bc_pbe_sha1_pkcs12)
|| algorithm.on(BCObjectIdentifiers.bc_pbe_sha256_pkcs12);
}
/**
* converts a password to a byte array according to the scheme in
* PKCS5 (ascii, no padding)
*
* @param password a character array representing the password.
* @return a byte array representing the password.
*/
private static byte[] PKCS5PasswordToBytes(
char[] password)
{
if (password != null)
{
byte[] bytes = new byte[password.length];
for (int i = 0; i != bytes.length; i++)
{
bytes[i] = (byte)password[i];
}
return bytes;
}
else
{
return new byte[0];
}
}
/**
* converts a password to a byte array according to the scheme in
* PKCS12 (unicode, big endian, 2 zero pad bytes at the end).
*
* @param password a character array representing the password.
* @return a byte array representing the password.
*/
private static byte[] PKCS12PasswordToBytes(
char[] password)
{
if (password != null && password.length > 0)
{
// +1 for extra 2 pad bytes.
byte[] bytes = new byte[(password.length + 1) * 2];
for (int i = 0; i != password.length; i++)
{
bytes[i * 2] = (byte)(password[i] >>> 8);
bytes[i * 2 + 1] = (byte)password[i];
}
return bytes;
}
else
{
return new byte[0];
}
}
}