package org.bouncycastle.openssl;
import java.io.IOException;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyPair;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CRLException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
import org.bouncycastle.asn1.x509.DSAParameter;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.io.pem.PemGenerationException;
import org.bouncycastle.util.io.pem.PemHeader;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemObjectGenerator;
import org.bouncycastle.x509.X509AttributeCertificate;
import org.bouncycastle.x509.X509V2AttributeCertificate;
public class MiscPEMGenerator
implements PemObjectGenerator
{
private Object obj;
private String algorithm;
private char[] password;
private SecureRandom random;
private Provider provider;
public MiscPEMGenerator(Object o)
{
this.obj = o;
}
public MiscPEMGenerator(
Object obj,
String algorithm,
char[] password,
SecureRandom random,
Provider provider)
{
this.obj = obj;
this.algorithm = algorithm;
this.password = password;
this.random = random;
this.provider = provider;
}
public MiscPEMGenerator(
Object obj,
String algorithm,
char[] password,
SecureRandom random,
String provider)
throws NoSuchProviderException
{
this.obj = obj;
this.algorithm = algorithm;
this.password = password;
this.random = random;
if (provider != null)
{
this.provider = Security.getProvider(provider);
if (this.provider == null)
{
throw new NoSuchProviderException("cannot find provider: " + provider);
}
}
}
private PemObject createPemObject(Object o)
throws IOException
{
String type;
byte[] encoding;
if (o instanceof PemObject)
{
return (PemObject)o;
}
if (o instanceof PemObjectGenerator)
{
return ((PemObjectGenerator)o).generate();
}
if (o instanceof X509Certificate)
{
type = "CERTIFICATE";
try
{
encoding = ((X509Certificate)o).getEncoded();
}
catch (CertificateEncodingException e)
{
throw new PemGenerationException("Cannot encode object: " + e.toString());
}
}
else if (o instanceof X509CRL)
{
type = "X509 CRL";
try
{
encoding = ((X509CRL)o).getEncoded();
}
catch (CRLException e)
{
throw new PemGenerationException("Cannot encode object: " + e.toString());
}
}
else if (o instanceof KeyPair)
{
return createPemObject(((KeyPair)o).getPrivate());
}
else if (o instanceof PrivateKey)
{
PrivateKeyInfo info = new PrivateKeyInfo(
(ASN1Sequence) ASN1Object.fromByteArray(((Key)o).getEncoded()));
if (o instanceof RSAPrivateKey)
{
type = "RSA PRIVATE KEY";
encoding = info.getPrivateKey().getEncoded();
}
else if (o instanceof DSAPrivateKey)
{
type = "DSA PRIVATE KEY";
DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new DERInteger(0));
v.add(new DERInteger(p.getP()));
v.add(new DERInteger(p.getQ()));
v.add(new DERInteger(p.getG()));
BigInteger x = ((DSAPrivateKey)o).getX();
BigInteger y = p.getG().modPow(x, p.getP());
v.add(new DERInteger(y));
v.add(new DERInteger(x));
encoding = new DERSequence(v).getEncoded();
}
else if (((PrivateKey)o).getAlgorithm().equals("ECDSA"))
{
type = "EC PRIVATE KEY";
encoding = info.getPrivateKey().getEncoded();
}
else
{
throw new IOException("Cannot identify private key");
}
}
else if (o instanceof PublicKey)
{
type = "PUBLIC KEY";
encoding = ((PublicKey)o).getEncoded();
}
else if (o instanceof X509AttributeCertificate)
{
type = "ATTRIBUTE CERTIFICATE";
encoding = ((X509V2AttributeCertificate)o).getEncoded();
}
else if (o instanceof PKCS10CertificationRequest)
{
type = "CERTIFICATE REQUEST";
encoding = ((PKCS10CertificationRequest)o).getEncoded();
}
else if (o instanceof ContentInfo)
{
type = "PKCS7";
encoding = ((ContentInfo)o).getEncoded();
}
else
{
throw new PemGenerationException("unknown object passed - can't encode.");
}
return new PemObject(type, encoding);
}
private String getHexEncoded(byte[] bytes)
throws IOException
{
bytes = Hex.encode(bytes);
char[] chars = new char[bytes.length];
for (int i = 0; i != bytes.length; i++)
{
chars[i] = (char)bytes[i];
}
return new String(chars);
}
private PemObject createPemObject(
Object obj,
String algorithm,
char[] password,
SecureRandom random)
throws IOException
{
if (obj instanceof KeyPair)
{
return createPemObject(((KeyPair)obj).getPrivate(), algorithm, password, random);
}
String type = null;
byte[] keyData = null;
if (obj instanceof RSAPrivateCrtKey)
{
type = "RSA PRIVATE KEY";
RSAPrivateCrtKey k = (RSAPrivateCrtKey)obj;
RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(
k.getModulus(),
k.getPublicExponent(),
k.getPrivateExponent(),
k.getPrimeP(),
k.getPrimeQ(),
k.getPrimeExponentP(),
k.getPrimeExponentQ(),
k.getCrtCoefficient());
keyData = keyStruct.getEncoded();
}
else if (obj instanceof DSAPrivateKey)
{
type = "DSA PRIVATE KEY";
DSAPrivateKey k = (DSAPrivateKey)obj;
DSAParams p = k.getParams();
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new DERInteger(0));
v.add(new DERInteger(p.getP()));
v.add(new DERInteger(p.getQ()));
v.add(new DERInteger(p.getG()));
BigInteger x = k.getX();
BigInteger y = p.getG().modPow(x, p.getP());
v.add(new DERInteger(y));
v.add(new DERInteger(x));
keyData = new DERSequence(v).getEncoded();
}
else if (obj instanceof PrivateKey && "ECDSA".equals(((PrivateKey)obj).getAlgorithm()))
{
type = "EC PRIVATE KEY";
PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(ASN1Object.fromByteArray(((PrivateKey)obj).getEncoded()));
keyData = privInfo.getPrivateKey().getEncoded();
}
if (type == null || keyData == null)
{
throw new IllegalArgumentException("Object type not supported: " + obj.getClass().getName());
}
String dekAlgName = Strings.toUpperCase(algorithm);
if (dekAlgName.equals("DESEDE"))
{
dekAlgName = "DES-EDE3-CBC";
}
int ivLength = dekAlgName.startsWith("AES-") ? 16 : 8;
byte[] iv = new byte[ivLength];
random.nextBytes(iv);
byte[] encData = PEMUtilities.crypt(true, provider, keyData, password, dekAlgName, iv);
List headers = new ArrayList(2);
headers.add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
headers.add(new PemHeader("DEK-Info", dekAlgName + "," + getHexEncoded(iv)));
return new PemObject(type, headers, encData);
}
public PemObject generate()
throws PemGenerationException
{
try
{
if (algorithm != null)
{
return createPemObject(obj, algorithm, password, random);
}
return createPemObject(obj);
}
catch (IOException e)
{
throw new PemGenerationException("encoding exception: " + e.getMessage(), e);
}
}
}