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; 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; 42a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstromimport org.bouncycastle.crypto.digests.SHA1Digest; 43b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; 44b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.io.DigestInputStream; 45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.io.DigestOutputStream; 46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.io.MacInputStream; 47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.io.MacOutputStream; 48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.macs.HMac; 49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.jce.interfaces.BCKeyStore; 50a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstromimport org.bouncycastle.jce.provider.BouncyCastleProvider; 51c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.util.Arrays; 52c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.util.io.Streams; 534c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstromimport org.bouncycastle.util.io.TeeOutputStream; 54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 55a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrompublic class BcKeyStoreSpi 56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam extends KeyStoreSpi 57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam implements BCKeyStore 58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{ 594c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom private static final int STORE_VERSION = 2; 60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private static final int STORE_SALT_SIZE = 20; 62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private static final String STORE_CIPHER = "PBEWithSHAAndTwofish-CBC"; 63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private static final int KEY_SALT_SIZE = 20; 65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private static final int MIN_ITERATIONS = 1024; 66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam private static final String KEY_CIPHER = "PBEWithSHAAnd3-KeyTripleDES-CBC"; 68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // generic object types 71b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam static final int NULL = 0; 73b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam static final int CERTIFICATE = 1; 74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam static final int KEY = 2; 75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam static final int SECRET = 3; 76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam static final int SEALED = 4; 77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // key types 80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam // 81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam static final int KEY_PRIVATE = 0; 82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam static final int KEY_PUBLIC = 1; 83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam static final int KEY_SECRET = 2; 84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam protected Hashtable table = new Hashtable(); 86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam protected SecureRandom random = new SecureRandom(); 88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 89a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom protected int version; 90a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom 91a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom public BcKeyStoreSpi(int version) 92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 93a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom this.version = version; 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 { 450b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new IOException("Exception creating key: " + e.toString()); 451b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 452b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 453b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 454b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam protected Cipher makePBECipher( 455b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String algorithm, 456b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int mode, 457b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam char[] password, 458b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] salt, 459b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int iterationCount) 460b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws IOException 461b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 462b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam try 463b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 464b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam PBEKeySpec pbeSpec = new PBEKeySpec(password); 4656e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME); 466b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); 467b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 4686e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom Cipher cipher = Cipher.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME); 469b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 470b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams); 471b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 472b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return cipher; 473b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 474b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam catch (Exception e) 475b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 476b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new IOException("Error initialising store of key store: " + e); 477b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 478b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 479b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 480b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void setRandom( 481b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam SecureRandom rand) 482b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 483b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam this.random = rand; 484b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 485b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 486b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public Enumeration engineAliases() 487b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 488b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return table.keys(); 489b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 490b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 491b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public boolean engineContainsAlias( 492b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias) 493b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 494b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return (table.get(alias) != null); 495b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 496b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 497b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void engineDeleteEntry( 498b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias) 499b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws KeyStoreException 500b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 501b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Object entry = table.get(alias); 502b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 503b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry == null) 504b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 5058e551503a8d09fb57fd4efe9a2aa0392e7ba56e9Brian Carlstrom return; 506b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 507b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 508b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.remove(alias); 509b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 510b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 511b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public Certificate engineGetCertificate( 512b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias) 513b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 514b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)table.get(alias); 515b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 516b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry != null) 517b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 518b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry.getType() == CERTIFICATE) 519b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 520b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return (Certificate)entry.getObject(); 521b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 522b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 523b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 524b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate[] chain = entry.getCertificateChain(); 525b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 526b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (chain != null) 527b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 528b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return chain[0]; 529b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 530b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 531b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 532b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 533b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return null; 534b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 535b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 536b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public String engineGetCertificateAlias( 537b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate cert) 538b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 539b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Enumeration e = table.elements(); 540b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam while (e.hasMoreElements()) 541b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 542b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)e.nextElement(); 543b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 544b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry.getObject() instanceof Certificate) 545b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 546b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate c = (Certificate)entry.getObject(); 547b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 548b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (c.equals(cert)) 549b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 550b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return entry.getAlias(); 551b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 552b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 553b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 554b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 555b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate[] chain = entry.getCertificateChain(); 556b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 557b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (chain != null && chain[0].equals(cert)) 558b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 559b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return entry.getAlias(); 560b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 561b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 562b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 563b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 564b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return null; 565b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 566b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 567b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public Certificate[] engineGetCertificateChain( 568b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias) 569b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 570b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)table.get(alias); 571b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 572b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry != null) 573b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 574b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return entry.getCertificateChain(); 575b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 576b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 577b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return null; 578b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 579b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 580b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public Date engineGetCreationDate(String alias) 581b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 582b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)table.get(alias); 583b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 584b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry != null) 585b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 586b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return entry.getDate(); 587b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 588b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 589b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return null; 590b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 591b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 592b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public Key engineGetKey( 593b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias, 594b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam char[] password) 595b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws NoSuchAlgorithmException, UnrecoverableKeyException 596b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 597b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)table.get(alias); 598b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 599b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry == null || entry.getType() == CERTIFICATE) 600b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 601b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return null; 602b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 603b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 604b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return (Key)entry.getObject(password); 605b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 606b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 607b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public boolean engineIsCertificateEntry( 608b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias) 609b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 610b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)table.get(alias); 611b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 612b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry != null && entry.getType() == CERTIFICATE) 613b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 614b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return true; 615b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 616b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 617b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return false; 618b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 619b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 620b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public boolean engineIsKeyEntry( 621b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias) 622b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 623b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)table.get(alias); 624b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 625b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry != null && entry.getType() != CERTIFICATE) 626b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 627b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return true; 628b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 629b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 630b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return false; 631b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 632b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 633b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void engineSetCertificateEntry( 634b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias, 635b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate cert) 636b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws KeyStoreException 637b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 638b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)table.get(alias); 639b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 640b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (entry != null && entry.getType() != CERTIFICATE) 641b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 642c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom throw new KeyStoreException("key store already has a key entry with alias " + alias); 643b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 644b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 645b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.put(alias, new StoreEntry(alias, cert)); 646b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 647b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 648b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void engineSetKeyEntry( 649b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias, 650b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] key, 651b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate[] chain) 652b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws KeyStoreException 653b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 654b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.put(alias, new StoreEntry(alias, key, chain)); 655b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 656b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 657b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void engineSetKeyEntry( 658b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias, 659b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Key key, 660b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam char[] password, 661b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate[] chain) 662b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws KeyStoreException 663b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 664b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if ((key instanceof PrivateKey) && (chain == null)) 665b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 666b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new KeyStoreException("no certificate chain for private key"); 667b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 668b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 669b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam try 670b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 671b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.put(alias, new StoreEntry(alias, key, password, chain)); 672b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 673b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam catch (Exception e) 674b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 675b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new KeyStoreException(e.toString()); 676b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 677b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 678b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 679b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public int engineSize() 680b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 681b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return table.size(); 682b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 683b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 684b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam protected void loadStore( 685b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam InputStream in) 686b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws IOException 687b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 688b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam DataInputStream dIn = new DataInputStream(in); 689b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int type = dIn.read(); 690b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 691b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam while (type > NULL) 692b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 693b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam String alias = dIn.readUTF(); 694b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Date date = new Date(dIn.readLong()); 695b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int chainLength = dIn.readInt(); 696b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate[] chain = null; 697b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 698b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (chainLength != 0) 699b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 700b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam chain = new Certificate[chainLength]; 701b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 702b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam for (int i = 0; i != chainLength; i++) 703b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 704b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam chain[i] = decodeCertificate(dIn); 705b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 706b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 707b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 708b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam switch (type) 709b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 710b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam case CERTIFICATE: 711b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate cert = decodeCertificate(dIn); 712b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 713b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.put(alias, new StoreEntry(alias, date, CERTIFICATE, cert)); 714b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam break; 715b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam case KEY: 716b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Key key = decodeKey(dIn); 717b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.put(alias, new StoreEntry(alias, date, KEY, key, chain)); 718b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam break; 719b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam case SECRET: 720b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam case SEALED: 721b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] b = new byte[dIn.readInt()]; 722b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 723b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dIn.readFully(b); 724b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.put(alias, new StoreEntry(alias, date, type, b, chain)); 725b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam break; 726b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam default: 727b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new RuntimeException("Unknown object type in store."); 728b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 729b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 730b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam type = dIn.read(); 731b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 732b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 733b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 734b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam protected void saveStore( 735b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam OutputStream out) 736b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws IOException 737b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 738b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Enumeration e = table.elements(); 739b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam DataOutputStream dOut = new DataOutputStream(out); 740b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 741b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam while (e.hasMoreElements()) 742b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 743b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam StoreEntry entry = (StoreEntry)e.nextElement(); 744b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 745b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.write(entry.getType()); 746b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeUTF(entry.getAlias()); 747b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeLong(entry.getDate().getTime()); 748b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 749b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Certificate[] chain = entry.getCertificateChain(); 750b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (chain == null) 751b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 752b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeInt(0); 753b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 754b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 755b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 756b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeInt(chain.length); 757b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam for (int i = 0; i != chain.length; i++) 758b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 759b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam encodeCertificate(chain[i], dOut); 760b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 761b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 762b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 763b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam switch (entry.getType()) 764b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 765b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam case CERTIFICATE: 766b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam encodeCertificate((Certificate)entry.getObject(), dOut); 767b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam break; 768b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam case KEY: 769b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam encodeKey((Key)entry.getObject(), dOut); 770b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam break; 771b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam case SEALED: 772b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam case SECRET: 773b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] b = (byte[])entry.getObject(); 774b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 775b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeInt(b.length); 776b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.write(b); 777b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam break; 778b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam default: 779b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new RuntimeException("Unknown object type in store."); 780b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 781b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 782b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 783b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.write(NULL); 784b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 785b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 786b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void engineLoad( 787b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam InputStream stream, 788b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam char[] password) 789b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws IOException 790b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 791b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.clear(); 792b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 793b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (stream == null) // just initialising 794b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 795b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return; 796b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 797b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 798b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam DataInputStream dIn = new DataInputStream(stream); 799b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int version = dIn.readInt(); 800b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 801b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (version != STORE_VERSION) 802b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 8034c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom if (version != 0 && version != 1) 804b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 805b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new IOException("Wrong version of key store."); 806b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 807b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 808b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 8094c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom int saltLength = dIn.readInt(); 8104c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom if (saltLength <= 0) 8114c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom { 8124c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom throw new IOException("Invalid salt detected"); 8134c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom } 8144c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom 8154c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom byte[] salt = new byte[saltLength]; 816b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 817b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dIn.readFully(salt); 818b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 819b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int iterationCount = dIn.readInt(); 820b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 821c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // 822c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // we only do an integrity check if the password is provided. 823c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // 824a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom HMac hMac = new HMac(new SHA1Digest()); 825c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom if (password != null && password.length != 0) 826c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom { 827c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password); 828b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 829a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new SHA1Digest()); 830c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom pbeGen.init(passKey, salt, iterationCount); 8314c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom 8324c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom CipherParameters macParams; 8334c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom 8344c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom if (version != 2) 8354c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom { 8364c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize()); 8374c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom } 8384c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom else 8394c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom { 8404c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8); 8414c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom } 8424c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom 843c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom Arrays.fill(passKey, (byte)0); 844b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 845c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom hMac.init(macParams); 846c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom MacInputStream mIn = new MacInputStream(dIn, hMac); 847b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 848c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom loadStore(mIn); 849b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 850c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // Finalise our mac calculation 851c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom byte[] mac = new byte[hMac.getMacSize()]; 852c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom hMac.doFinal(mac, 0); 853b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 854c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // TODO Should this actually be reading the remainder of the stream? 855c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // Read the original mac from the stream 856c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom byte[] oldMac = new byte[hMac.getMacSize()]; 857c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom dIn.readFully(oldMac); 858b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 859c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom if (!Arrays.constantTimeAreEqual(mac, oldMac)) 860c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom { 861c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom table.clear(); 862c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom throw new IOException("KeyStore integrity check failed."); 863c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom } 864b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 865c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom else 866b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 867c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom loadStore(dIn); 868c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 869c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // TODO Should this actually be reading the remainder of the stream? 870c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // Parse the original mac from the stream too 871c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom byte[] oldMac = new byte[hMac.getMacSize()]; 872c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom dIn.readFully(oldMac); 873b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 874b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 875b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 876b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 877b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void engineStore(OutputStream stream, char[] password) 878b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws IOException 879b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 880b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam DataOutputStream dOut = new DataOutputStream(stream); 881b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] salt = new byte[STORE_SALT_SIZE]; 882b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff); 883b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 884b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam random.nextBytes(salt); 885b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 886a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom dOut.writeInt(version); 887b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeInt(salt.length); 888b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.write(salt); 889b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeInt(iterationCount); 890b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 891a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom HMac hMac = new HMac(new SHA1Digest()); 8924c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom MacOutputStream mOut = new MacOutputStream(hMac); 893a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new SHA1Digest()); 894b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password); 895b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 896b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam pbeGen.init(passKey, salt, iterationCount); 897b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 898a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom if (version < 2) 899a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom { 900a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize())); 901a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom } 902a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom else 903a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom { 904a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8)); 905a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom } 906b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 907b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam for (int i = 0; i != passKey.length; i++) 908b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 909b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam passKey[i] = 0; 910b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 911b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 9124c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom saveStore(new TeeOutputStream(dOut, mOut)); 913b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 914b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] mac = new byte[hMac.getMacSize()]; 915b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 916b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam hMac.doFinal(mac, 0); 917b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 918b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.write(mac); 919b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 920b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.close(); 921b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 922b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 923b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 924b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * the BouncyCastle store. This wont work with the key tool as the 9254c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom * store is stored encrypted on disk, so the password is mandatory, 926b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * however if you hard drive is in a bad part of town and you absolutely, 927b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * positively, don't want nobody peeking at your things, this is the 928b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * one to use, no problem! After all in a Bouncy Castle nothing can 929b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * touch you. 930b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 931b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * Also referred to by the alias UBER. 932b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 933b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public static class BouncyCastleStore 934a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom extends BcKeyStoreSpi 935b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 936a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom public BouncyCastleStore() 937a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom { 938a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom super(1); 939a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom } 940a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom 941b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void engineLoad( 942b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam InputStream stream, 943b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam char[] password) 944b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws IOException 945b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 946b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.clear(); 947b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 948b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (stream == null) // just initialising 949b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 950b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return; 951b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 952b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 953b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam DataInputStream dIn = new DataInputStream(stream); 954b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int version = dIn.readInt(); 955b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 956b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (version != STORE_VERSION) 957b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 9584c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom if (version != 0 && version != 1) 959b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 960b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new IOException("Wrong version of key store."); 961b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 962b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 963b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 964b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] salt = new byte[dIn.readInt()]; 965b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 966b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (salt.length != STORE_SALT_SIZE) 967b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 968b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new IOException("Key store corrupted."); 969b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 970b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 971b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dIn.readFully(salt); 972b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 973b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int iterationCount = dIn.readInt(); 974b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 975b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if ((iterationCount < 0) || (iterationCount > 4 * MIN_ITERATIONS)) 976b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 977b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new IOException("Key store corrupted."); 978b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 979b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 980c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom String cipherAlg; 981b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (version == 0) 982b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 983c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom cipherAlg = "Old" + STORE_CIPHER; 984b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 985b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 986b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 987c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom cipherAlg = STORE_CIPHER; 988b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 989b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 990c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom Cipher cipher = this.makePBECipher(cipherAlg, Cipher.DECRYPT_MODE, password, salt, iterationCount); 991c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom CipherInputStream cIn = new CipherInputStream(dIn, cipher); 992c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 993a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom Digest dig = new SHA1Digest(); 994c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom DigestInputStream dgIn = new DigestInputStream(cIn, dig); 995b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 996c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom this.loadStore(dgIn); 997c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 998c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // Finalise our digest calculation 999c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom byte[] hash = new byte[dig.getDigestSize()]; 1000b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dig.doFinal(hash, 0); 1001c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 1002c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // TODO Should this actually be reading the remainder of the stream? 1003c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // Read the original digest from the stream 1004c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom byte[] oldHash = new byte[dig.getDigestSize()]; 1005c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom Streams.readFully(cIn, oldHash); 1006c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 1007c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom if (!Arrays.constantTimeAreEqual(hash, oldHash)) 1008b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 1009b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam table.clear(); 1010b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throw new IOException("KeyStore integrity check failed."); 1011b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 1012b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 10134c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom 1014b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void engineStore(OutputStream stream, char[] password) 1015b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam throws IOException 1016b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 1017b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam Cipher cipher; 1018b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam DataOutputStream dOut = new DataOutputStream(stream); 1019b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] salt = new byte[STORE_SALT_SIZE]; 1020b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff); 1021b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 1022b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam random.nextBytes(salt); 1023b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 1024a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom dOut.writeInt(version); 1025b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeInt(salt.length); 1026b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.write(salt); 1027b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam dOut.writeInt(iterationCount); 1028b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 1029b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cipher = this.makePBECipher(STORE_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount); 1030b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 1031b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam CipherOutputStream cOut = new CipherOutputStream(dOut, cipher); 1032a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom DigestOutputStream dgOut = new DigestOutputStream(new SHA1Digest()); 1033b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 10344c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom this.saveStore(new TeeOutputStream(cOut, dgOut)); 1035b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 10364c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom byte[] dig = dgOut.getDigest(); 10374c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom 10384c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom cOut.write(dig); 1039b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 1040b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam cOut.close(); 1041b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 10424c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom } 1043a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom 1044a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom public static class Std 1045a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom extends BcKeyStoreSpi 1046a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom { 1047a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom public Std() 1048a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom { 1049a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom super(STORE_VERSION); 1050a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom } 1051a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom } 1052a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom 1053a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom public static class Version1 1054a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom extends BcKeyStoreSpi 1055a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom { 1056a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom public Version1() 1057a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom { 1058a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom super(1); 1059a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom } 1060a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom } 1061b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam} 1062