1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.bouncycastle.openssl;
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.BufferedWriter;
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ByteArrayInputStream;
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ByteArrayOutputStream;
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.Writer;
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.math.BigInteger;
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.Key;
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.KeyPair;
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.PrivateKey;
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.PublicKey;
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.SecureRandom;
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.cert.CRLException;
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.cert.CertificateEncodingException;
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.cert.X509CRL;
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.cert.X509Certificate;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.interfaces.DSAPrivateKey;
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.interfaces.RSAPrivateCrtKey;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.interfaces.RSAPrivateKey;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport javax.crypto.Cipher;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport javax.crypto.SecretKey;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport javax.crypto.spec.IvParameterSpec;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport javax.crypto.spec.SecretKeySpec;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.ASN1EncodableVector;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.ASN1InputStream;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.ASN1OutputStream;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.ASN1Sequence;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.DERInteger;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.DERSequence;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.cms.ContentInfo;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.asn1.x509.DSAParameter;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.PBEParametersGenerator;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.KeyParameter;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.jce.PKCS10CertificationRequest;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.util.encoders.Base64;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.util.encoders.Hex;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.x509.X509AttributeCertificate;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.x509.X509V2AttributeCertificate;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * General purpose writer for OpenSSL PEM objects.
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class PEMWriter
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    extends BufferedWriter
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Base constructor.
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param out output stream to use.
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public PEMWriter(Writer out)
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        super(out);
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void writeHexEncoded(byte[] bytes)
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws IOException
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytes = Hex.encode(bytes);
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i != bytes.length; i++)
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.write((char)bytes[i]);
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void writeEncoded(byte[] bytes)
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws IOException
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char[]  buf = new char[64];
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytes = Base64.encode(bytes);
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < bytes.length; i += buf.length)
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int index = 0;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            while (index != buf.length)
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if ((i + index) >= bytes.length)
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                {
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                buf[index] = (char)bytes[i + index];
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                index++;
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.write(buf, 0, index);
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.newLine();
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeObject(
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Object  o)
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws IOException
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String  type;
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  encoding;
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (o instanceof X509Certificate)
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            type = "CERTIFICATE";
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                encoding = ((X509Certificate)o).getEncoded();
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            catch (CertificateEncodingException e)
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new IOException("Cannot encode object: " + e.toString());
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (o instanceof X509CRL)
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            type = "X509 CRL";
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                encoding = ((X509CRL)o).getEncoded();
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            catch (CRLException e)
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new IOException("Cannot encode object: " + e.toString());
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (o instanceof KeyPair)
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            writeObject(((KeyPair)o).getPrivate());
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (o instanceof PrivateKey)
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ByteArrayInputStream    bIn = new ByteArrayInputStream(((Key)o).getEncoded());
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ASN1InputStream         aIn = new ASN1InputStream(bIn);
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            PrivateKeyInfo          info = new PrivateKeyInfo((ASN1Sequence)aIn.readObject());
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (o instanceof RSAPrivateKey)
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                type = "RSA PRIVATE KEY";
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                aOut.writeObject(info.getPrivateKey());
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            else if (o instanceof DSAPrivateKey)
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                type = "DSA PRIVATE KEY";
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DSAParameter        p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ASN1EncodableVector v = new ASN1EncodableVector();
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                v.add(new DERInteger(0));
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                v.add(new DERInteger(p.getP()));
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                v.add(new DERInteger(p.getQ()));
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                v.add(new DERInteger(p.getG()));
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                BigInteger x = ((DSAPrivateKey)o).getX();
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                BigInteger y = p.getG().modPow(x, p.getP());
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                v.add(new DERInteger(y));
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                v.add(new DERInteger(x));
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                aOut.writeObject(new DERSequence(v));
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            else
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new IOException("Cannot identify private key");
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            encoding = bOut.toByteArray();
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (o instanceof PublicKey)
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            type = "PUBLIC KEY";
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            encoding = ((PublicKey)o).getEncoded();
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (o instanceof X509AttributeCertificate)
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            type = "ATTRIBUTE CERTIFICATE";
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            encoding = ((X509V2AttributeCertificate)o).getEncoded();
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (o instanceof PKCS10CertificationRequest)
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            type = "CERTIFICATE REQUEST";
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            encoding = ((PKCS10CertificationRequest)o).getEncoded();
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else if (o instanceof ContentInfo)
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            type = "PKCS7";
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            encoding = ((ContentInfo)o).getEncoded();
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IOException("unknown object passed - can't encode.");
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.write("-----BEGIN " + type + "-----");
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.newLine();
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        writeEncoded(encoding);
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.write("-----END " + type + "-----");
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.newLine();
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeObject(
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Object       o,
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String       algorithm,
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char[]       password,
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SecureRandom random)
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throws IOException
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] salt = new byte[8];
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        random.nextBytes(salt);
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt);
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SecretKey secretKey = null;
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (algorithm.equalsIgnoreCase("DESEDE"))
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // generate key
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int keyLength = 24;
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            secretKey = new SecretKeySpec(((KeyParameter)pGen.generateDerivedParameters(keyLength * 8)).getKey(), algorithm);
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IOException("unknown algorithm in writeObject");
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] keyData = null;
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (o instanceof RSAPrivateCrtKey)
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RSAPrivateCrtKey k = (RSAPrivateCrtKey)o;
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                k.getModulus(),
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                k.getPublicExponent(),
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                k.getPrivateExponent(),
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                k.getPrimeP(),
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                k.getPrimeQ(),
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                k.getPrimeExponentP(),
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                k.getPrimeExponentQ(),
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                k.getCrtCoefficient());
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // convert to bytearray
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ASN1OutputStream      aOut = new ASN1OutputStream(bOut);
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            aOut.writeObject(keyStruct);
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            aOut.close();
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            keyData = bOut.toByteArray();
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[]  encData = null;
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // cipher
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Cipher  c = Cipher.getInstance("DESede/CBC/PKCS5Padding", "BC");
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(salt));
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            encData = c.doFinal(keyData);
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        catch (Exception e)
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IOException("exception using cipher: " + e.toString());
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // write the data
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.write("-----BEGIN RSA PRIVATE KEY-----");
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.newLine();
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.write("Proc-Type: 4,ENCRYPTED");
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.newLine();
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.write("DEK-Info: DES-EDE3-CBC,");
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.writeHexEncoded(salt);
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.newLine();
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.newLine();
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.writeEncoded(encData);
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.write("-----END RSA PRIVATE KEY-----");
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
296