Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pkix/src/main/java/org/spongycastle/openssl/jcajce')
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java98
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java115
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMWriter.java68
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java18
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java141
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java221
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java54
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java78
-rw-r--r--pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java257
9 files changed, 1050 insertions, 0 deletions
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java
new file mode 100644
index 00000000..88f2a32e
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java
@@ -0,0 +1,98 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.jcajce.JcaX509AttributeCertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.jce.PKCS10CertificationRequest;
+import org.spongycastle.openssl.MiscPEMGenerator;
+import org.spongycastle.openssl.PEMEncryptor;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509V2AttributeCertificate;
+
+/**
+ * PEM generator for the original set of PEM objects used in Open SSL.
+ */
+public class JcaMiscPEMGenerator
+ extends MiscPEMGenerator
+{
+ private Object obj;
+ private String algorithm;
+ private char[] password;
+ private SecureRandom random;
+ private Provider provider;
+
+ public JcaMiscPEMGenerator(Object o)
+ throws IOException
+ {
+ super(convertObject(o));
+ }
+
+ public JcaMiscPEMGenerator(Object o, PEMEncryptor encryptor)
+ throws IOException
+ {
+ super(convertObject(o), encryptor);
+ }
+
+ private static Object convertObject(Object o)
+ throws IOException
+ {
+ if (o instanceof X509Certificate)
+ {
+ try
+ {
+ return new JcaX509CertificateHolder((X509Certificate)o);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IllegalArgumentException("Cannot encode object: " + e.toString());
+ }
+ }
+ else if (o instanceof X509CRL)
+ {
+ try
+ {
+ return new JcaX509CRLHolder((X509CRL)o);
+ }
+ catch (CRLException e)
+ {
+ throw new IllegalArgumentException("Cannot encode object: " + e.toString());
+ }
+ }
+ else if (o instanceof KeyPair)
+ {
+ return convertObject(((KeyPair)o).getPrivate());
+ }
+ else if (o instanceof PrivateKey)
+ {
+ return PrivateKeyInfo.getInstance(((Key)o).getEncoded());
+ }
+ else if (o instanceof PublicKey)
+ {
+ return SubjectPublicKeyInfo.getInstance(((PublicKey)o).getEncoded());
+ }
+ else if (o instanceof X509AttributeCertificate)
+ {
+ return new JcaX509AttributeCertificateHolder((X509V2AttributeCertificate)o);
+ }
+ else if (o instanceof PKCS10CertificationRequest)
+ {
+ return new org.spongycastle.pkcs.PKCS10CertificationRequest(((PKCS10CertificationRequest)o).getEncoded());
+ }
+
+ return o;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java
new file mode 100644
index 00000000..1b15639a
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java
@@ -0,0 +1,115 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.JcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.openssl.PEMKeyPair;
+
+public class JcaPEMKeyConverter
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ private static final Map algorithms = new HashMap();
+
+ static
+ {
+ algorithms.put(X9ObjectIdentifiers.id_ecPublicKey, "ECDSA");
+ algorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ algorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+ }
+
+ public JcaPEMKeyConverter setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcaPEMKeyConverter setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public KeyPair getKeyPair(PEMKeyPair keyPair)
+ throws PEMException
+ {
+ try
+ {
+ KeyFactory keyFactory = getKeyFactory(keyPair.getPrivateKeyInfo().getPrivateKeyAlgorithm());
+
+ return new KeyPair(keyFactory.generatePublic(new X509EncodedKeySpec(keyPair.getPublicKeyInfo().getEncoded())),
+ keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyPair.getPrivateKeyInfo().getEncoded())));
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("unable to convert key pair: " + e.getMessage(), e);
+ }
+ }
+
+ public PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws PEMException
+ {
+ try
+ {
+ KeyFactory keyFactory = getKeyFactory(publicKeyInfo.getAlgorithm());
+
+ return keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("unable to convert key pair: " + e.getMessage(), e);
+ }
+ }
+
+ public PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+ throws PEMException
+ {
+ try
+ {
+ KeyFactory keyFactory = getKeyFactory(privateKeyInfo.getPrivateKeyAlgorithm());
+
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("unable to convert key pair: " + e.getMessage(), e);
+ }
+ }
+
+ private KeyFactory getKeyFactory(AlgorithmIdentifier algId)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+
+ String algName = (String)algorithms.get(algorithm);
+
+ if (algName == null)
+ {
+ algName = algorithm.getId();
+ }
+
+ return helper.createKeyFactory(algName);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMWriter.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMWriter.java
new file mode 100644
index 00000000..0224b89e
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMWriter.java
@@ -0,0 +1,68 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.spongycastle.openssl.PEMEncryptor;
+import org.spongycastle.util.io.pem.PemGenerationException;
+import org.spongycastle.util.io.pem.PemObjectGenerator;
+import org.spongycastle.util.io.pem.PemWriter;
+
+/**
+ * General purpose writer for OpenSSL PEM objects based on JCA/JCE classes.
+ */
+public class JcaPEMWriter
+ extends PemWriter
+{
+ /**
+ * Base constructor.
+ *
+ * @param out output stream to use.
+ */
+ public JcaPEMWriter(Writer out)
+ {
+ super(out);
+ }
+
+ /**
+ * @throws java.io.IOException
+ */
+ public void writeObject(
+ Object obj)
+ throws IOException
+ {
+ writeObject(obj, null);
+ }
+
+ /**
+ * @param obj
+ * @param encryptor
+ * @throws java.io.IOException
+ */
+ public void writeObject(
+ Object obj,
+ PEMEncryptor encryptor)
+ throws IOException
+ {
+ try
+ {
+ super.writeObject(new JcaMiscPEMGenerator(obj, encryptor));
+ }
+ catch (PemGenerationException e)
+ {
+ if (e.getCause() instanceof IOException)
+ {
+ throw (IOException)e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ public void writeObject(
+ PemObjectGenerator obj)
+ throws IOException
+ {
+ super.writeObject(obj);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java
new file mode 100644
index 00000000..9c4e4f46
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java
@@ -0,0 +1,18 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.PrivateKey;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.openssl.PKCS8Generator;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.util.io.pem.PemGenerationException;
+
+public class JcaPKCS8Generator
+ extends PKCS8Generator
+{
+ public JcaPKCS8Generator(PrivateKey key, OutputEncryptor encryptor)
+ throws PemGenerationException
+ {
+ super(PrivateKeyInfo.getInstance(key.getEncoded()), encryptor);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java
new file mode 100644
index 00000000..5050f4b2
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java
@@ -0,0 +1,141 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+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.spongycastle.asn1.pkcs.EncryptionScheme;
+import org.spongycastle.asn1.pkcs.KeyDerivationFunc;
+import org.spongycastle.asn1.pkcs.PBEParameter;
+import org.spongycastle.asn1.pkcs.PBES2Parameters;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.JcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.InputDecryptorProvider;
+import org.spongycastle.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 (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e);
+ }
+ };
+ };
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java
new file mode 100644
index 00000000..8404661f
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java
@@ -0,0 +1,221 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.KeyDerivationFunc;
+import org.spongycastle.asn1.pkcs.PBES2Parameters;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.JcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+public class JceOpenSSLPKCS8EncryptorBuilder
+{
+ public static final String AES_128_CBC = NISTObjectIdentifiers.id_aes128_CBC.getId();
+ public static final String AES_192_CBC = NISTObjectIdentifiers.id_aes192_CBC.getId();
+ public static final String AES_256_CBC = NISTObjectIdentifiers.id_aes256_CBC.getId();
+
+ public static final String DES3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC.getId();
+
+ public static final String PBE_SHA1_RC4_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4.getId();
+ public static final String PBE_SHA1_RC4_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4.getId();
+ public static final String PBE_SHA1_3DES = PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC.getId();
+ public static final String PBE_SHA1_2DES = PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC.getId();
+ public static final String PBE_SHA1_RC2_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC.getId();
+ public static final String PBE_SHA1_RC2_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC.getId();
+
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ private AlgorithmParameters params;
+ private ASN1ObjectIdentifier algOID;
+ byte[] salt;
+ int iterationCount;
+ private Cipher cipher;
+ private SecureRandom random;
+ private AlgorithmParameterGenerator paramGen;
+ private SecretKeyFactory secKeyFact;
+ private char[] password;
+
+ private SecretKey key;
+
+ public JceOpenSSLPKCS8EncryptorBuilder(ASN1ObjectIdentifier algorithm)
+ {
+ algOID = algorithm;
+
+ this.iterationCount = 2048;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setPasssword(char[] password)
+ {
+ this.password = password;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setIterationCount(int iterationCount)
+ {
+ this.iterationCount = iterationCount;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setProvider(String providerName)
+ {
+ helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setProvider(Provider provider)
+ {
+ helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws OperatorCreationException
+ {
+ final AlgorithmIdentifier algID;
+
+ salt = new byte[20];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(salt);
+
+ try
+ {
+ this.cipher = helper.createCipher(algOID.getId());
+
+ if (PEMUtilities.isPKCS5Scheme2(algOID))
+ {
+ this.paramGen = helper.createAlgorithmParameterGenerator(algOID.getId());
+ }
+ else
+ {
+ this.secKeyFact = helper.createSecretKeyFactory(algOID.getId());
+ }
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(algOID + " not available: " + e.getMessage(), e);
+ }
+
+ if (PEMUtilities.isPKCS5Scheme2(algOID))
+ {
+ params = paramGen.generateParameters();
+
+ try
+ {
+ KeyDerivationFunc scheme = new KeyDerivationFunc(algOID, ASN1Primitive.fromByteArray(params.getEncoded()));
+ KeyDerivationFunc func = new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(func);
+ v.add(scheme);
+
+ algID = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, PBES2Parameters.getInstance(new DERSequence(v)));
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+
+ key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algOID.getId(), password, salt, iterationCount);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, key, params);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+ }
+ else if (PEMUtilities.isPKCS12(algOID))
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DEROctetString(salt));
+ v.add(new ASN1Integer(iterationCount));
+
+ algID = new AlgorithmIdentifier(algOID, PKCS12PBEParams.getInstance(new DERSequence(v)));
+
+ try
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
+
+ key = secKeyFact.generateSecret(pbeSpec);
+
+ cipher.init(Cipher.ENCRYPT_MODE, key, defParams);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+ }
+ else
+ {
+ throw new OperatorCreationException("unknown algorithm: " + algOID, null);
+ }
+
+ return new OutputEncryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algID;
+ }
+
+ public OutputStream getOutputStream(OutputStream encOut)
+ {
+ return new CipherOutputStream(encOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(algID, key);
+ }
+ };
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java
new file mode 100644
index 00000000..b54d7fd3
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java
@@ -0,0 +1,54 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.Provider;
+
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.JcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMDecryptor;
+import org.spongycastle.openssl.PEMDecryptorProvider;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.openssl.PasswordException;
+
+public class JcePEMDecryptorProviderBuilder
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ public JcePEMDecryptorProviderBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcePEMDecryptorProviderBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public PEMDecryptorProvider build(final char[] password)
+ {
+ return new PEMDecryptorProvider()
+ {
+ public PEMDecryptor get(final String dekAlgName)
+ {
+ return new PEMDecryptor()
+ {
+ public byte[] decrypt(byte[] keyBytes, byte[] iv)
+ throws PEMException
+ {
+ if (password == null)
+ {
+ throw new PasswordException("Password is null, but a password is required");
+ }
+
+ return PEMUtilities.crypt(false, helper, keyBytes, password, dekAlgName, iv);
+ }
+ };
+ }
+ };
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java
new file mode 100644
index 00000000..3360f8a8
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java
@@ -0,0 +1,78 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import org.spongycastle.jcajce.util.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.util.JcaJceHelper;
+import org.spongycastle.jcajce.util.NamedJcaJceHelper;
+import org.spongycastle.jcajce.util.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMEncryptor;
+import org.spongycastle.openssl.PEMException;
+
+public class JcePEMEncryptorBuilder
+{
+ private final String algorithm;
+
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+ private SecureRandom random;
+
+ public JcePEMEncryptorBuilder(String algorithm)
+ {
+ this.algorithm = algorithm;
+ }
+
+ public JcePEMEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcePEMEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JcePEMEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public PEMEncryptor build(final char[] password)
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ int ivLength = algorithm.startsWith("AES-") ? 16 : 8;
+
+ final byte[] iv = new byte[ivLength];
+
+ random.nextBytes(iv);
+
+ return new PEMEncryptor()
+ {
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public byte[] getIV()
+ {
+ return iv;
+ }
+
+ public byte[] encrypt(byte[] encoding)
+ throws PEMException
+ {
+ return PEMUtilities.crypt(true, helper, encoding, password, algorithm, iv);
+ }
+ };
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java
new file mode 100644
index 00000000..6bfa2a57
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java
@@ -0,0 +1,257 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.jcajce.util.JcaJceHelper;
+import org.spongycastle.openssl.EncryptionException;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.util.Integers;
+
+class PEMUtilities
+{
+ private static final Map KEYSIZES = new HashMap();
+ private static final Set PKCS5_SCHEME_1 = new HashSet();
+ private static final Set PKCS5_SCHEME_2 = new HashSet();
+
+ static
+ {
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC);
+
+ PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2);
+ PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC);
+
+ KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integers.valueOf(128));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integers.valueOf(192));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integers.valueOf(256));
+ }
+
+ static int getKeySize(String algorithm)
+ {
+ if (!KEYSIZES.containsKey(algorithm))
+ {
+ throw new IllegalStateException("no key size for algorithm: " + algorithm);
+ }
+
+ return ((Integer)KEYSIZES.get(algorithm)).intValue();
+ }
+
+ static boolean isPKCS5Scheme1(ASN1ObjectIdentifier algOid)
+ {
+ return PKCS5_SCHEME_1.contains(algOid);
+ }
+
+ static boolean isPKCS5Scheme2(ASN1ObjectIdentifier algOid)
+ {
+ return PKCS5_SCHEME_2.contains(algOid);
+ }
+
+ public static boolean isPKCS12(ASN1ObjectIdentifier algOid)
+ {
+ return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId());
+ }
+
+ public static SecretKey generateSecretKeyForPKCS5Scheme2(String algorithm, char[] password, byte[] salt, int iterationCount)
+ {
+ PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
+
+ generator.init(
+ PBEParametersGenerator.PKCS5PasswordToBytes(password),
+ salt,
+ iterationCount);
+
+ return new SecretKeySpec(((KeyParameter)generator.generateDerivedParameters(PEMUtilities.getKeySize(algorithm))).getKey(), algorithm);
+ }
+
+ static byte[] crypt(
+ boolean encrypt,
+ JcaJceHelper helper,
+ byte[] bytes,
+ char[] password,
+ String dekAlgName,
+ byte[] iv)
+ throws PEMException
+ {
+ AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
+ String alg;
+ String blockMode = "CBC";
+ String padding = "PKCS5Padding";
+ Key sKey;
+
+ // Figure out block mode and padding.
+ if (dekAlgName.endsWith("-CFB"))
+ {
+ blockMode = "CFB";
+ padding = "NoPadding";
+ }
+ if (dekAlgName.endsWith("-ECB") ||
+ "DES-EDE".equals(dekAlgName) ||
+ "DES-EDE3".equals(dekAlgName))
+ {
+ // ECB is actually the default (though seldom used) when OpenSSL
+ // uses DES-EDE (des2) or DES-EDE3 (des3).
+ blockMode = "ECB";
+ paramSpec = null;
+ }
+ if (dekAlgName.endsWith("-OFB"))
+ {
+ blockMode = "OFB";
+ padding = "NoPadding";
+ }
+
+
+ // Figure out algorithm and key size.
+ if (dekAlgName.startsWith("DES-EDE"))
+ {
+ alg = "DESede";
+ // "DES-EDE" is actually des2 in OpenSSL-speak!
+ // "DES-EDE3" is des3.
+ boolean des2 = !dekAlgName.startsWith("DES-EDE3");
+ sKey = getKey(password, alg, 24, iv, des2);
+ }
+ else if (dekAlgName.startsWith("DES-"))
+ {
+ alg = "DES";
+ sKey = getKey(password, alg, 8, iv);
+ }
+ else if (dekAlgName.startsWith("BF-"))
+ {
+ alg = "Blowfish";
+ sKey = getKey(password, alg, 16, iv);
+ }
+ else if (dekAlgName.startsWith("RC2-"))
+ {
+ alg = "RC2";
+ int keyBits = 128;
+ if (dekAlgName.startsWith("RC2-40-"))
+ {
+ keyBits = 40;
+ }
+ else if (dekAlgName.startsWith("RC2-64-"))
+ {
+ keyBits = 64;
+ }
+ sKey = getKey(password, alg, keyBits / 8, iv);
+ if (paramSpec == null) // ECB block mode
+ {
+ paramSpec = new RC2ParameterSpec(keyBits);
+ }
+ else
+ {
+ paramSpec = new RC2ParameterSpec(keyBits, iv);
+ }
+ }
+ else if (dekAlgName.startsWith("AES-"))
+ {
+ alg = "AES";
+ byte[] salt = iv;
+ if (salt.length > 8)
+ {
+ salt = new byte[8];
+ System.arraycopy(iv, 0, salt, 0, 8);
+ }
+
+ int keyBits;
+ if (dekAlgName.startsWith("AES-128-"))
+ {
+ keyBits = 128;
+ }
+ else if (dekAlgName.startsWith("AES-192-"))
+ {
+ keyBits = 192;
+ }
+ else if (dekAlgName.startsWith("AES-256-"))
+ {
+ keyBits = 256;
+ }
+ else
+ {
+ throw new EncryptionException("unknown AES encryption with private key");
+ }
+ sKey = getKey(password, "AES", keyBits / 8, salt);
+ }
+ else
+ {
+ throw new EncryptionException("unknown encryption with private key");
+ }
+
+ String transformation = alg + "/" + blockMode + "/" + padding;
+
+ try
+ {
+ Cipher c = helper.createCipher(transformation);
+ int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+
+ if (paramSpec == null) // ECB block mode
+ {
+ c.init(mode, sKey);
+ }
+ else
+ {
+ c.init(mode, sKey, paramSpec);
+ }
+ return c.doFinal(bytes);
+ }
+ catch (Exception e)
+ {
+ throw new EncryptionException("exception using cipher - please check password and data.", e);
+ }
+ }
+
+ private static SecretKey getKey(
+ char[] password,
+ String algorithm,
+ int keyLength,
+ byte[] salt)
+ {
+ return getKey(password, algorithm, keyLength, salt, false);
+ }
+
+ private static SecretKey getKey(
+ char[] password,
+ String algorithm,
+ int keyLength,
+ byte[] salt,
+ boolean des2)
+ {
+ OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
+
+ pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt);
+
+ KeyParameter keyParam;
+ keyParam = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8);
+ byte[] key = keyParam.getKey();
+ if (des2 && key.length >= 24)
+ {
+ // For DES2, we must copy first 8 bytes into the last 8 bytes.
+ System.arraycopy(key, 0, key, 16, 8);
+ }
+ return new SecretKeySpec(key, algorithm);
+ }
+}