数据安全设计
引言:在 web 程序中,数据加密非常重要,对于不用解密的数据,如密码等,一般使用 md5 的加密技术,对于需要解密的数据,我们常用 AES 加密,现在我们来讨论下如何提高数据的安全性。
一、对私钥用公钥加密,然后数据进行多次对称加密
我觉得,数据的加首先双方约定一个
公钥:ABCDEFGHIJKLMNOP
签名:QWERTYHJKDLOFJSK
数据加密次数:n
-
加密随机**
首先对公钥进行MD5加密,转大写并截取 16 位作为newKey;
然后随机生成 16 位的随机** randomKey,对randomKey 进行 AES 标准加密(偏移量和私钥一样,加密方式为为:“AES/CBC/PKCS5Padding”)得到加密的秘钥realKey;
-
双方约定数据封装形式+签名-> data,然后对其 MD5 加密转大写成为newSign;
再对上面的随机秘钥 randomKey 进行 MD5 加密,截取 16 位作为数据传输的 json 进行 AES 标准进行加密,json 一般都是需要传输的数据+newSign;(这里 AES 根据约定进行轮换 n 次)
下面给出流程示例
下面贴出代码
package com.dao.xu;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.digest.DigestUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
/**
* 安全设计
*
* @author 阿导
* @CopyRight 万物皆导
* @Created 2019/5/15 20:26:00
*/
public class WWJD {
/**
* 加密公钥
*/
private final static String COMMON_KEY = "wwjdwwjdwwjdwwjdwwjdwwjdwwjdwwjd";
/**
* 签名秘钥
*/
private final static String SIGN_KEY = "wwjdwwjdwwjdwwjdwwjdwwjdwwjdwwjd";
/**
* 约定次数
*/
private final static Integer N = 10;
/**
* SIGN
*/
private final static String SIGN = "sign";
/**
* 随机秘钥集合
*/
private final static String KEYS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz*$";
/**
* 默认字符集
*/
private final static String DEFAULT_CODE = "UTF-8";
/**
* 零
*/
private final static Integer ZERO = Integer.valueOf(0);
/**
* 引号
*/
public static final String QUOTES = "\"";
/**
* 逗号
*/
public static final String COMMA = ",";
/**
* 冒号
*/
public static final String COLON = ":";
/**
* 左大括号
*/
public static final String BRACES_LEFT = "{";
/**
* 右大括号
*/
public static final String BRACES_RIGHT = "}";
/**
* 将字符串MD5加码 生成32位md5码
*
* @param inStr
* @return java.lang.String
* @author 阿导
* @time 2019/5/15 20:23:00
*/
private static String md5(String inStr) {
try {
return DigestUtils.md5Hex(inStr.getBytes(DEFAULT_CODE));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误");
}
}
/**
* AES加密
*
* @param cleartext
* @param rKey
* @return java.lang.String
* @author 阿导
* @time 2019/5/15 20:24:00
*/
private static String encrypt(String cleartext, String rKey) {
//加密方式: AES128(CBC/PKCS5Padding) + Base64, 私钥:rKey
try {
IvParameterSpec zeroIv = new IvParameterSpec(rKey.getBytes());
//两个参数,第一个为私钥字节数组, 第二个为加密方式 AES或者DES
SecretKeySpec key = new SecretKeySpec(rKey.getBytes(), "AES");
//实例化加密类,参数为加密方式,要写全
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//PKCS5Padding比PKCS7Padding效率高,PKCS7Padding可支持IOS加解密
//初始化,此方法可以采用三种方式,按加密算法要求来添加。(1)无第三个参数(2)第三个参数为SecureRandom random = new SecureRandom();中random对象,随机数。(AES不可采用这种方法)(3)采用此代码中的IVParameterSpec
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
//加密操作,返回加密后的字节数组,然后需要编码。主要编解码方式有Base64, HEX, UUE,7bit等等。此处看服务器需要什么编码方式
byte[] encryptedData = cipher.doFinal(cleartext.getBytes(DEFAULT_CODE));
return new BASE64Encoder().encode(encryptedData);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* AES 解密
* @author 阿导
* @time 2019/5/15 20:24:00
* @param encrypted
* @param rKey
* @return java.lang.String
*/
private static String decrypt(String encrypted, String rKey) {
try {
byte[] byteMi = new BASE64Decoder().decodeBuffer(encrypted);
IvParameterSpec zeroIv = new IvParameterSpec(rKey.getBytes());
SecretKeySpec key = new SecretKeySpec(rKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//与加密时不同MODE:Cipher.DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
byte[] decryptedData = cipher.doFinal(byteMi);
return new String(decryptedData, DEFAULT_CODE);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* 获取随机秘钥
*
* @author 阿导
* @time 2019/5/15 20:25:00
* @param num
* @return java.lang.String
*/
private static String getRKey(Integer num) {
String rs = new String();
for (int pox = ZERO; pox < num; pox++) {
rs += KEYS.toCharArray()[new Random().nextInt(KEYS.length())];
}
return rs;
}
public static Map<String, String> getEncryptionData(Map<String, String> map) {
//存储realKey和realData
Map<String, String> rsMap = new HashMap<>(16);
String randomKey = getRKey(16);
rsMap.put("realKey", URLEncoder.encode(encrypt(randomKey, md5(COMMON_KEY).substring(ZERO, 16).toUpperCase())));
String realData = getJsonString(map);
for (int i = ZERO; i < N; i++) {
realData = encrypt(realData, randomKey);
}
rsMap.put("realData", URLEncoder.encode(realData));
return rsMap;
}
/**
* 处理数据
*
* @author 阿导
* @time 2019/5/15 20:26:00
* @param params
* @return java.lang.String
*/
private static String dealData(Map<String, Object> params) {
StringBuilder sign = new StringBuilder();
Map<String, Object> sortParams = new TreeMap<String, Object>(params);
Set<Map.Entry<String, Object>> entrys = sortParams.entrySet();
int count = ZERO;
for (Map.Entry<String, Object> entry : entrys) {
if (entry.getValue() != null) {
if (count++ != ZERO) {
sign.append(COMMA);
}
sign.append(QUOTES)
.append(entry.getKey())
.append(COLON)
.append(entry.getValue())
.append(QUOTES);
}
}
sign.append(QUOTES)
.append(SIGN)
.append(COLON)
.append(SIGN_KEY)
.append(QUOTES);
return md5(sign.toString()).toUpperCase();
}
/**
* 获取 json 数据
*
* @author 阿导
* @time 2019/5/15 20:26:00
* @param params
* @return java.lang.String
*/
private static String getJsonString(Map<String, String> params) {
StringBuilder json = new StringBuilder();
// 将参数以参数名的字典升序排序
Map<String, String> sortParams = new TreeMap<String, String>(params);
Set<Map.Entry<String, String>> entrys = sortParams.entrySet();
String sign = dealData(new HashMap<>(params));
json.append(BRACES_LEFT);
int count = ZERO;
for (Map.Entry<String, String> entry : entrys) {
if (entry.getValue() != null) {
if (count++ != ZERO) {
json.append(COMMA);
}
json.append(QUOTES)
.append(entry.getKey())
.append(QUOTES)
.append(COLON)
.append(QUOTES)
.append(entry.getValue())
.append(QUOTES);
}
}
json.append(COMMA)
.append(QUOTES)
.append(SIGN)
.append(QUOTES)
.append(COLON)
.append(QUOTES)
.append(sign)
.append(QUOTES)
.append(BRACES_RIGHT);
return json.toString();
}
/**
* 获取解密数据
*
* @author 阿导
* @time 2019/5/15 20:27:00
* @param map
* @return java.lang.Object
*/
private static Object getDecryptData(Map<String, String> map) {
try {
String randomKey = decrypt(URLDecoder.decode(map.get("realKey")), md5(COMMON_KEY).substring(0, 16).toUpperCase());
String rsData = URLDecoder.decode(map.get("realData").toString());
for (int i = ZERO; i < N; i++) {
rsData = decrypt(rsData, randomKey);
}
Map<String, Object> rsMap = JSON.parseObject(rsData);
String sign = (String) rsMap.get("sign");
if (sign == null || "".equals(sign)) {
return "SIGN_NULL";
}
rsMap.remove("sign");
if (sign.equals(dealData(rsMap))) {
return rsMap;
} else {
return "SIGN_ERROR";
}
} catch (Exception e) {
return "KEY_ERROR";
}
}
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("name", "小明");
map.put("sex", "男");
Map<String, String> map1 = getEncryptionData(map);
Object map2 = getDecryptData(map1);
System.err.println(map2);
}
}
哎!最近阿导诸事不利,广告还是打起来: