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> * <ENCRYPT key_store_name="defaultStore.keystore" store_password="changeit" alias="myKey"/><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 + -
显示快捷键?