📄 jdkkeystore.java
字号:
package org.bouncycastle.jce.provider;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.*;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.bouncycastle.crypto.Digest;import org.bouncycastle.crypto.PBEParametersGenerator;import org.bouncycastle.crypto.digests.SHA1Digest;import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;import org.bouncycastle.crypto.io.DigestInputStream;import org.bouncycastle.crypto.io.DigestOutputStream;import org.bouncycastle.crypto.io.MacInputStream;import org.bouncycastle.crypto.io.MacOutputStream;import org.bouncycastle.crypto.macs.HMac;import org.bouncycastle.jce.interfaces.BCKeyStore;public class JDKKeyStore extends KeyStoreSpi implements BCKeyStore{ private static final int STORE_VERSION = 1; 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(); public JDKKeyStore() { } 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, Key obj, Certificate[] certChain) { this.type = KEY; this.alias = alias; this.obj = obj; this.certChain = certChain; } 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, "BC"); 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, "BC").generatePrivate(spec); case KEY_PUBLIC: return KeyFactory.getInstance(algorithm, "BC").generatePublic(spec); case KEY_SECRET: return SecretKeyFactory.getInstance(algorithm, "BC").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, "BC"); PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); Cipher cipher = Cipher.getInstance(algorithm, "BC"); 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) { throw new KeyStoreException("no such entry as " + alias); } table.remove(alias); } public Certificate engineGetCertificate( String alias) { StoreEntry entry = (StoreEntry)table.get(alias); if (entry != null) { if (entry.getType() == CERTIFICATE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -