encrypt.java

来自「JGRoups源码」· Java 代码 · 共 1,405 行 · 第 1/3 页

JAVA
1,405
字号
// $Id: ENCRYPT.java,v 1.26 2006/10/11 14:39:13 belaban Exp $package org.jgroups.protocols;import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;import org.jgroups.*;import org.jgroups.stack.Protocol;import org.jgroups.util.QueueClosedException;import org.jgroups.util.Streamable;import org.jgroups.util.Util;import javax.crypto.*;import javax.crypto.spec.SecretKeySpec;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStream;import java.security.*;import java.security.cert.CertificateException;import java.security.spec.X509EncodedKeySpec;import java.util.Map;import java.util.Properties;import java.util.WeakHashMap;/** * ENCRYPT layer. Encrypt and decrypt the group communication in JGroups * * The file can be used in two ways: * <ul> * <li> Option 1. Configured with a secretKey in a keystore so it can be used at any * layer in JGroups without the need for a coordinator,  or if you want protection against passive * monitoring but do not want the key exchange overhead and complexity. In this mode all nodes must be distributed with * the same keystore file. * <li> Option 2. Configured with algorithms and key sizes. The Encrypt Layer in this mode sould be used between the * FRAG and PBCast layers in the stack. The coordinator then chooses the * secretkey which it distributes amongst all the peers. In this form no keystore exists as the keys are * distributed using a public/private key exchange. View changes that identify a new controller will result in a new session key * being generated and then distributed to all peers. This overhead can be substantial in a an application with * a reasonable peer churn. * </ul> * <p> * <p> * Each message is identified as encrypted with a specific encryption header which identifies * the type of encrypt header and an MD5 digest that identifies the version of the key being used * to encrypt/decrypt the messages. * <p> * <p> *<h2>Option 1</h2><br> * This is the simplest option and can be used by simply inserting the Encryption layer * at any point in the JGroup stack - it will encrypt all Events of a type MSG that * have a non-null message buffer. The format of the entry in this form is:<br> * &lt;ENCRYPT key_store_name="defaultStore.keystore" store_password="changeit" alias="myKey"/&gt;<br> * An example bare-bones.xml file showing the keystore version can be found in the conf * ina file called EncryptKeyStore.xml - along with a defaultStore.keystore file.<br> * In order to use the Encrypt layer in this manner it is necessary to have the secretKey already generated * in a keystore file. The directory containing the keystore file must be on the application's classpath. * You cannot create a SecretKey keystore file using the keytool application shipped with the JDK. * A java file called KeyStoreGenerator is included in the demo * package that can be used from the command line (or IDE) to generate a suitable keystore. * <p> * <p> *<h2>Option 2</h2><br> * This option is suited to an application that does not ship with a known key but instead it is generated * and distributed by the controller. The secret key is first generated by the Controller (in JGroup terms). When a view change * occurs a peer will request the secret key by sending a key request with its own public key. The controller * encrypts the secret key with this key and sends it back to the peer who then decrypts it and installs the * key as its own secret key. * <br>All encryption and decryption of Messages is done using this key. When a peer receives * a view change that shows a different keyserver it will repeat this process - the view change event * also trigger the encrypt layer to queue up and down messages until the new key is installed. * The previous keys are retained so that messages sent before the view change that are queued can be decrypted * if the key is different. * <br> * An example EncryptNoKeyStore.xml is included in the conf file as a guide. * <p><p> * <br> Note: the current version does not support the concept of perfect forward encryption (PFE) * which means that if a peer leaves the group the keys are re-generated preventing the departed peer from * decrypting future messages if it chooses to listen in on the group. This is not included as it really requires * a suitable authentication scheme as well to make this feature useful as there is nothing to stop the peer rejoining and receiving the new * key. A future release will address this issue. * * @author Steve Woodcock * @author Bela Ban */public class ENCRYPT extends Protocol {    static final String DEFAULT_SYM_ALGO = "Blowfish";    // address info    Address local_addr = null;    // keyserver address    Address keyServerAddr = null;    //used to see whether we are the key server    boolean keyServer = false;    // encryption properties in no supplied key mode    String asymProvider = null;    final String symProvider = null;    String asymAlgorithm = "RSA";    String symAlgorithm = DEFAULT_SYM_ALGO;    int asymInit = 512; // initial public/private key length    int symInit = 56; // initial shared key length    // properties for functioning in supplied key mode    private boolean suppliedKey = false;    private String keyStoreName;    private String storePassword ="changeit"; //JDK default    private String keyPassword="changeit"; //JDK default    private String alias="mykey"; // JDK default    // public/private Key    KeyPair Kpair; // to store own's public/private Key//	 for client to store server's public Key    PublicKey serverPubKey = null;    // needed because we do simultaneous encode/decode with these ciphers - which    // would be a threading issue    Cipher symEncodingCipher;    Cipher symDecodingCipher;    // version filed for secret key    private String symVersion = null;    // dhared secret key to encrypt/decrypt messages    SecretKey secretKey = null;    // map to hold previous keys so we can decrypt some earlier messages if we need to    final Map keyMap = new WeakHashMap();    // queues to buffer data while we are swapping shared key    // or obtsining key for first time    private boolean queue_up = true;    private boolean queue_down = false;    // queue to hold upcoming messages while key negotiation is happening    private LinkedQueue upMessageQueue = new LinkedQueue();//	 queue to hold downcoming messages while key negotiation is happening    private LinkedQueue downMessageQueue = new LinkedQueue();    // decrypting cypher for secret key requests    private Cipher asymCipher;    /** determines whether to encrypt the entire message, or just the buffer */    private boolean encrypt_entire_message=false;    public ENCRYPT()    {    }    public String getName()    {        return "ENCRYPT";    }    /*      * GetAlgorithm: Get the algorithm name from "algorithm/mode/padding"      *  taken from original ENCRYPT file      */    private String getAlgorithm(String s)    {        int index = s.indexOf("/");        if (index == -1)            return s;        return s.substring(0, index);    }    public boolean setProperties(Properties props)    {        String str;        super.setProperties(props);        // asymmetric key length        str = props.getProperty("asym_init");        if (str != null)        {            asymInit = Integer.parseInt(str);            props.remove("asym_init");            if (log.isInfoEnabled())                log.info("Asym algo bits used is " + asymInit);        }        // symmetric key length        str = props.getProperty("sym_init");        if (str != null)        {            symInit = Integer.parseInt(str);            props.remove("sym_init");            if (log.isInfoEnabled())                log.info("Sym algo bits used is " + symInit);        }        // asymmetric algorithm name        str = props.getProperty("asym_algorithm");        if (str != null)        {            asymAlgorithm = str;            props.remove("asym_algorithm");            if (log.isInfoEnabled())                log.info("Asym algo used is " + asymAlgorithm);        }        // symmetric algorithm name        str = props.getProperty("sym_algorithm");        if (str != null)        {            symAlgorithm = str;            props.remove("sym_algorithm");            if (log.isInfoEnabled())                log.info("Sym algo used is " + symAlgorithm);        }        // symmetric algorithm name        str = props.getProperty("asym_provider");        if (str != null)        {            asymProvider = str;            props.remove("asym_provider");            if (log.isInfoEnabled())                log.info("asymProvider used is " + asymProvider);        }        //symmetric algorithm name        str = props.getProperty("key_store_name");        if (str != null)        {            keyStoreName = str;            props.remove("key_store_name");            if (log.isInfoEnabled())                log.info("key_store_name used is " + keyStoreName);        }        //		symmetric algorithm name        str = props.getProperty("store_password");        if (str != null)        {            storePassword = str;            props.remove("store_password");            if (log.isInfoEnabled())                log.info("store_password used is not null");        }        //		symmetric algorithm name        str = props.getProperty("key_password");        if (str != null)        {            keyPassword = str;            props.remove("key_password");            if (log.isInfoEnabled())                log.info("key_password used is not null");        } else if (storePassword != null)        {            keyPassword = storePassword;            if (log.isInfoEnabled())                log.info("key_password used is same as store_password");        }        //		symmetric algorithm name        str = props.getProperty("alias");        if (str != null)        {            alias = str;            props.remove("alias");            if (log.isInfoEnabled())                log.info("alias used is " + alias);        }        str=props.getProperty("encrypt_entire_message");        if(str != null)        {            this.encrypt_entire_message=new Boolean(str).booleanValue();            props.remove("encrypt_entire_message");        }        if (props.size() > 0)        {            if (log.isErrorEnabled())                log.error("these properties are not recognized:" + props);            return false;        }        return true;    }    public void init() throws Exception    {        if (keyStoreName == null)        {            initSymKey();            initKeyPair();        } else        {            initConfiguredKey();        }        initSymCiphers(symAlgorithm, getSecretKey());    }    /**     *  Initialisation if a supplied key is defined in the properties. This     *  supplied key must be in a keystore which can be generated using the     *  keystoreGenerator file in demos. The keystore must be on the classpath     *  to find it.     *     * @throws KeyStoreException     * @throws Exception     * @throws IOException     * @throws NoSuchAlgorithmException     * @throws CertificateException     * @throws UnrecoverableKeyException     */    private void initConfiguredKey() throws KeyStoreException, Exception,                                            IOException, NoSuchAlgorithmException, CertificateException,                                            UnrecoverableKeyException    {        InputStream inputStream = null;        // must not use default keystore type - as does not support secret keys        KeyStore store = KeyStore.getInstance("JCEKS");        SecretKey tempKey = null;        try        {            // load in keystore using this thread's classloader            inputStream = Thread.currentThread().getContextClassLoader()                    .getResourceAsStream(keyStoreName);            // we can't find a keystore here -            if (inputStream == null)            {                throw new Exception("Unable to load keystore " + keyStoreName +                        " ensure file is on classpath");            }            // we have located a file lets load the keystore            try{            store.load(inputStream, storePassword.toCharArray());            // loaded keystore - get the key            tempKey = (SecretKey) store                    .getKey(alias, keyPassword.toCharArray());            } catch (IOException e){                throw new Exception("Unable to load keystore "+ keyStoreName + ": " + e);            }catch (NoSuchAlgorithmException e){                throw new Exception("No Such algorithm "+ keyStoreName + ": " + e);            }catch(CertificateException e){                throw new Exception("Certificate exception "+ keyStoreName + ": " + e);            }            if (tempKey == null)            {                throw new Exception("Unable to retrieve key '" + alias                        + "' from keystore " + keyStoreName);            }            //set the key here            setSecretKey(tempKey);            if (symAlgorithm.equals(DEFAULT_SYM_ALGO)) {            symAlgorithm = tempKey.getAlgorithm();            }            // set the fact we are using a supplied key            suppliedKey = true;            queue_down =false;            queue_up =false;        } finally        {            Util.close(inputStream);        }    }    /**     * Used to initialise the symmetric key if none is supplied in a keystore.     * @throws Exception     */    public void initSymKey() throws Exception    {        KeyGenerator keyGen = null;        // see if we have a provider specified        if (symProvider != null && symProvider.trim().length() > 0)        {            keyGen = KeyGenerator.getInstance(getAlgorithm(symAlgorithm),                                              symProvider);        } else        {            keyGen = KeyGenerator.getInstance(getAlgorithm(symAlgorithm));        }        // generate the key using the defined init properties        keyGen.init(symInit);        secretKey = keyGen.generateKey();        setSecretKey(secretKey);        if (log.isInfoEnabled())            log.info(" Symmetric key generated ");    }    /**     * Initialises the Ciphers for both encryption and decryption using the     * generated or supplied secret key.     *     * @param algorithm     * @param secret     * @throws Exception     */    private void initSymCiphers(String algorithm, SecretKey secret) throws Exception    {        if (log.isInfoEnabled())            log.info(" Initializing symmetric ciphers");        symEncodingCipher = Cipher.getInstance(algorithm);        symDecodingCipher = Cipher.getInstance(algorithm);        symEncodingCipher.init(Cipher.ENCRYPT_MODE, secret);        symDecodingCipher.init(Cipher.DECRYPT_MODE, secret);        //set the version        MessageDigest digest = MessageDigest.getInstance("MD5");        digest.reset();        digest.update(secret.getEncoded());        symVersion = new String(digest.digest(), "UTF-8");        if (log.isInfoEnabled()) {            // log.info(" Initialized symmetric ciphers with secret key (" + symVersion.length() + " bytes) " +symVersion);            StringBuffer sb=new StringBuffer(" Initialized symmetric ciphers with secret key (" + symVersion.length() + " bytes) ");            char[] arr=symVersion.toCharArray();            for(int i=0; i < arr.length; i++) {                char c=arr[i];                sb.append((int)c);            }            log.info(sb.toString());        }    }    /**     *  Generates the public/private key pair from the init params     * @throws Exception     */    public void initKeyPair() throws Exception    {        // generate keys according to the specified algorithms        // generate publicKey and Private Key        KeyPairGenerator KpairGen = null;        if (asymProvider != null && asymProvider.trim().length() > 0)        {            KpairGen = KeyPairGenerator.getInstance(

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?