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