aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java')
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java1061
1 files changed, 0 insertions, 1061 deletions
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
deleted file mode 100644
index a06ae3917..000000000
--- a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
+++ /dev/null
@@ -1,1061 +0,0 @@
-package org.spongycastle.jcajce.provider.keystore.bc;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.Key;
-import java.security.KeyFactory;
-import java.security.KeyStoreException;
-import java.security.KeyStoreSpi;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.spec.KeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.Hashtable;
-
-import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
-import javax.crypto.CipherOutputStream;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.PBEParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.spongycastle.crypto.CipherParameters;
-import org.spongycastle.crypto.Digest;
-import org.spongycastle.crypto.PBEParametersGenerator;
-import org.spongycastle.crypto.digests.SHA1Digest;
-import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
-import org.spongycastle.crypto.io.DigestInputStream;
-import org.spongycastle.crypto.io.DigestOutputStream;
-import org.spongycastle.crypto.io.MacInputStream;
-import org.spongycastle.crypto.io.MacOutputStream;
-import org.spongycastle.crypto.macs.HMac;
-import org.spongycastle.jce.interfaces.BCKeyStore;
-import org.spongycastle.jce.provider.BouncyCastleProvider;
-import org.spongycastle.util.Arrays;
-import org.spongycastle.util.io.Streams;
-import org.spongycastle.util.io.TeeOutputStream;
-
-public class BcKeyStoreSpi
- extends KeyStoreSpi
- implements BCKeyStore
-{
- private static final int STORE_VERSION = 2;
-
- private static final int STORE_SALT_SIZE = 20;
- private static final String STORE_CIPHER = "PBEWithSHAAndTwofish-CBC";
-
- private static final int KEY_SALT_SIZE = 20;
- private static final int MIN_ITERATIONS = 1024;
-
- private static final String KEY_CIPHER = "PBEWithSHAAnd3-KeyTripleDES-CBC";
-
- //
- // generic object types
- //
- static final int NULL = 0;
- static final int CERTIFICATE = 1;
- static final int KEY = 2;
- static final int SECRET = 3;
- static final int SEALED = 4;
-
- //
- // key types
- //
- static final int KEY_PRIVATE = 0;
- static final int KEY_PUBLIC = 1;
- static final int KEY_SECRET = 2;
-
- protected Hashtable table = new Hashtable();
-
- protected SecureRandom random = new SecureRandom();
-
- protected int version;
-
- public BcKeyStoreSpi(int version)
- {
- this.version = version;
- }
-
- private class StoreEntry
- {
- int type;
- String alias;
- Object obj;
- Certificate[] certChain;
- Date date = new Date();
-
- StoreEntry(
- String alias,
- Certificate obj)
- {
- this.type = CERTIFICATE;
- this.alias = alias;
- this.obj = obj;
- this.certChain = null;
- }
-
- StoreEntry(
- String alias,
- byte[] obj,
- Certificate[] certChain)
- {
- this.type = SECRET;
- this.alias = alias;
- this.obj = obj;
- this.certChain = certChain;
- }
-
- StoreEntry(
- String alias,
- Key key,
- char[] password,
- Certificate[] certChain)
- throws Exception
- {
- this.type = SEALED;
- this.alias = alias;
- this.certChain = certChain;
-
- byte[] salt = new byte[KEY_SALT_SIZE];
-
- random.setSeed(System.currentTimeMillis());
- random.nextBytes(salt);
-
- int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
-
-
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- DataOutputStream dOut = new DataOutputStream(bOut);
-
- dOut.writeInt(salt.length);
- dOut.write(salt);
- dOut.writeInt(iterationCount);
-
- Cipher cipher = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
- CipherOutputStream cOut = new CipherOutputStream(dOut, cipher);
-
- dOut = new DataOutputStream(cOut);
-
- encodeKey(key, dOut);
-
- dOut.close();
-
- obj = bOut.toByteArray();
- }
-
- StoreEntry(
- String alias,
- Date date,
- int type,
- Object obj)
- {
- this.alias = alias;
- this.date = date;
- this.type = type;
- this.obj = obj;
- }
-
- StoreEntry(
- String alias,
- Date date,
- int type,
- Object obj,
- Certificate[] certChain)
- {
- this.alias = alias;
- this.date = date;
- this.type = type;
- this.obj = obj;
- this.certChain = certChain;
- }
-
- int getType()
- {
- return type;
- }
-
- String getAlias()
- {
- return alias;
- }
-
- Object getObject()
- {
- return obj;
- }
-
- Object getObject(
- char[] password)
- throws NoSuchAlgorithmException, UnrecoverableKeyException
- {
- if (password == null || password.length == 0)
- {
- if (obj instanceof Key)
- {
- return obj;
- }
- }
-
- if (type == SEALED)
- {
- ByteArrayInputStream bIn = new ByteArrayInputStream((byte[])obj);
- DataInputStream dIn = new DataInputStream(bIn);
-
- try
- {
- byte[] salt = new byte[dIn.readInt()];
-
- dIn.readFully(salt);
-
- int iterationCount = dIn.readInt();
-
- Cipher cipher = makePBECipher(KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
-
- CipherInputStream cIn = new CipherInputStream(dIn, cipher);
-
- try
- {
- return decodeKey(new DataInputStream(cIn));
- }
- catch (Exception x)
- {
- bIn = new ByteArrayInputStream((byte[])obj);
- dIn = new DataInputStream(bIn);
-
- salt = new byte[dIn.readInt()];
-
- dIn.readFully(salt);
-
- iterationCount = dIn.readInt();
-
- cipher = makePBECipher("Broken" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
-
- cIn = new CipherInputStream(dIn, cipher);
-
- Key k = null;
-
- try
- {
- k = decodeKey(new DataInputStream(cIn));
- }
- catch (Exception y)
- {
- bIn = new ByteArrayInputStream((byte[])obj);
- dIn = new DataInputStream(bIn);
-
- salt = new byte[dIn.readInt()];
-
- dIn.readFully(salt);
-
- iterationCount = dIn.readInt();
-
- cipher = makePBECipher("Old" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
-
- cIn = new CipherInputStream(dIn, cipher);
-
- k = decodeKey(new DataInputStream(cIn));
- }
-
- //
- // reencrypt key with correct cipher.
- //
- if (k != null)
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- DataOutputStream dOut = new DataOutputStream(bOut);
-
- dOut.writeInt(salt.length);
- dOut.write(salt);
- dOut.writeInt(iterationCount);
-
- Cipher out = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
- CipherOutputStream cOut = new CipherOutputStream(dOut, out);
-
- dOut = new DataOutputStream(cOut);
-
- encodeKey(k, dOut);
-
- dOut.close();
-
- obj = bOut.toByteArray();
-
- return k;
- }
- else
- {
- throw new UnrecoverableKeyException("no match");
- }
- }
- }
- catch (Exception e)
- {
- throw new UnrecoverableKeyException("no match");
- }
- }
- else
- {
- throw new RuntimeException("forget something!");
- // TODO
- // if we get to here key was saved as byte data, which
- // according to the docs means it must be a private key
- // in EncryptedPrivateKeyInfo (PKCS8 format), later...
- //
- }
- }
-
- Certificate[] getCertificateChain()
- {
- return certChain;
- }
-
- Date getDate()
- {
- return date;
- }
- }
-
- private void encodeCertificate(
- Certificate cert,
- DataOutputStream dOut)
- throws IOException
- {
- try
- {
- byte[] cEnc = cert.getEncoded();
-
- dOut.writeUTF(cert.getType());
- dOut.writeInt(cEnc.length);
- dOut.write(cEnc);
- }
- catch (CertificateEncodingException ex)
- {
- throw new IOException(ex.toString());
- }
- }
-
- private Certificate decodeCertificate(
- DataInputStream dIn)
- throws IOException
- {
- String type = dIn.readUTF();
- byte[] cEnc = new byte[dIn.readInt()];
-
- dIn.readFully(cEnc);
-
- try
- {
- CertificateFactory cFact = CertificateFactory.getInstance(type, BouncyCastleProvider.PROVIDER_NAME);
- ByteArrayInputStream bIn = new ByteArrayInputStream(cEnc);
-
- return cFact.generateCertificate(bIn);
- }
- catch (NoSuchProviderException ex)
- {
- throw new IOException(ex.toString());
- }
- catch (CertificateException ex)
- {
- throw new IOException(ex.toString());
- }
- }
-
- private void encodeKey(
- Key key,
- DataOutputStream dOut)
- throws IOException
- {
- byte[] enc = key.getEncoded();
-
- if (key instanceof PrivateKey)
- {
- dOut.write(KEY_PRIVATE);
- }
- else if (key instanceof PublicKey)
- {
- dOut.write(KEY_PUBLIC);
- }
- else
- {
- dOut.write(KEY_SECRET);
- }
-
- dOut.writeUTF(key.getFormat());
- dOut.writeUTF(key.getAlgorithm());
- dOut.writeInt(enc.length);
- dOut.write(enc);
- }
-
- private Key decodeKey(
- DataInputStream dIn)
- throws IOException
- {
- int keyType = dIn.read();
- String format = dIn.readUTF();
- String algorithm = dIn.readUTF();
- byte[] enc = new byte[dIn.readInt()];
- KeySpec spec;
-
- dIn.readFully(enc);
-
- if (format.equals("PKCS#8") || format.equals("PKCS8"))
- {
- spec = new PKCS8EncodedKeySpec(enc);
- }
- else if (format.equals("X.509") || format.equals("X509"))
- {
- spec = new X509EncodedKeySpec(enc);
- }
- else if (format.equals("RAW"))
- {
- return new SecretKeySpec(enc, algorithm);
- }
- else
- {
- throw new IOException("Key format " + format + " not recognised!");
- }
-
- try
- {
- switch (keyType)
- {
- case KEY_PRIVATE:
- return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePrivate(spec);
- case KEY_PUBLIC:
- return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePublic(spec);
- case KEY_SECRET:
- return SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generateSecret(spec);
- default:
- throw new IOException("Key type " + keyType + " not recognised!");
- }
- }
- catch (Exception e)
- {
- throw new IOException("Exception creating key: " + e.toString());
- }
- }
-
- protected Cipher makePBECipher(
- String algorithm,
- int mode,
- char[] password,
- byte[] salt,
- int iterationCount)
- throws IOException
- {
- try
- {
- PBEKeySpec pbeSpec = new PBEKeySpec(password);
- SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
- PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
-
- Cipher cipher = Cipher.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
-
- cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
-
- return cipher;
- }
- catch (Exception e)
- {
- throw new IOException("Error initialising store of key store: " + e);
- }
- }
-
- public void setRandom(
- SecureRandom rand)
- {
- this.random = rand;
- }
-
- public Enumeration engineAliases()
- {
- return table.keys();
- }
-
- public boolean engineContainsAlias(
- String alias)
- {
- return (table.get(alias) != null);
- }
-
- public void engineDeleteEntry(
- String alias)
- throws KeyStoreException
- {
- Object entry = table.get(alias);
-
- if (entry == null)
- {
- return;
- }
-
- table.remove(alias);
- }
-
- public Certificate engineGetCertificate(
- String alias)
- {
- StoreEntry entry = (StoreEntry)table.get(alias);
-
- if (entry != null)
- {
- if (entry.getType() == CERTIFICATE)
- {
- return (Certificate)entry.getObject();
- }
- else
- {
- Certificate[] chain = entry.getCertificateChain();
-
- if (chain != null)
- {
- return chain[0];
- }
- }
- }
-
- return null;
- }
-
- public String engineGetCertificateAlias(
- Certificate cert)
- {
- Enumeration e = table.elements();
- while (e.hasMoreElements())
- {
- StoreEntry entry = (StoreEntry)e.nextElement();
-
- if (entry.getObject() instanceof Certificate)
- {
- Certificate c = (Certificate)entry.getObject();
-
- if (c.equals(cert))
- {
- return entry.getAlias();
- }
- }
- else
- {
- Certificate[] chain = entry.getCertificateChain();
-
- if (chain != null && chain[0].equals(cert))
- {
- return entry.getAlias();
- }
- }
- }
-
- return null;
- }
-
- public Certificate[] engineGetCertificateChain(
- String alias)
- {
- StoreEntry entry = (StoreEntry)table.get(alias);
-
- if (entry != null)
- {
- return entry.getCertificateChain();
- }
-
- return null;
- }
-
- public Date engineGetCreationDate(String alias)
- {
- StoreEntry entry = (StoreEntry)table.get(alias);
-
- if (entry != null)
- {
- return entry.getDate();
- }
-
- return null;
- }
-
- public Key engineGetKey(
- String alias,
- char[] password)
- throws NoSuchAlgorithmException, UnrecoverableKeyException
- {
- StoreEntry entry = (StoreEntry)table.get(alias);
-
- if (entry == null || entry.getType() == CERTIFICATE)
- {
- return null;
- }
-
- return (Key)entry.getObject(password);
- }
-
- public boolean engineIsCertificateEntry(
- String alias)
- {
- StoreEntry entry = (StoreEntry)table.get(alias);
-
- if (entry != null && entry.getType() == CERTIFICATE)
- {
- return true;
- }
-
- return false;
- }
-
- public boolean engineIsKeyEntry(
- String alias)
- {
- StoreEntry entry = (StoreEntry)table.get(alias);
-
- if (entry != null && entry.getType() != CERTIFICATE)
- {
- return true;
- }
-
- return false;
- }
-
- public void engineSetCertificateEntry(
- String alias,
- Certificate cert)
- throws KeyStoreException
- {
- StoreEntry entry = (StoreEntry)table.get(alias);
-
- if (entry != null && entry.getType() != CERTIFICATE)
- {
- throw new KeyStoreException("key store already has a key entry with alias " + alias);
- }
-
- table.put(alias, new StoreEntry(alias, cert));
- }
-
- public void engineSetKeyEntry(
- String alias,
- byte[] key,
- Certificate[] chain)
- throws KeyStoreException
- {
- table.put(alias, new StoreEntry(alias, key, chain));
- }
-
- public void engineSetKeyEntry(
- String alias,
- Key key,
- char[] password,
- Certificate[] chain)
- throws KeyStoreException
- {
- if ((key instanceof PrivateKey) && (chain == null))
- {
- throw new KeyStoreException("no certificate chain for private key");
- }
-
- try
- {
- table.put(alias, new StoreEntry(alias, key, password, chain));
- }
- catch (Exception e)
- {
- throw new KeyStoreException(e.toString());
- }
- }
-
- public int engineSize()
- {
- return table.size();
- }
-
- protected void loadStore(
- InputStream in)
- throws IOException
- {
- DataInputStream dIn = new DataInputStream(in);
- int type = dIn.read();
-
- while (type > NULL)
- {
- String alias = dIn.readUTF();
- Date date = new Date(dIn.readLong());
- int chainLength = dIn.readInt();
- Certificate[] chain = null;
-
- if (chainLength != 0)
- {
- chain = new Certificate[chainLength];
-
- for (int i = 0; i != chainLength; i++)
- {
- chain[i] = decodeCertificate(dIn);
- }
- }
-
- switch (type)
- {
- case CERTIFICATE:
- Certificate cert = decodeCertificate(dIn);
-
- table.put(alias, new StoreEntry(alias, date, CERTIFICATE, cert));
- break;
- case KEY:
- Key key = decodeKey(dIn);
- table.put(alias, new StoreEntry(alias, date, KEY, key, chain));
- break;
- case SECRET:
- case SEALED:
- byte[] b = new byte[dIn.readInt()];
-
- dIn.readFully(b);
- table.put(alias, new StoreEntry(alias, date, type, b, chain));
- break;
- default:
- throw new RuntimeException("Unknown object type in store.");
- }
-
- type = dIn.read();
- }
- }
-
- protected void saveStore(
- OutputStream out)
- throws IOException
- {
- Enumeration e = table.elements();
- DataOutputStream dOut = new DataOutputStream(out);
-
- while (e.hasMoreElements())
- {
- StoreEntry entry = (StoreEntry)e.nextElement();
-
- dOut.write(entry.getType());
- dOut.writeUTF(entry.getAlias());
- dOut.writeLong(entry.getDate().getTime());
-
- Certificate[] chain = entry.getCertificateChain();
- if (chain == null)
- {
- dOut.writeInt(0);
- }
- else
- {
- dOut.writeInt(chain.length);
- for (int i = 0; i != chain.length; i++)
- {
- encodeCertificate(chain[i], dOut);
- }
- }
-
- switch (entry.getType())
- {
- case CERTIFICATE:
- encodeCertificate((Certificate)entry.getObject(), dOut);
- break;
- case KEY:
- encodeKey((Key)entry.getObject(), dOut);
- break;
- case SEALED:
- case SECRET:
- byte[] b = (byte[])entry.getObject();
-
- dOut.writeInt(b.length);
- dOut.write(b);
- break;
- default:
- throw new RuntimeException("Unknown object type in store.");
- }
- }
-
- dOut.write(NULL);
- }
-
- public void engineLoad(
- InputStream stream,
- char[] password)
- throws IOException
- {
- table.clear();
-
- if (stream == null) // just initialising
- {
- return;
- }
-
- DataInputStream dIn = new DataInputStream(stream);
- int version = dIn.readInt();
-
- if (version != STORE_VERSION)
- {
- if (version != 0 && version != 1)
- {
- throw new IOException("Wrong version of key store.");
- }
- }
-
- int saltLength = dIn.readInt();
- if (saltLength <= 0)
- {
- throw new IOException("Invalid salt detected");
- }
-
- byte[] salt = new byte[saltLength];
-
- dIn.readFully(salt);
-
- int iterationCount = dIn.readInt();
-
- //
- // we only do an integrity check if the password is provided.
- //
- HMac hMac = new HMac(new SHA1Digest());
- if (password != null && password.length != 0)
- {
- byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
-
- PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
- pbeGen.init(passKey, salt, iterationCount);
-
- CipherParameters macParams;
-
- if (version != 2)
- {
- macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize());
- }
- else
- {
- macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8);
- }
-
- Arrays.fill(passKey, (byte)0);
-
- hMac.init(macParams);
- MacInputStream mIn = new MacInputStream(dIn, hMac);
-
- loadStore(mIn);
-
- // Finalise our mac calculation
- byte[] mac = new byte[hMac.getMacSize()];
- hMac.doFinal(mac, 0);
-
- // TODO Should this actually be reading the remainder of the stream?
- // Read the original mac from the stream
- byte[] oldMac = new byte[hMac.getMacSize()];
- dIn.readFully(oldMac);
-
- if (!Arrays.constantTimeAreEqual(mac, oldMac))
- {
- table.clear();
- throw new IOException("KeyStore integrity check failed.");
- }
- }
- else
- {
- loadStore(dIn);
-
- // TODO Should this actually be reading the remainder of the stream?
- // Parse the original mac from the stream too
- byte[] oldMac = new byte[hMac.getMacSize()];
- dIn.readFully(oldMac);
- }
- }
-
-
- public void engineStore(OutputStream stream, char[] password)
- throws IOException
- {
- DataOutputStream dOut = new DataOutputStream(stream);
- byte[] salt = new byte[STORE_SALT_SIZE];
- int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
-
- random.nextBytes(salt);
-
- dOut.writeInt(version);
- dOut.writeInt(salt.length);
- dOut.write(salt);
- dOut.writeInt(iterationCount);
-
- HMac hMac = new HMac(new SHA1Digest());
- MacOutputStream mOut = new MacOutputStream(hMac);
- PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
- byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
-
- pbeGen.init(passKey, salt, iterationCount);
-
- if (version < 2)
- {
- hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize()));
- }
- else
- {
- hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8));
- }
-
- for (int i = 0; i != passKey.length; i++)
- {
- passKey[i] = 0;
- }
-
- saveStore(new TeeOutputStream(dOut, mOut));
-
- byte[] mac = new byte[hMac.getMacSize()];
-
- hMac.doFinal(mac, 0);
-
- dOut.write(mac);
-
- dOut.close();
- }
-
- /**
- * the BouncyCastle store. This wont work with the key tool as the
- * store is stored encrypted on disk, so the password is mandatory,
- * however if you hard drive is in a bad part of town and you absolutely,
- * positively, don't want nobody peeking at your things, this is the
- * one to use, no problem! After all in a Bouncy Castle nothing can
- * touch you.
- *
- * Also referred to by the alias UBER.
- */
- public static class BouncyCastleStore
- extends BcKeyStoreSpi
- {
- public BouncyCastleStore()
- {
- super(1);
- }
-
- public void engineLoad(
- InputStream stream,
- char[] password)
- throws IOException
- {
- table.clear();
-
- if (stream == null) // just initialising
- {
- return;
- }
-
- DataInputStream dIn = new DataInputStream(stream);
- int version = dIn.readInt();
-
- if (version != STORE_VERSION)
- {
- if (version != 0 && version != 1)
- {
- throw new IOException("Wrong version of key store.");
- }
- }
-
- byte[] salt = new byte[dIn.readInt()];
-
- if (salt.length != STORE_SALT_SIZE)
- {
- throw new IOException("Key store corrupted.");
- }
-
- dIn.readFully(salt);
-
- int iterationCount = dIn.readInt();
-
- if ((iterationCount < 0) || (iterationCount > 4 * MIN_ITERATIONS))
- {
- throw new IOException("Key store corrupted.");
- }
-
- String cipherAlg;
- if (version == 0)
- {
- cipherAlg = "Old" + STORE_CIPHER;
- }
- else
- {
- cipherAlg = STORE_CIPHER;
- }
-
- Cipher cipher = this.makePBECipher(cipherAlg, Cipher.DECRYPT_MODE, password, salt, iterationCount);
- CipherInputStream cIn = new CipherInputStream(dIn, cipher);
-
- Digest dig = new SHA1Digest();
- DigestInputStream dgIn = new DigestInputStream(cIn, dig);
-
- this.loadStore(dgIn);
-
- // Finalise our digest calculation
- byte[] hash = new byte[dig.getDigestSize()];
- dig.doFinal(hash, 0);
-
- // TODO Should this actually be reading the remainder of the stream?
- // Read the original digest from the stream
- byte[] oldHash = new byte[dig.getDigestSize()];
- Streams.readFully(cIn, oldHash);
-
- if (!Arrays.constantTimeAreEqual(hash, oldHash))
- {
- table.clear();
- throw new IOException("KeyStore integrity check failed.");
- }
- }
-
- public void engineStore(OutputStream stream, char[] password)
- throws IOException
- {
- Cipher cipher;
- DataOutputStream dOut = new DataOutputStream(stream);
- byte[] salt = new byte[STORE_SALT_SIZE];
- int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
-
- random.nextBytes(salt);
-
- dOut.writeInt(version);
- dOut.writeInt(salt.length);
- dOut.write(salt);
- dOut.writeInt(iterationCount);
-
- cipher = this.makePBECipher(STORE_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
-
- CipherOutputStream cOut = new CipherOutputStream(dOut, cipher);
- DigestOutputStream dgOut = new DigestOutputStream(new SHA1Digest());
-
- this.saveStore(new TeeOutputStream(cOut, dgOut));
-
- byte[] dig = dgOut.getDigest();
-
- cOut.write(dig);
-
- cOut.close();
- }
- }
-
- public static class Std
- extends BcKeyStoreSpi
- {
- public Std()
- {
- super(STORE_VERSION);
- }
- }
-
- public static class Version1
- extends BcKeyStoreSpi
- {
- public Version1()
- {
- super(1);
- }
- }
-}