org.bouncycastle.openssl.MiscPEMGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.bouncycastle.openssl.MiscPEMGenerator.java

Source

package org.bouncycastle.openssl;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.DSAParameter;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.util.Strings;
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;

/**
 * PEM generator for the original set of PEM objects used in Open SSL.
 */
public class MiscPEMGenerator implements PemObjectGenerator {
    private static final ASN1ObjectIdentifier[] dsaOids = { X9ObjectIdentifiers.id_dsa,
            OIWObjectIdentifiers.dsaWithSHA1 };

    private static final byte[] hexEncodingTable = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4',
            (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C',
            (byte) 'D', (byte) 'E', (byte) 'F' };

    private final Object obj;
    private final PEMEncryptor encryptor;

    public MiscPEMGenerator(Object o) {
        this.obj = o; // use of this confuses some earlier JDKs.
        this.encryptor = null;
    }

    public MiscPEMGenerator(Object o, PEMEncryptor encryptor) {
        this.obj = o;
        this.encryptor = encryptor;
    }

    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 X509CertificateHolder) {
            type = "CERTIFICATE";

            encoding = ((X509CertificateHolder) o).getEncoded();
        } else if (o instanceof X509CRLHolder) {
            type = "X509 CRL";

            encoding = ((X509CRLHolder) o).getEncoded();
        } else if (o instanceof X509TrustedCertificateBlock) {
            type = "TRUSTED CERTIFICATE";

            encoding = ((X509TrustedCertificateBlock) o).getEncoded();
        } else if (o instanceof PrivateKeyInfo) {
            PrivateKeyInfo info = (PrivateKeyInfo) o;
            ASN1ObjectIdentifier algOID = info.getPrivateKeyAlgorithm().getAlgorithm();

            if (algOID.equals(PKCSObjectIdentifiers.rsaEncryption)) {
                type = "RSA PRIVATE KEY";

                encoding = info.parsePrivateKey().toASN1Primitive().getEncoded();
            } else if (algOID.equals(dsaOids[0]) || algOID.equals(dsaOids[1])) {
                type = "DSA PRIVATE KEY";

                DSAParameter p = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
                ASN1EncodableVector v = new ASN1EncodableVector();

                v.add(new ASN1Integer(0));
                v.add(new ASN1Integer(p.getP()));
                v.add(new ASN1Integer(p.getQ()));
                v.add(new ASN1Integer(p.getG()));

                BigInteger x = ASN1Integer.getInstance(info.parsePrivateKey()).getValue();
                BigInteger y = p.getG().modPow(x, p.getP());

                v.add(new ASN1Integer(y));
                v.add(new ASN1Integer(x));

                encoding = new DERSequence(v).getEncoded();
            } else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey)) {
                type = "EC PRIVATE KEY";

                encoding = info.parsePrivateKey().toASN1Primitive().getEncoded();
            } else {
                throw new IOException("Cannot identify private key");
            }
        } else if (o instanceof SubjectPublicKeyInfo) {
            type = "PUBLIC KEY";

            encoding = ((SubjectPublicKeyInfo) o).getEncoded();
        } else if (o instanceof X509AttributeCertificateHolder) {
            type = "ATTRIBUTE CERTIFICATE";
            encoding = ((X509AttributeCertificateHolder) o).getEncoded();
        } else if (o instanceof org.bouncycastle.pkcs.PKCS10CertificationRequest) {
            type = "CERTIFICATE REQUEST";
            encoding = ((PKCS10CertificationRequest) o).getEncoded();
        } else if (o instanceof PKCS8EncryptedPrivateKeyInfo) {
            type = "ENCRYPTED PRIVATE KEY";
            encoding = ((PKCS8EncryptedPrivateKeyInfo) o).getEncoded();
        } else if (o instanceof ContentInfo) {
            type = "PKCS7";
            encoding = ((ContentInfo) o).getEncoded();
        } else {
            throw new PemGenerationException("unknown object passed - can't encode.");
        }

        if (encryptor != null) {
            String dekAlgName = Strings.toUpperCase(encryptor.getAlgorithm());

            // Note: For backward compatibility
            if (dekAlgName.equals("DESEDE")) {
                dekAlgName = "DES-EDE3-CBC";
            }

            byte[] iv = encryptor.getIV();

            byte[] encData = encryptor.encrypt(encoding);

            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);
        }
        return new PemObject(type, encoding);
    }

    private String getHexEncoded(byte[] bytes) throws IOException {
        char[] chars = new char[bytes.length * 2];

        for (int i = 0; i != bytes.length; i++) {
            int v = bytes[i] & 0xff;

            chars[2 * i] = (char) (hexEncodingTable[(v >>> 4)]);
            chars[2 * i + 1] = (char) (hexEncodingTable[v & 0xf]);
        }

        return new String(chars);
    }

    public PemObject generate() throws PemGenerationException {
        try {
            return createPemObject(obj);
        } catch (IOException e) {
            throw new PemGenerationException("encoding exception: " + e.getMessage(), e);
        }
    }
}