1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.jce.provider;
2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.ByteArrayInputStream;
4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.ByteArrayOutputStream;
5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.DataInputStream;
6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.DataOutputStream;
7b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.IOException;
8b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.InputStream;
9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.OutputStream;
10c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.Key;
11c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.KeyFactory;
12c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.KeyStoreException;
13c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.KeyStoreSpi;
14c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.NoSuchAlgorithmException;
15c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.NoSuchProviderException;
16c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.PrivateKey;
17c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.PublicKey;
18c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.SecureRandom;
19c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.security.UnrecoverableKeyException;
20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.security.cert.Certificate;
21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.security.cert.CertificateEncodingException;
22b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.security.cert.CertificateException;
23b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.security.cert.CertificateFactory;
24b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.security.spec.KeySpec;
25b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.security.spec.PKCS8EncodedKeySpec;
26b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.security.spec.X509EncodedKeySpec;
27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.util.Date;
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.util.Enumeration;
29b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.util.Hashtable;
30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport javax.crypto.Cipher;
32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport javax.crypto.CipherInputStream;
33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport javax.crypto.CipherOutputStream;
34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport javax.crypto.SecretKeyFactory;
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport javax.crypto.spec.PBEKeySpec;
36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport javax.crypto.spec.PBEParameterSpec;
37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport javax.crypto.spec.SecretKeySpec;
38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
39c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.CipherParameters;
40b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.Digest;
41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.PBEParametersGenerator;
4210261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstrom// BEGIN android-added
4310261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstromimport org.bouncycastle.crypto.digests.OpenSSLDigest;
4410261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstrom// END android-added
45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam// BEGIN android-removed
46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam// import org.bouncycastle.crypto.digests.SHA1Digest;
47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam// END android-removed
48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.io.DigestInputStream;
50b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.io.DigestOutputStream;
51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.io.MacInputStream;
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.io.MacOutputStream;
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.macs.HMac;
54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.jce.interfaces.BCKeyStore;
55c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.util.Arrays;
56c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.util.io.Streams;
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class JDKKeyStore
59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    extends KeyStoreSpi
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    implements BCKeyStore
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static final int    STORE_VERSION = 1;
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static final int    STORE_SALT_SIZE = 20;
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static final String STORE_CIPHER = "PBEWithSHAAndTwofish-CBC";
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static final int    KEY_SALT_SIZE = 20;
68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static final int    MIN_ITERATIONS = 1024;
69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private static final String KEY_CIPHER = "PBEWithSHAAnd3-KeyTripleDES-CBC";
71b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    //
73b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    // generic object types
74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    //
75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static final int NULL           = 0;
76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static final int CERTIFICATE    = 1;
77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static final int KEY            = 2;
78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static final int SECRET         = 3;
79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static final int SEALED         = 4;
80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    //
82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    // key types
83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    //
84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static final int    KEY_PRIVATE = 0;
85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static final int    KEY_PUBLIC  = 1;
86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    static final int    KEY_SECRET  = 2;
87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected Hashtable       table = new Hashtable();
89b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
90b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected SecureRandom    random = new SecureRandom();
91b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public JDKKeyStore()
93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private class StoreEntry
97b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int             type;
99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String          alias;
100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Object          obj;
101b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Certificate[]   certChain;
102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Date            date = new Date();
103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry(
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            String       alias,
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Certificate  obj)
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.type = CERTIFICATE;
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.alias = alias;
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.obj = obj;
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.certChain = null;
112b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry(
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            String          alias,
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            byte[]          obj,
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Certificate[]   certChain)
118b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.type = SECRET;
120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.alias = alias;
121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.obj = obj;
122b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.certChain = certChain;
123b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
124b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
125b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry(
126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            String          alias,
127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Key             key,
128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            char[]          password,
129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Certificate[]   certChain)
130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throws Exception
131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.type = SEALED;
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.alias = alias;
134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.certChain = certChain;
135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            byte[] salt = new byte[KEY_SALT_SIZE];
137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            random.setSeed(System.currentTimeMillis());
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            random.nextBytes(salt);
140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            DataOutputStream        dOut = new DataOutputStream(bOut);
146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeInt(salt.length);
148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.write(salt);
149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeInt(iterationCount);
150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Cipher              cipher = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            CipherOutputStream  cOut = new CipherOutputStream(dOut, cipher);
153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut = new DataOutputStream(cOut);
155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            encodeKey(key, dOut);
157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.close();
159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            obj = bOut.toByteArray();
161b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
163b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry(
164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            String          alias,
165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Date            date,
166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            int             type,
167b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Object          obj)
168b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.alias = alias;
170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.date = date;
171b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.type = type;
172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.obj = obj;
173b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
175b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry(
176b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            String          alias,
177b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Date            date,
178b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            int             type,
179b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Object          obj,
180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Certificate[]   certChain)
181b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
182b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.alias = alias;
183b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.date = date;
184b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.type = type;
185b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.obj = obj;
186b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.certChain = certChain;
187b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
188b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
189b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int getType()
190b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
191b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return type;
192b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
193b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
194b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String getAlias()
195b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
196b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return alias;
197b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
198b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
199b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Object getObject()
200b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
201b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return obj;
202b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
203b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
204b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Object getObject(
205b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            char[]  password)
206b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throws NoSuchAlgorithmException, UnrecoverableKeyException
207b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
208b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (password == null || password.length == 0)
209b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
210b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                if (obj instanceof Key)
211b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
212b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    return obj;
213b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
214b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
215b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
216b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (type == SEALED)
217b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
218b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                ByteArrayInputStream    bIn = new ByteArrayInputStream((byte[])obj);
219b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                DataInputStream         dIn = new DataInputStream(bIn);
220b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
221b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                try
222b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
223b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    byte[]      salt = new byte[dIn.readInt()];
224b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
225b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    dIn.readFully(salt);
226b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
227b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    int     iterationCount = dIn.readInt();
228b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
229b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    Cipher      cipher = makePBECipher(KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
230b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
231b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    CipherInputStream cIn = new CipherInputStream(dIn, cipher);
232b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
233b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    try
234b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    {
235b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        return decodeKey(new DataInputStream(cIn));
236b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    }
237b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    catch (Exception x)
238b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    {
239b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        bIn = new ByteArrayInputStream((byte[])obj);
240b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        dIn = new DataInputStream(bIn);
241b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
242b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        salt = new byte[dIn.readInt()];
243b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
244b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        dIn.readFully(salt);
245b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
246b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        iterationCount = dIn.readInt();
247b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
248b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        cipher = makePBECipher("Broken" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
249b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
250b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        cIn = new CipherInputStream(dIn, cipher);
251b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
252b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        Key k = null;
253b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
254b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        try
255b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        {
256b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            k = decodeKey(new DataInputStream(cIn));
257b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        }
258b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        catch (Exception y)
259b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        {
260b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            bIn = new ByteArrayInputStream((byte[])obj);
261b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            dIn = new DataInputStream(bIn);
262b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
263b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            salt = new byte[dIn.readInt()];
264b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
265b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            dIn.readFully(salt);
266b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
267b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            iterationCount = dIn.readInt();
268b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
269b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            cipher = makePBECipher("Old" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
270b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
271b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            cIn = new CipherInputStream(dIn, cipher);
272b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
273b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            k = decodeKey(new DataInputStream(cIn));
274b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        }
275b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
276b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        //
277b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        // reencrypt key with correct cipher.
278b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        //
279b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        if (k != null)
280b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        {
281b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
282b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            DataOutputStream        dOut = new DataOutputStream(bOut);
283b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
284b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            dOut.writeInt(salt.length);
285b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            dOut.write(salt);
286b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            dOut.writeInt(iterationCount);
287b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
288b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            Cipher              out = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
289b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            CipherOutputStream  cOut = new CipherOutputStream(dOut, out);
290b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
291b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            dOut = new DataOutputStream(cOut);
292b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
293b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            encodeKey(k, dOut);
294b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
295b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            dOut.close();
296b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
297b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            obj = bOut.toByteArray();
298b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
299b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            return k;
300b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        }
301b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        else
302b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        {
303b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                            throw new UnrecoverableKeyException("no match");
304b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        }
305b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    }
306b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
307b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                catch (Exception e)
308b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
309b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    throw new UnrecoverableKeyException("no match");
310b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
311b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
312b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            else
313b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
314b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                throw new RuntimeException("forget something!");
315b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                // TODO
316b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                // if we get to here key was saved as byte data, which
317b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                // according to the docs means it must be a private key
318b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                // in EncryptedPrivateKeyInfo (PKCS8 format), later...
319b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                //
320b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
321b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
322b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
323b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Certificate[] getCertificateChain()
324b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
325b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return certChain;
326b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
327b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
328b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Date getDate()
329b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
330b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return date;
331b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
332b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
333b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
334b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private void encodeCertificate(
335b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Certificate         cert,
336b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        DataOutputStream    dOut)
337b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
338b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
339b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        try
340b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
341b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            byte[]      cEnc = cert.getEncoded();
342b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
343b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeUTF(cert.getType());
344b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeInt(cEnc.length);
345b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.write(cEnc);
346b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
347b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        catch (CertificateEncodingException ex)
348b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
349b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new IOException(ex.toString());
350b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
351b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
352b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
353b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private Certificate decodeCertificate(
354b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        DataInputStream   dIn)
355b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
356b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
357b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String      type = dIn.readUTF();
358b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      cEnc = new byte[dIn.readInt()];
359b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
360b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dIn.readFully(cEnc);
361b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
362b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        try
363b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
3646e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            CertificateFactory cFact = CertificateFactory.getInstance(type, BouncyCastleProvider.PROVIDER_NAME);
365b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            ByteArrayInputStream bIn = new ByteArrayInputStream(cEnc);
366b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
367b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return cFact.generateCertificate(bIn);
368b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
369b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        catch (NoSuchProviderException ex)
370b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
371b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new IOException(ex.toString());
372b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
373b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        catch (CertificateException ex)
374b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
375b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new IOException(ex.toString());
376b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
377b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
378b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
379b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private void encodeKey(
380b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Key                 key,
381b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        DataOutputStream    dOut)
382b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
383b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
384b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      enc = key.getEncoded();
385b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
386b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (key instanceof PrivateKey)
387b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
388b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.write(KEY_PRIVATE);
389b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
390b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else if (key instanceof PublicKey)
391b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
392b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.write(KEY_PUBLIC);
393b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
394b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
395b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
396b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.write(KEY_SECRET);
397b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
398b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
399b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.writeUTF(key.getFormat());
400b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.writeUTF(key.getAlgorithm());
401b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.writeInt(enc.length);
402b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.write(enc);
403b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
404b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
405b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    private Key decodeKey(
406b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        DataInputStream dIn)
407b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
408b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
409b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         keyType = dIn.read();
410b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String      format = dIn.readUTF();
411b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String      algorithm = dIn.readUTF();
412b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      enc = new byte[dIn.readInt()];
413b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        KeySpec     spec;
414b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
415b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dIn.readFully(enc);
416b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
417b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (format.equals("PKCS#8") || format.equals("PKCS8"))
418b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
419b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            spec = new PKCS8EncodedKeySpec(enc);
420b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
421b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else if (format.equals("X.509") || format.equals("X509"))
422b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
423b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            spec = new X509EncodedKeySpec(enc);
424b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
425b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else if (format.equals("RAW"))
426b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
427b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return new SecretKeySpec(enc, algorithm);
428b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
429b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
430b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
431b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new IOException("Key format " + format + " not recognised!");
432b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
433b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
434b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        try
435b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
436b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            switch (keyType)
437b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
438b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case KEY_PRIVATE:
4396e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePrivate(spec);
440b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case KEY_PUBLIC:
4416e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePublic(spec);
442b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case KEY_SECRET:
4436e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                return SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generateSecret(spec);
444b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            default:
445b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                throw new IOException("Key type " + keyType + " not recognised!");
446b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
447b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
448b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        catch (Exception e)
449b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
4508e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom
451b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new IOException("Exception creating key: " + e.toString());
452b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
453b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
454b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
455b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected Cipher makePBECipher(
456b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String  algorithm,
457b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     mode,
458b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        char[]  password,
459b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]  salt,
460b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     iterationCount)
461b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
462b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
463b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        try
464b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
465b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            PBEKeySpec          pbeSpec = new PBEKeySpec(password);
4666e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
467b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            PBEParameterSpec    defParams = new PBEParameterSpec(salt, iterationCount);
468b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
4696e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            Cipher cipher = Cipher.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
470b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
471b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
472b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
473b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return cipher;
474b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
475b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        catch (Exception e)
476b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
477b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new IOException("Error initialising store of key store: " + e);
478b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
479b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
480b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
481b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void setRandom(
482b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            SecureRandom    rand)
483b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
484b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        this.random = rand;
485b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
486b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
487b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public Enumeration engineAliases()
488b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
489b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return table.keys();
490b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
491b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
492b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public boolean engineContainsAlias(
493b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String  alias)
494b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
495b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return (table.get(alias) != null);
496b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
497b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
498b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void engineDeleteEntry(
499b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String  alias)
500b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws KeyStoreException
501b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
502b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Object  entry = table.get(alias);
503b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
504b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (entry == null)
505b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
5068e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom            // BEGIN android-removed
5078e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom            // Only throw if there is a problem removing, not if missing
5088e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom            // throw new KeyStoreException("no such entry as " + alias);
5098e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom            // END android-removed
5108e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom            // BEGIN android-added
5118e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom            return;
5128e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom            // END android-added
513b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
514b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
515b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        table.remove(alias);
516b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
517b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
518b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public Certificate engineGetCertificate(
519b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String alias)
520b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
521b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry  entry = (StoreEntry)table.get(alias);
522b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
523b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (entry != null)
524b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
525b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (entry.getType() == CERTIFICATE)
526b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
527b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                return (Certificate)entry.getObject();
528b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
529b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            else
530b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
531b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                Certificate[]   chain = entry.getCertificateChain();
532b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
533b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                if (chain != null)
534b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
535b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    return chain[0];
536b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
537b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
538b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
539b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
540b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return null;
541b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
542b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
543b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public String engineGetCertificateAlias(
544b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Certificate cert)
545b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
546b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Enumeration e = table.elements();
547b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        while (e.hasMoreElements())
548b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
549b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            StoreEntry  entry = (StoreEntry)e.nextElement();
550b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
551b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (entry.getObject() instanceof Certificate)
552b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
553b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                Certificate c = (Certificate)entry.getObject();
554b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
555b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                if (c.equals(cert))
556b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
557b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    return entry.getAlias();
558b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
559b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
560b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            else
561b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
562b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                Certificate[]   chain = entry.getCertificateChain();
563b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
564b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                if (chain != null && chain[0].equals(cert))
565b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
566b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    return entry.getAlias();
567b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
568b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
569b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
570b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
571b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return null;
572b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
573b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
574b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public Certificate[] engineGetCertificateChain(
575b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String alias)
576b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
577b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry  entry = (StoreEntry)table.get(alias);
578b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
579b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (entry != null)
580b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
581b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return entry.getCertificateChain();
582b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
583b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
584b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return null;
585b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
586b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
587b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public Date engineGetCreationDate(String alias)
588b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
589b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry  entry = (StoreEntry)table.get(alias);
590b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
591b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (entry != null)
592b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
593b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return entry.getDate();
594b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
595b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
596b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return null;
597b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
598b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
599b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public Key engineGetKey(
600b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String alias,
601b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        char[] password)
602b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws NoSuchAlgorithmException, UnrecoverableKeyException
603b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
604b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry  entry = (StoreEntry)table.get(alias);
605b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
606b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (entry == null || entry.getType() == CERTIFICATE)
607b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
608b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return null;
609b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
610b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
611b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return (Key)entry.getObject(password);
612b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
613b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
614b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public boolean engineIsCertificateEntry(
615b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String alias)
616b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
617b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry  entry = (StoreEntry)table.get(alias);
618b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
619b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (entry != null && entry.getType() == CERTIFICATE)
620b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
621b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return true;
622b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
623b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
624b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return false;
625b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
626b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
627b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public boolean engineIsKeyEntry(
628b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String alias)
629b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
630b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry  entry = (StoreEntry)table.get(alias);
631b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
632b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (entry != null && entry.getType() != CERTIFICATE)
633b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
634b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return true;
635b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
636b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
637b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return false;
638b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
639b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
640b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void engineSetCertificateEntry(
641b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String      alias,
642b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Certificate cert)
643b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws KeyStoreException
644b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
645b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        StoreEntry  entry = (StoreEntry)table.get(alias);
646b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
647b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (entry != null && entry.getType() != CERTIFICATE)
648b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
649c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new KeyStoreException("key store already has a key entry with alias " + alias);
650b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
651b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
652b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        table.put(alias, new StoreEntry(alias, cert));
653b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
654b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
655b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void engineSetKeyEntry(
656b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String alias,
657b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] key,
658b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Certificate[] chain)
659b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws KeyStoreException
660b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
661b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        table.put(alias, new StoreEntry(alias, key, chain));
662b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
663b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
664b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void engineSetKeyEntry(
665b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String          alias,
666b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Key             key,
667b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        char[]          password,
668b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Certificate[]   chain)
669b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws KeyStoreException
670b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
671b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if ((key instanceof PrivateKey) && (chain == null))
672b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
673b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new KeyStoreException("no certificate chain for private key");
674b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
675b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
676b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        try
677b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
678b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            table.put(alias, new StoreEntry(alias, key, password, chain));
679b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
680b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        catch (Exception e)
681b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
682b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throw new KeyStoreException(e.toString());
683b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
684b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
685b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
686b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int engineSize()
687b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
688b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return table.size();
689b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
690b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
691b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected void loadStore(
692b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        InputStream in)
693b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
694b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
695b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        DataInputStream     dIn = new DataInputStream(in);
696b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int                 type = dIn.read();
697b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
698b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        while (type > NULL)
699b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
700b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            String          alias = dIn.readUTF();
701b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Date            date = new Date(dIn.readLong());
702b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            int             chainLength = dIn.readInt();
703b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Certificate[]   chain = null;
704b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
705b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (chainLength != 0)
706b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
707b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                chain = new Certificate[chainLength];
708b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
709b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                for (int i = 0; i != chainLength; i++)
710b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
711b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    chain[i] = decodeCertificate(dIn);
712b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
713b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
714b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
715b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            switch (type)
716b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
717b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case CERTIFICATE:
718b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    Certificate     cert = decodeCertificate(dIn);
719b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
720b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    table.put(alias, new StoreEntry(alias, date, CERTIFICATE, cert));
721b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    break;
722b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case KEY:
723b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    Key     key = decodeKey(dIn);
724b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    table.put(alias, new StoreEntry(alias, date, KEY, key, chain));
725b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    break;
726b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case SECRET:
727b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case SEALED:
728b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    byte[]      b = new byte[dIn.readInt()];
729b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
730b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    dIn.readFully(b);
731b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    table.put(alias, new StoreEntry(alias, date, type, b, chain));
732b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    break;
733b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            default:
734b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    throw new RuntimeException("Unknown object type in store.");
735b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
736b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
737b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            type = dIn.read();
738b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
739b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
740b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
741b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected void saveStore(
742b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        OutputStream    out)
743b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
744b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
745b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Enumeration         e = table.elements();
746b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        DataOutputStream    dOut = new DataOutputStream(out);
747b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
748b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        while (e.hasMoreElements())
749b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
750b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            StoreEntry  entry = (StoreEntry)e.nextElement();
751b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
752b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.write(entry.getType());
753b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeUTF(entry.getAlias());
754b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeLong(entry.getDate().getTime());
755b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
756b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Certificate[]   chain = entry.getCertificateChain();
757b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (chain == null)
758b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
759b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                dOut.writeInt(0);
760b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
761b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            else
762b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
763b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                dOut.writeInt(chain.length);
764b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                for (int i = 0; i != chain.length; i++)
765b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
766b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    encodeCertificate(chain[i], dOut);
767b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
768b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
769b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
770b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            switch (entry.getType())
771b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
772b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case CERTIFICATE:
773b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    encodeCertificate((Certificate)entry.getObject(), dOut);
774b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    break;
775b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case KEY:
776b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    encodeKey((Key)entry.getObject(), dOut);
777b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    break;
778b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case SEALED:
779b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            case SECRET:
780b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    byte[]  b = (byte[])entry.getObject();
781b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
782b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    dOut.writeInt(b.length);
783b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    dOut.write(b);
784b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    break;
785b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            default:
786b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    throw new RuntimeException("Unknown object type in store.");
787b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
788b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
789b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
790b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.write(NULL);
791b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
792b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
793b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void engineLoad(
794b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        InputStream stream,
795b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        char[]      password)
796b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
797b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
798b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        table.clear();
799b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
800b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (stream == null)     // just initialising
801b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
802b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return;
803b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
804b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
805b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        DataInputStream     dIn = new DataInputStream(stream);
806b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int                 version = dIn.readInt();
807b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
808b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        if (version != STORE_VERSION)
809b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
810b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (version != 0)
811b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
812b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                throw new IOException("Wrong version of key store.");
813b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
814b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
815b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
816b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]      salt = new byte[dIn.readInt()];
817b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
818b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dIn.readFully(salt);
819b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
820b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int         iterationCount = dIn.readInt();
821b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
822c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        //
823c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // we only do an integrity check if the password is provided.
824c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        //
825c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // BEGIN android-changed
82610261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstrom        HMac hMac = new HMac(new OpenSSLDigest.SHA1());
827c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // END android-changed
828c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (password != null && password.length != 0)
829c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
830c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
831b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
832c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // BEGIN android-changed
83310261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstrom            PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA1());
834c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // END android-changed
835c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            pbeGen.init(passKey, salt, iterationCount);
836c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            CipherParameters macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize());
837c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            Arrays.fill(passKey, (byte)0);
838b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
839c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            hMac.init(macParams);
840c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            MacInputStream mIn = new MacInputStream(dIn, hMac);
841b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
842c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            loadStore(mIn);
843b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
844c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // Finalise our mac calculation
845c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            byte[] mac = new byte[hMac.getMacSize()];
846c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            hMac.doFinal(mac, 0);
847b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
848c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // TODO Should this actually be reading the remainder of the stream?
849c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // Read the original mac from the stream
850c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            byte[] oldMac = new byte[hMac.getMacSize()];
851c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            dIn.readFully(oldMac);
852b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
853c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (!Arrays.constantTimeAreEqual(mac, oldMac))
854c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
855c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                table.clear();
856c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new IOException("KeyStore integrity check failed.");
857c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
858b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
859c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        else
860b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
861c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            loadStore(dIn);
862c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
863c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // TODO Should this actually be reading the remainder of the stream?
864c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // Parse the original mac from the stream too
865c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            byte[] oldMac = new byte[hMac.getMacSize()];
866c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            dIn.readFully(oldMac);
867b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
868b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
869b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
870b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
871b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public void engineStore(OutputStream stream, char[] password)
872b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
873b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
874b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        DataOutputStream    dOut = new DataOutputStream(stream);
875b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]              salt = new byte[STORE_SALT_SIZE];
876b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int                 iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
877b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
878b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        random.nextBytes(salt);
879b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
880b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.writeInt(STORE_VERSION);
881b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.writeInt(salt.length);
882b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.write(salt);
883b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.writeInt(iterationCount);
884b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
885c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // BEGIN android-changed
88610261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstrom        HMac                    hMac = new HMac(new OpenSSLDigest.SHA1());
887b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        MacOutputStream         mOut = new MacOutputStream(dOut, hMac);
88810261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstrom        PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(new OpenSSLDigest.SHA1());
889c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // END android-changed
890b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]                  passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
891b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
892b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        pbeGen.init(passKey, salt, iterationCount);
893b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
894b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize()));
895b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
896b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int i = 0; i != passKey.length; i++)
897b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
898b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            passKey[i] = 0;
899b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
900b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
901b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        saveStore(mOut);
902b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
903b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]  mac = new byte[hMac.getMacSize()];
904b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
905b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        hMac.doFinal(mac, 0);
906b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
907b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.write(mac);
908b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
909b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dOut.close();
910b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
911b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
912b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
913b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * the BouncyCastle store. This wont work with the key tool as the
914b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * store is stored encrypteed on disk, so the password is mandatory,
915b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * however if you hard drive is in a bad part of town and you absolutely,
916b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * positively, don't want nobody peeking at your things, this is the
917b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * one to use, no problem! After all in a Bouncy Castle nothing can
918b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * touch you.
919b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
920b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Also referred to by the alias UBER.
921b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
922b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public static class BouncyCastleStore
923b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        extends JDKKeyStore
924b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
925b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        public void engineLoad(
926b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            InputStream stream,
927b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            char[]      password)
928b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throws IOException
929b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
930b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            table.clear();
931b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
932b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (stream == null)     // just initialising
933b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
934b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                return;
935b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
936b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
937b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            DataInputStream     dIn = new DataInputStream(stream);
938b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            int                 version = dIn.readInt();
939b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
940b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (version != STORE_VERSION)
941b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
942b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                if (version != 0)
943b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
944b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    throw new IOException("Wrong version of key store.");
945b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
946b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
947b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
948b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            byte[]      salt = new byte[dIn.readInt()];
949b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
950b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (salt.length != STORE_SALT_SIZE)
951b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
952b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                throw new IOException("Key store corrupted.");
953b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
954b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
955b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dIn.readFully(salt);
956b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
957b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            int         iterationCount = dIn.readInt();
958b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
959b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if ((iterationCount < 0) || (iterationCount > 4 *  MIN_ITERATIONS))
960b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
961b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                throw new IOException("Key store corrupted.");
962b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
963b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
964c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            String cipherAlg;
965b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (version == 0)
966b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
967c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                cipherAlg = "Old" + STORE_CIPHER;
968b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
969b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            else
970b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
971c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                cipherAlg = STORE_CIPHER;
972b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
973b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
974c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            Cipher cipher = this.makePBECipher(cipherAlg, Cipher.DECRYPT_MODE, password, salt, iterationCount);
975c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            CipherInputStream cIn = new CipherInputStream(dIn, cipher);
976c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
977c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // BEGIN android-changed
97810261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstrom            Digest dig = new OpenSSLDigest.SHA1();
979c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // END android-changed
980c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            DigestInputStream  dgIn = new DigestInputStream(cIn, dig);
981b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
982c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            this.loadStore(dgIn);
983c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
984c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // Finalise our digest calculation
985c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            byte[] hash = new byte[dig.getDigestSize()];
986b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dig.doFinal(hash, 0);
987c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
988c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // TODO Should this actually be reading the remainder of the stream?
989c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // Read the original digest from the stream
990c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            byte[] oldHash = new byte[dig.getDigestSize()];
991c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            Streams.readFully(cIn, oldHash);
992c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
993c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (!Arrays.constantTimeAreEqual(hash, oldHash))
994b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
995b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                table.clear();
996b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                throw new IOException("KeyStore integrity check failed.");
997b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
998b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
999b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1000b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1001b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        public void engineStore(OutputStream stream, char[] password)
1002b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            throws IOException
1003b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
1004b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Cipher              cipher;
1005b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            DataOutputStream    dOut = new DataOutputStream(stream);
1006b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            byte[]              salt = new byte[STORE_SALT_SIZE];
1007b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            int                 iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
1008b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1009b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            random.nextBytes(salt);
1010b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1011b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeInt(STORE_VERSION);
1012b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeInt(salt.length);
1013b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.write(salt);
1014b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dOut.writeInt(iterationCount);
1015b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1016b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            cipher = this.makePBECipher(STORE_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
1017b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1018b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            CipherOutputStream  cOut = new CipherOutputStream(dOut, cipher);
1019c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // BEGIN android-changed
102010261d9785b26fbcfe273b7b8119907fda09a999Brian Carlstrom            DigestOutputStream  dgOut = new DigestOutputStream(cOut, new OpenSSLDigest.SHA1());
1021c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // END android-changed
1022b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            this.saveStore(dgOut);
1023b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1024b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            Digest  dig = dgOut.getDigest();
1025b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            byte[]  hash = new byte[dig.getDigestSize()];
1026b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1027b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            dig.doFinal(hash, 0);
1028b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1029b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            cOut.write(hash);
1030b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1031b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            cOut.close();
1032b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
1033b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
1034b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
1035