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