前言
加解密插件是很常用的功能来的,加上去以后起码网站的安全性会高那么一点点。下面尝试用配置好的框架来写这个插件。插件包含aes,des,md5以及base64,注意,目前只是雏形,以后有需要会优化的。
这次整合到MasterWebApp模块中。
添加对应的配置类以及工具类
在WebExt下面添加对应的类,如下图:
代码分别是:
package net.w2p.WebExt.config;
/***
*
* 注意,这是加密解密组件的配置文件
* ***/
public class CryptoConf {
/***
* AES/ECB/PKCS5Padding,Java版3DES加密解密的密钥,密钥为16的倍数,例如:AKlMU89D3FchIkhK
* ***/
public String aes_key="";
/***
* DES/CBC/PKCS5Padding,des加解密需要用到的私钥,长度不能够小于8位,例如:abcdefgh
* ***/
public String des_key="";
/***
*
* md5使用的key
* ***/
public String md5_key="";
public String getAes_key() {
return aes_key;
}
public void setAes_key(String aes_key) {
this.aes_key = aes_key;
}
public String getDes_key() {
return des_key;
}
public void setDes_key(String des_key) {
this.des_key = des_key;
}
public String getMd5_key() {
return md5_key;
}
public void setMd5_key(String md5_key) {
this.md5_key = md5_key;
}
}
package net.w2p.WebExt.Plugins;
import net.w2p.WebExt.config.CryptoConf;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
/***
* 加解密插件。
* ***/
public class CryptoPlugin {
private CryptoConf conf=null;
private Cipher cipher4Aes = null; //私鈅加密对象Cipher
private SecretKey secretKey4Aes = null;//key对象
//des
private final String ALGORITHM_DES = "DES/CBC/PKCS5Padding";
private AlgorithmParameterSpec paramSpec4Des=null;
private Key secretKey4Des=null;
private Cipher cipher4Des=null;
//md5
protected char md5hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
protected static MessageDigest md5messagedigest = null;
public CryptoPlugin(CryptoConf conf) throws Exception {
this.conf=conf;
//--aes初始化
// secretKey = new SecretKeySpec(keyString.getBytes(), "DESede");//获得密钥
secretKey4Aes = new SecretKeySpec(this.conf.aes_key.getBytes(), "AES");//获得密钥
/*获得一个私鈅加密类Cipher,DESede是算法,ECB是加密模式,PKCS5Padding是填充方式*/
// cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
/*获得一个私鈅加密类Cipher,DESede-》AES算法,ECB是加密模式,PKCS5Padding是填充方式*/
cipher4Aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
//--des初始化。
DESKeySpec dks = new DESKeySpec(this.conf.des_key.getBytes());
SecretKeyFactory keyFactory4Des = SecretKeyFactory.getInstance("DES");
//key的长度不能够小于8位字节
secretKey4Des = keyFactory4Des.generateSecret(dks);
cipher4Des = Cipher.getInstance(ALGORITHM_DES);
paramSpec4Des = new IvParameterSpec(this.conf.des_key.getBytes());
cipher4Des.init(Cipher.ENCRYPT_MODE, secretKey4Des, paramSpec4Des);
//--md5初始化
md5messagedigest = MessageDigest.getInstance("MD5");
}
/***base64 begin***/
/**
*
* 创建日期2011-4-25上午10:12:38
* 修改日期
* 作者:dh
*TODO 使用Base64加密算法加密字符串
*return
*/
public String encodeBase64(String plainText){
byte[] b=plainText.getBytes();
Base64 base64=new Base64();
b=base64.encode(b);
String s=new String(b);
return s;
}
/**
*
* 创建日期2011-4-25上午10:12:38
* 修改日期
* 作者:dh
*TODO 使用Base64加密算法加密字符串
*return
*/
public String encodeBase64(byte[] bytes){
byte[] b=bytes;
Base64 base64=new Base64();
b=base64.encode(b);
String s=new String(b);
return s;
}
/**
*
* 创建日期2011-4-25上午10:15:11
* 修改日期
* 作者:dh
*TODO 使用Base64加密
*return
*/
public String decodeBase64(String encodeStr){
byte[] b=encodeStr.getBytes();
Base64 base64=new Base64();
b=base64.decode(b);
String s=new String(b);
return s;
}
/**
*
* 创建日期2011-4-25上午10:15:11
* 修改日期
* 作者:dh
*TODO 使用Base64加密
*return
*/
public byte[] decodeBase64(byte[] bytes){
byte[] b=bytes;
Base64 base64=new Base64();
b=base64.decode(b);
return b;
}
/***base64 end***/
/***Aes begin***/
/**
* Aes加密
* @param message
* @return
*/
public String AesEncrypt(String message) throws Exception {
String result = ""; //DES加密字符串
String newResult = "";//去掉换行符后的加密字符串
cipher4Aes.init(Cipher.ENCRYPT_MODE, secretKey4Aes); //设置工作模式为加密模式,给出密钥
byte[] resultBytes = cipher4Aes.doFinal(message.getBytes("UTF-8")); //正式执行加密操作
BASE64Encoder enc = new BASE64Encoder();
result = enc.encode(resultBytes);//进行BASE64编码
newResult = filter(result); //去掉加密串中的换行符
return newResult;
}
/**
* Aes解密
* @param message
* @return
* @throws Exception
*/
public String AesDecrypt(String message) throws Exception {
String result = "";
BASE64Decoder dec = new BASE64Decoder();
byte[] messageBytes = dec.decodeBuffer(message); //进行BASE64编码
cipher4Aes.init(Cipher.DECRYPT_MODE, secretKey4Aes); //设置工作模式为解密模式,给出密钥
byte[] resultBytes = cipher4Aes.doFinal(messageBytes);//正式执行解密操作
result = new String(resultBytes,"UTF-8");
return result;
}
/**
* aes 加密解密时候去掉加密字符串换行符
* @param str
* @return
*/
public String filter(String str) {
String output = "";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < str.length(); i++) {
int asc = str.charAt(i);
if (asc != 10 && asc != 13) {
sb.append(str.subSequence(i, i+1));
}
}
output = new String(sb);
return output;
}
/***Aes end***/
/****Des begin***/
/**
* DES算法,加密
*
* @param data 待加密字符串
* @return 加密后的字节数组,一般结合Base64编码使用
* @throws CryptException 异常
*/
public String DesEncrypt(String data) throws Exception
{
return DesEncrypt(data.getBytes());
}
/**
* DES算法,加密
*
* @param data 待加密字符串
* @param key 加密私钥,长度不能够小于8位
* @return 加密后的字节数组,一般结合Base64编码使用
* @throws CryptException 异常
*/
public String DesEncrypt(byte[] data) throws Exception
{
try
{
cipher4Des.init(Cipher.ENCRYPT_MODE, secretKey4Des,paramSpec4Des);
byte[] bytes = cipher4Des.doFinal(data);
// return byte2hex(bytes);
return new String(encodeBase64(bytes));
} catch (Exception e)
{
throw new Exception(e);
}
}
/**
* DES算法,解密
*
* @param data 待解密字符串
* @param key 解密私钥,长度不能够小于8位
* @return 解密后的字节数组
* @throws Exception 异常
*/
public byte[] DesDecrypt(byte[] data) throws Exception
{
try
{
cipher4Des.init(Cipher.DECRYPT_MODE, secretKey4Des,paramSpec4Des);
return cipher4Des.doFinal(data);
} catch (Exception e)
{
throw new Exception(e);
}
}
/**
* des算法,解密
* @param data
* @return
* @throws Exception
*/
public String DesDecrypt(String data)
{
byte[] datas;
String value = null;
try {
datas = DesDecrypt(decodeBase64(data.getBytes()));
value = new String(datas);
} catch (Exception e) {
value = "";
}
return value;
}
/****Des end***/
/***md5 begin***/
/**
* MD5方法
*
* @param text 明文 *
* @return 密文
* @throws Exception
*/
public String md5WithKey(String text) throws Exception {
//加密后的字符串
return md5((text+conf.md5_key).getBytes());
}
public String md5WithoutKey(String text) throws Exception {
//加密后的字符串
return md5(text.getBytes());
}
/**
* 对byte类型的数组进行MD5加密
*
* @author 高焕杰
*/
public String md5(byte[] bytes) throws Exception {
md5messagedigest.update(bytes);
return bufferToHex(md5messagedigest.digest());
}
//
private String bufferToHex(byte bytes[]) {
return bufferToHex(bytes, 0, bytes.length);
}
private String bufferToHex(byte bytes[], int m, int n) {
StringBuffer stringbuffer = new StringBuffer(2 * n);
int k = m + n;
for (int l = m; l < k; l++) {
char c0 = md5hexDigits[(bytes[l] & 0xf0) >> 4];
char c1 = md5hexDigits[bytes[l] & 0xf];
stringbuffer.append(c0);
stringbuffer.append(c1);
}
return stringbuffer.toString();
}
/**
* MD5验证方法
*
* @param text 明文
* @param md5 密文
* @return true/false
* @throws Exception
*/
public boolean verifyMD5(String text, String md5) throws Exception {
//根据传入的密钥进行验证
String md5Text = md5WithKey(text);
if(md5Text.equalsIgnoreCase(md5))
{
System.out.println("MD5验证通过");
return true;
}
return false;
}
/***md5 end***/
}
初始化配置中心的数据
请执行
create or replace function "initCryptoConfig"(
in envName varchar
)
returns varchar
as $BODY$
declare _defaultValues varchar;
declare _envName varchar;
declare _appname varchar;
declare _prefix varchar;
declare strArrays varchar[];
declare arrItemLv1 varchar;
declare tempArrSubItem varchar;
declare valArrs varchar[];
declare item_attr varchar;
declare item_title varchar;
declare item_val varchar;
declare _appDesc varchar;
begin
if envName <> 'test' and envName<> 'ppe' and envName<> 'product' then
raise notice '环境变量异常,只能为test、ppe以及product其中一个。';
return '环境变量异常,只能为test、ppe以及product其中一个。';
end if;
_appname:='crypto';
_appDesc:='加解密设置(系统通用)';
_prefix:=concat(_appname,'.','');
_defaultValues:=
'aes_key->AES/ECB/PKCS5Padding,Java版3DES加密解密的密钥,密钥为16的倍数,例如:12345678abcdefgh->12345678abcdefgh$$' ||
'des_key->DES/CBC/PKCS5Padding,des加解密需要用到的私钥,长度不能够小于8位,例如:abcdefgh->abcdefgh$$' ||
'md5_key->md5_key,随意字符串,例如:13579->13579$$' ||
''
;
strArrays:=string_to_array(_defaultValues,'$$');
_envName:=envName;
-- fastdfs.connect_timeout_in_seconds = 5
-- fastdfs.network_timeout_in_seconds = 30
-- fastdfs.charset = UTF-8
-- fastdfs.http_anti_steal_token = false
-- fastdfs.http_secret_key = FastDFS1234567890
-- fastdfs.http_tracker_http_port = 80
-- #fastdfs.tracker_servers = tw-server:22122,10.0.11.202:22122,10.0.11.203:22122
-- fastdfs.tracker_servers = localhost:22122
-- fastdfs.visit_url = http://localhost/
-- env varchar(100) not null,
-- key varchar(200) not null,
-- appname varchar(100) not null,
-- title varchar(100) not null,
-- value varchar(2000) default NULL::character varying,
insert into xxl_conf_project (appname, title) values (_appname,_appDesc) on conflict ("appname") do nothing;
<<loop4BigArray>>
foreach arrItemLv1 in array strArrays
loop
if char_length(arrItemLv1) < 1 then
raise notice '空字符串无须处理';
continue ;
end if;
valArrs:=string_to_array(arrItemLv1,'->');
item_attr:=valArrs[1];
item_title:=valArrs[2];
item_val:=valArrs[3];
raise notice '属性名称:%,描述:%,当前值:%',item_attr,item_title,item_val;
raise notice '开始添加记录';
insert into xxl_conf_node("env","key","appname","title","value")
values (_envName,concat(_prefix,item_attr),_appname,item_title,item_val)
on conflict ("env","key") do nothing ;
end loop loop4BigArray;
return envName||'环境下的'||_appName||'配置成功';
end;
$BODY$ language plpgsql volatile ;
-- 记住执行下面方法分别添加三个环境下的默认数据。
-- select "initCryptoConfig"('test');
-- select "initCryptoConfig"('ppe');
-- select "initCryptoConfig"('product');
用工具远程登录配置中心的数据库,直接执行即可:
select "initCryptoConfig"('test');
select "initCryptoConfig"('ppe');
select "initCryptoConfig"('product');
使用java代码整合到spring中进行设置
在MasterWebApp中整合。
在MasterWebApp的BeanConfiguration下面添加:
package net.w2p.local.plugins.BeanConfiguration;
import com.xxl.conf.core.XxlConfClient;
import net.w2p.WebExt.Plugins.CryptoPlugin;
import net.w2p.WebExt.config.CryptoConf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/***
*
* 系统加解密插件配置
* ***/
@Configuration
public class CryptoConfiguration {
@Bean(name="cryptoConf")
public CryptoConf cryptoConf(){
final String VarPrefix ="crypto.";
CryptoConf conf=new CryptoConf();
conf.aes_key = XxlConfClient.get(VarPrefix+"aes_key");
conf.des_key = XxlConfClient.get(VarPrefix+"des_key");
conf.md5_key = XxlConfClient.get(VarPrefix+"md5_key");
return conf;
}
@Bean(name="cryptoPlugin")
@Autowired
public CryptoPlugin cryptoPlugin(@Qualifier("cryptoConf") CryptoConf conf){
try {
CryptoPlugin plugin = new CryptoPlugin(conf);
return plugin;
}
catch (Exception ed){
ed.printStackTrace();
return null;
}
}
}
进行测试
测试代码如下:
@Test
public void testCrypto() throws Exception {
if(1==1){
String flag="Aes--->";
System.out.println(flag);
String res="nihao,你好,hello";
String enc=cryptoPlugin.AesEncrypt(res);
String dec=cryptoPlugin.AesDecrypt(enc);
System.out.println(flag+"原始数据:"+res);
System.out.println(flag+"加密后:"+enc);
System.out.println(flag+"解密后:"+dec);
res="well,done!!!?><:L";
enc=cryptoPlugin.AesEncrypt(res);
dec=cryptoPlugin.AesDecrypt(enc);
System.out.println(flag+"原始数据:"+res);
System.out.println(flag+"加密后:"+enc);
System.out.println(flag+"解密后:"+dec);
}
if(1==1){
String flag="Des--->";
System.out.println(flag);
String res="nihao,你好,hello";
String enc=cryptoPlugin.DesEncrypt(res);
String dec=cryptoPlugin.DesDecrypt(enc);
System.out.println(flag+"原始数据:"+res);
System.out.println(flag+"加密后:"+enc);
System.out.println(flag+"解密后:"+dec);
res="well,done!!!?><:L";
enc=cryptoPlugin.DesEncrypt(res);
dec=cryptoPlugin.DesDecrypt(enc);
System.out.println(flag+"原始数据:"+res);
System.out.println(flag+"加密后:"+enc);
System.out.println(flag+"解密后:"+dec);
}
if(1==1){
String flag="MD5--->";
System.out.println(flag);
String res="nihao,你好,hello";
String enc=cryptoPlugin.md5WithKey(res);
System.out.println(flag+"原始数据:"+res);
System.out.println(flag+"加密后:"+enc);
res="well,done!!!?><:L";
enc=cryptoPlugin.md5WithKey(res);
System.out.println(flag+"原始数据:"+res);
System.out.println(flag+"加密后:"+enc);
}
}
测试结果:
插件基本通过验收。后续的组件将用到这个插件的。所以,还是安上去好点。