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