Encrypt and Decrypt tool, and load remote config file

This commit is contained in:
xiaoyu830411
2012-08-31 16:59:51 +08:00
parent 88908b5f25
commit 056303ae5a
36 changed files with 211 additions and 454 deletions
@@ -16,15 +16,17 @@
package com.alibaba.druid.filter.config;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.config.loader.ConfigLoader;
import com.alibaba.druid.filter.config.loader.ConfigLoaderFactory;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.support.security.decryptor.DecryptException;
import com.alibaba.druid.support.security.decryptor.Decrypter;
import com.alibaba.druid.support.security.decryptor.DecrypterFactory;
import com.alibaba.druid.support.security.decryptor.SensitiveParameters;
import com.alibaba.druid.filter.config.security.decrypter.DecryptException;
import com.alibaba.druid.filter.config.security.decrypter.Decrypter;
import com.alibaba.druid.filter.config.security.decrypter.DecrypterFactory;
import com.alibaba.druid.filter.config.security.decrypter.SensitiveParameters;
import java.sql.SQLException;
import java.util.Properties;
@@ -76,10 +78,6 @@ import java.util.Properties;
* #远程文件路径
* config.file=http://xxxxx(http://开头或者file:开头)
*
* #AES解密, key不指定, 使用默认的
* config.decrypt=AES
* config.decrypt.key=abcdfeg
*
* #RSA解密, Key不指定, 使用默认的
* config.decrypt=RSA
* config.decrypt.key=密钥字符串
@@ -1,50 +0,0 @@
package com.alibaba.druid.filter.config;
import java.util.Properties;
/**
* <pre>
* 配置文件装载器.
*
* 要实现自己的装载器有如下要求.
* 1. 一定要有自己的协议格式, 例如是由 my-protocol: 开头的protocol是由我支持的.
* public isSupported(String protocol) {
* return protocol.startsWith("my-protocol:");
* }
*
* 2. 要在class path的根目录下的ConfigLoader.properties注册(如果没有这个文件, 可以自己创建一个). 例如:
* WEB-INF/classes/ConfigLoader.properties [格式如下]:
* ConfigLoader.myConfigLoader=com.xxx.xxx.xx.MyConfigLoader
*
* 3. 配置<code>DruidDataSource</code>的时候的URL就要设置为装载器的协议格式
* DruidDataSource dataSource = new DruidDataSource();
* dataSource.setUrl("my-protocol:http://xxxxxx/");
*
* </pre>
* @see com.alibaba.druid.filter.config.impl.FileConfigLoader
* @see com.alibaba.druid.filter.config.impl.HttpConfigLoader
*
* @author Jonas Yang
*/
public interface ConfigLoader {
/**
* 唯一的ID
* @return
*/
public String getId();
/**
* 获得配置内容, 如果没有, 返回<code>null</code>.
* @param protocol
* @return
*/
public Properties loadConfig(String protocol);
/**
* 是否支持该协议, 如果支持, 将会使用该装载器获取配置文件
* @param protocol
* @return
*/
public boolean isSupported(String protocol);
}
@@ -0,0 +1,36 @@
package com.alibaba.druid.filter.config.loader;
import java.util.Properties;
/**
* <pre>
* 配置文件装载器.
* </pre>
*
* @see com.alibaba.druid.filter.config.ConfigFilter
* @see ConfigLoaderFactory
*
* @author Jonas Yang
*/
public interface ConfigLoader {
/**
* 唯一的ID
* @return
*/
public String getId();
/**
* 获得配置内容, 如果没有, 返回<code>null</code>.
* @param protocol
* @return
*/
public Properties loadConfig(String protocol);
/**
* 是否支持该协议, 如果支持, 将会使用该装载器获取配置文件
* @param protocol
* @return
*/
public boolean isSupported(String protocol);
}
@@ -1,4 +1,4 @@
package com.alibaba.druid.filter.config;
package com.alibaba.druid.filter.config.loader;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
@@ -11,9 +11,9 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* <pre>
* 如果有扩展的装载器.
* 可以放到classes目录下的ConfigLoader.properties
* 可以放到classes目录下的druid-config-loader.properties
*
* ConfigLoader.properties 内容如下:
* druid-config-loader.properties 内容如下:
* ConfigLoader.x=com.xx.xxx.xx.MyConfigLoader
*
* </pre>
@@ -1,6 +1,6 @@
package com.alibaba.druid.filter.config.impl;
package com.alibaba.druid.filter.config.loader.impl;
import com.alibaba.druid.filter.config.ConfigLoader;
import com.alibaba.druid.filter.config.loader.ConfigLoader;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
@@ -1,6 +1,6 @@
package com.alibaba.druid.filter.config.impl;
package com.alibaba.druid.filter.config.loader.impl;
import com.alibaba.druid.filter.config.ConfigLoader;
import com.alibaba.druid.filter.config.loader.ConfigLoader;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
@@ -1,9 +1,8 @@
package com.alibaba.druid.support.security.decryptor;
package com.alibaba.druid.filter.config.security.decrypter;
import com.alibaba.druid.util.Base64;
import javax.crypto.Cipher;
import java.util.Properties;
/**
* 加密抽象类
@@ -12,11 +11,6 @@ import java.util.Properties;
*/
public abstract class AbstractDecrypter implements Decrypter {
/**
* DES, AES 密钥都有长度限制, 如果不够, 默认使用该字段补长
*/
public static final String KEY_PADDING = "FOLLOW YOUR HEART. YOU CAN DO BEST THAN ANY ONE.";
public final static String KEY = "config.decrypt.key";
/**
@@ -1,4 +1,4 @@
package com.alibaba.druid.support.security.decryptor;
package com.alibaba.druid.filter.config.security.decrypter;
/**
* 加密出错
@@ -1,4 +1,4 @@
package com.alibaba.druid.support.security.decryptor;
package com.alibaba.druid.filter.config.security.decrypter;
import java.util.Properties;
@@ -26,10 +26,10 @@ import java.util.Properties;
*
* </pre>
* <br/>
* <b>默认下, Druid 已经实现了AES, RSA加解密. AES, RSA 密文必须是通过Druid Tool的加密工具生成的</b>
* <b>默认下, Druid 已经实现了RSA加解密. RSA 密文必须是通过Druid Tool的加密工具生成的</b>
* <b>获取默认解密方式可以通过 DecrypterFactory.getDecrypter(String id)</b>
* <br/>
* <b>使用加密工具: java -cp druid-x.x.x.jar com.alibaba.druid.support.security.tool.Main</b>
* <b>使用加密工具: java -cp druid-x.x.x.jar com.alibaba.druid.filter.config.security.tool.Main</b>
* @author Jonas Yang
*/
public interface Decrypter {
@@ -1,4 +1,4 @@
package com.alibaba.druid.support.security.decryptor;
package com.alibaba.druid.filter.config.security.decrypter;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
@@ -17,10 +17,7 @@ public class DecrypterFactory {
static {
RsaDecrypter rsa = new RsaDecrypter();
AesDecrypter aes = new AesDecrypter();
decrypters.put(rsa.getId(), rsa);
decrypters.put(aes.getId(), aes);
}
private DecrypterFactory() {}
@@ -1,4 +1,4 @@
package com.alibaba.druid.support.security.decryptor;
package com.alibaba.druid.filter.config.security.decrypter;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
@@ -8,7 +8,6 @@ import com.alibaba.druid.util.JdbcUtils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.cert.Certificate;
@@ -50,7 +49,10 @@ public class RsaDecrypter extends AbstractDecrypter {
*/
public SensitiveParameters decrypt(SensitiveParameters parameters, Properties info) throws DecryptException {
PublicKey publicKey = getPublicKey(info);
return decrypt(parameters, publicKey);
}
protected SensitiveParameters decrypt(SensitiveParameters parameters, PublicKey publicKey) throws DecryptException {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
@@ -1,4 +1,4 @@
package com.alibaba.druid.support.security.decryptor;
package com.alibaba.druid.filter.config.security.decrypter;
/**
* <pre>
@@ -0,0 +1,11 @@
package com.alibaba.druid.filter.config.security.tool;
/**
* @author Jonas Yang
*/
public interface Action {
public String getId();
public void execute();
}
@@ -1,4 +1,4 @@
package com.alibaba.druid.support.security.tool;
package com.alibaba.druid.filter.config.security.tool;
import java.util.ArrayList;
import java.util.List;
@@ -1,10 +1,10 @@
package com.alibaba.druid.support.security.tool;
package com.alibaba.druid.filter.config.security.tool;
/**
* <pre>
* Druid 提供的加密工具. 如下运行
*
* <b>java -cp druid-x.x.x.jar com.alibaba.druid.support.security.tool.Main</b>
* <b>java -cp druid-x.x.x.jar com.alibaba.druid.filter.config.security.tool.Main</b>
*
* </pre>
* @author Jonas Yang
@@ -17,7 +17,6 @@ public class Main {
static {
int i = 1;
help.addAction(Integer.toString(i++), new RsaAction());
help.addAction(Integer.toString(i++), new AesAction());
help.addAction("h", help);
help.addAction("q", new QuitAction());
}
@@ -1,4 +1,4 @@
package com.alibaba.druid.support.security.tool;
package com.alibaba.druid.filter.config.security.tool;
/**
* @author Jonas Yang
@@ -1,4 +1,4 @@
package com.alibaba.druid.support.security.tool;
package com.alibaba.druid.filter.config.security.tool;
import com.alibaba.druid.util.Base64;
@@ -1,74 +0,0 @@
package com.alibaba.druid.support.security.decryptor;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Properties;
/**
* <pre>
* AES 解密器, 如果不指定密钥, 使用默认的密钥.
* 通过一下方式指定密钥:
* Properties info = new Properties();
* info.put("config.decrypt.key", "密钥");
*
* String 明文 = new AesDecrypter().decrypt("密文", info);
* </pre>
*
* @author Jonas Yang
*/
public class AesDecrypter extends AbstractDecrypter {
private static Log log = LogFactory.getLog(AesDecrypter.class);
private final static int KEY_LENGTH = 16; //128
public String getId() {
return "AES";
}
/**
* 密钥 放在 <code>Properties</code> 参数中, key 是 config.decrypt.key, 如果不指定密钥, 将使用默认密钥
* @param parameters 密文参数
* @param info
* @return
* @throws DecryptException
*/
public SensitiveParameters decrypt(SensitiveParameters parameters, Properties info) throws DecryptException {
SecretKeySpec spec = getSpec(info);
try {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, spec);
String passwordPlainText = decrypt(cipher, parameters.getPassword());
return new SensitiveParameters(parameters.getUrl(), parameters.getUsername(), passwordPlainText);
} catch (Exception e) {
throw new DecryptException("Failed to decrypt JDBC password’", e);
}
}
SecretKeySpec getSpec(Properties info) {
String key = null;
if (info != null) {
key = info.getProperty(KEY);
}
if (key == null) {
if (log.isDebugEnabled()) {
log.debug("Decrypt by default key");
}
key = "";
}
if (key.length() < 16) {
key = KEY_PADDING.substring(0, KEY_LENGTH - key.length()) + key;
}
return new SecretKeySpec(key.getBytes(), "AES");
}
}
@@ -1,72 +0,0 @@
package com.alibaba.druid.support.security.tool;
/**
* @author Jonas Yang
*/
public abstract class AbstractAction implements Action {
private int minKeyLength;
private int maxKeyLength;
private String prompt;
public AbstractAction(int minKeyLength, int maxKeyLength, String prompt) {
if (minKeyLength < 0 || maxKeyLength < 0) {
throw new IllegalArgumentException("The key length must be a positive.");
}
if (maxKeyLength < minKeyLength) {
throw new IllegalArgumentException("The max length of key cannot be less than min length.");
}
this.minKeyLength = minKeyLength;
this.maxKeyLength = maxKeyLength;
this.prompt = "[" + prompt + "]";
}
protected abstract String encrypt(String keyString, String plainString) throws Exception;
@Override
public void execute() {
System.out.println();
String keyString = readPassword();
if (keyString == null) return;
String plainString = System.console().readLine(this.prompt + "请输入要需要加密的明文: ");
if (plainString == null) {
System.err.println("输入不能为空.");
return;
}
try {
String encryptedString = encrypt(keyString, plainString);
System.out.println("请记住以下的密文, 长度为[" + encryptedString.length() + "].");
System.out.println();
System.out.println(encryptedString);
System.out.println();
} catch (Exception e) {
System.out.println("加密出错.");
e.printStackTrace();
}
}
protected String readPassword() {
char[] keyChars = System.console().readPassword(this.prompt + "请输入密码[长度最大为" + this.maxKeyLength + "字节]: ");
if (keyChars == null) {
keyChars = new char[0];
}
String keyString = new String(keyChars);
if (keyString.length() < this.minKeyLength || keyString.length() > this.maxKeyLength) {
System.err.println("错误: 密码长度要大于等于" + this.minKeyLength + ", 小于等于" + this.maxKeyLength + ".");
return null;
}
keyString = KEY_PADDING.substring(0, this.maxKeyLength - keyString.length()) + keyString;
return keyString;
}
}
@@ -1,17 +0,0 @@
package com.alibaba.druid.support.security.tool;
import com.alibaba.druid.support.security.decryptor.AbstractDecrypter;
/**
* @author Jonas Yang
*/
public interface Action {
/**
* DES, AES 密钥都有长度限制, 如果不够, 默认使用该字段补长
*/
public String KEY_PADDING = AbstractDecrypter.KEY_PADDING;
public String getId();
public void execute();
}
@@ -1,32 +0,0 @@
package com.alibaba.druid.support.security.tool;
import com.alibaba.druid.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/**
* @author Jonas Yang
*/
public class AesAction extends AbstractAction {
public AesAction() {
super(0, 16, "AES");
}
@Override
public String getId() {
return "AES";
}
protected String encrypt(String keyString, String plainString) throws Exception {
SecretKeySpec spec = new SecretKeySpec(keyString.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, spec);
byte[] encryptedBytes = cipher.doFinal(plainString.getBytes());
return Base64.byteArrayToBase64(encryptedBytes);
}
}