业务来源:
最近工作中,领导要求给别的项目组的小伙伴提供几个接口,要求对接口的参数进行解密操作,然后对返回的数据进行加密操作。
这时我想到了AES
AES 是对称加密算法,优点:加密速度快;缺点:如果秘钥丢失,就容易解密密文,安全性相对比较差。
代码案例:
请求参数格式:
{
"appId": "queryLectureListByPage",
"data": "eIVh49T2zKQrtcrhVi6BXcXljN4XFlZc9csQiyayIE1eYeIatVNc9gOTL6HHYj29arBEV3TXMVnQxGIR2EHMfICQz+Aq5ldGk0ys13Rgiqk="
}
响应的参数格式:
{
"code": 200,
"message": "ok",
"data": "eHDl88EzrjfZzA179EN6s1dUPs10bWpSWRo2skyQf1+eO6x66ypDnVXoyB5wr6T62lmfVdwa3oK0ZFqnOzd3SW/DE6UaMPZtJovzFTpjxbzvnuwO3v9b3vEsA2nOUQEjEqbpzBrzEClNtL2tkSuoA7oJkTiH3ec6otwFFJZGbV93JW9+xvFkG3TObHIO6fdqlgNIDGbgs7TnwStc64suuH+H7Bt25pCggCq6yVv+Zx69/0Zprvu5s7Dma8NYy/N69cfWgj+06Ik5DXcJlzlZXKQLwwQHiHtleIum2dSF3HWE7ck212n/zn1WVVpGUFnevYCr7Gx/lHbkh/hIOifl8sDpkaISP2tO4kXDi1neUyCnrM7437rf/ZhLPBANkkIO40cZcjEGdrMNswAfZ6XxkBTBq3BMpnjulUbSPZXA6xwwdiaORv1Jx9yxpVBRuw5D4FHby+VPRAh3WP2VMptpzXYeJGBJXU/KvODrKy+tDb8Iq/PUESzECrrYVc/QwWVeBmNKOFyCtXTB486QWqUGbFvoWHnQUUh/taM8/GOYglWzCtziDntRxum2qruxuq23fnNknKGi3wJBzBSZj8kWw0NUx7RIaZcoqwbzmYx4H6h9D28ViAv/y4/nQGxKho3nlW5EVuk6+yQLadc1DSp4Ug=="
}
生成密钥:
package com.ly.cloud.util;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import com.alibaba.druid.util.Base64;
import org.apache.commons.codec.binary.Hex;
public class AESUtils {
private static final String AES = "AES";
private static final String UTF8 = "UTF-8";
private static final String CIPHERALGORITHM = "AES/ECB/PKCS5Padding";
private static final String Key = "9!#95hsup*&$1zq7";
public static void main(String[] args) throws IOException {
// wqkjejqwkejqwk 可随便输入字符串,生成对应的密钥
String wqkjejqwkejqwk = encrypts("wqkjejqwkejqwk");
System.out.println(wqkjejqwkejqwk);
}
/**
* 生成base 64 作为AES加密后的密钥
*/
public static String encrypts(String content) {
try {
byte[] encodeFormat = Key.getBytes();
SecretKeySpec key = new SecretKeySpec(encodeFormat, AES);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(CIPHERALGORITHM);
// 加密内容进行编码
byte[] byteContent = content.getBytes(UTF8);
// 用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, key);
// 正式执行加密操作
byte[] result = cipher.doFinal(byteContent);
return Hex.encodeHexString(result);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
思路:
通过传入的appId然后去数据库中查询到对应的 唯一密钥。然后根据唯一密钥进行解析密文。然后转成将密文转成 我们需要的参数对象。
核心代码:
AES加密解密工具类:
package com.ly.cloud.util;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import com.alibaba.druid.util.Base64;
import org.apache.commons.codec.binary.Hex;
public class AESUtils {
private static final String AES = "AES";
private static final String UTF8 = "UTF-8";
private static final String CIPHERALGORITHM = "AES/ECB/PKCS5Padding";
private static final String Key = "9!#95hsup*&$1zq7";
/**
* AES加密+Base64转码
*
* @param data 明文(16进制)
* @param key 密钥
* @return
*/
public static String encrypt(String data, String key) {
byte[] keyb = null;
keyb = Base64.base64ToByteArray(key);
SecretKeySpec sKeySpec = new SecretKeySpec(keyb, "AES");
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
byte[] bjiamihou = null;
String miwen = "";
try {
bjiamihou = cipher.doFinal(data.getBytes("utf-8"));
// byte加密后
miwen = Base64.byteArrayToBase64(bjiamihou);// 密文用base64加密
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return miwen;
}
/**
* Base64解码 + AES解码
*
* @param data 密文 (16进制)
* @param key 密钥
* @return
*/
public static String decrypt(String data, String key){
byte[] keyb = null;
keyb = Base64.base64ToByteArray(key);
byte[] miwen = Base64.base64ToByteArray(data);
SecretKeySpec sKeySpec = new SecretKeySpec(keyb, "AES");
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
byte[] bjiemihou = null;
String mingwen = "";
try {
bjiemihou = cipher.doFinal(miwen);
// byte加密后
mingwen = new String(bjiemihou,"utf-8");
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return mingwen;
}
public static void main(String[] args) throws IOException {
String name = "{\"userId\":\"179135\",\"keyword\":\"讲座副标题\",\"pageNum\":\"1\",\"pageSize\":\"10\"}";
// String encrypt = encrypt(name, "qVkn2qNkkyAAF8PjQL/7GQ==");
// String name = "{\"userId\":\"179135\",\"pageNum\":\"1\",\"pageSize\":\"20\"}";
// String name1 = "{\"userId\":\"179135\",\"organizerId\":\"02020\"}";
String name1 = "{\"pageNum\":\"1\",\"pageSize\":\"20\"}";
String encrypt = encrypt(name, "8c5e186c9de8e9a628234522a794f45b0f");
System.out.println(encrypt);
System.out.println("---------");
System.out.println(decrypt(encrypt,"8c5e186c9de8e9a628234522a794f45b0f"));
String wqkjejqwkejqwk = encrypts("wqkjejqwkererjqwk");
System.out.println(wqkjejqwkererjqwk);
}
/**
* 生成base 64 作为AES加密后的密钥
*/
public static String encrypts(String content) {
try {
byte[] encodeFormat = Key.getBytes();
SecretKeySpec key = new SecretKeySpec(encodeFormat, AES);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(CIPHERALGORITHM);
// 加密内容进行编码
byte[] byteContent = content.getBytes(UTF8);
// 用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, key);
// 正式执行加密操作
byte[] result = cipher.doFinal(byteContent);
return Hex.encodeHexString(result);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 加密
public static String dataToAES(String password,String data){
String hexStr = encrypt(data, password);
return hexStr;
}
// 解密
public static String AESToData(String password, String data){
return decrypt(data, password);
}
}
业务层核心代码:
@Override
public String organizerList(LectureEncryptDto encrypt) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
//获取appid 对应的key值
String key = checkParam(encrypt);
// 解密参数 根据传入不同的 对象返回不同的对象
MySubscribeDto subscribe = returnObject(MySubscribeDto.class, key, encrypt);
//校验解密后参数是否为空
checkPageParam(subscribe, "2");
Page<MySubscribe> page = new Page<>(subscribe.getPageNum(), subscribe.getPageSize());
PageDto<MySubscribe> pageDto = new PageDto<>();
IPage<MySubscribe> pageData = lectureMapper.organizerList(page, subscribe.getUserId());
pageDto.setTotal(pageData.getTotal());
pageDto.setPages(pageData.getPages());
pageDto.setPageSize(subscribe.getPageSize());
pageDto.setPageNum(subscribe.getPageNum());
pageDto.setList(pageData.getRecords());
//加密
String json = JSONUtil.toJsonStr(pageDto);
return AESUtils.dataToAES(key, json);
}
/**
* 根据传入的不同的对象,将他进行解密。然后返回
*/
public static <T> T returnObject(Class<T> clazz, String key, LectureEncryptDto dto) {
Gson gson = new Gson();
String decryptedData = AESUtils.AESToData(key, dto.getData());
if (StrUtil.isEmpty(decryptedData)) {
throw new BusinessException("appId生成的data密钥有误");
}
return gson.fromJson(decryptedData, clazz);
}
/**
* 检查appID 是否有效
*/
public String checkParam(LectureEncryptDto dto) {
// 根据他传的appid 去数据库里取出appid 对应的 key值,
String key = lectureMapper.getAppIdKey(dto.getAppId());
if (StrUtil.isEmpty(key)) {
throw new BusinessException("appId有误,请重新输入");
}
return key;
}
/**
* 检查分页-以及其它所需参数是否为空
*/
public static void checkPageParam(Object objects, String key) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> clazz = objects.getClass();
Method getPageSizeMethod = clazz.getMethod("getPageSize");
Method getPageNumMethod = clazz.getMethod("getPageNum");
Integer pageSize = (Integer) getPageSizeMethod.invoke(objects);
Integer pageNum = (Integer) getPageNumMethod.invoke(objects);
if (pageSize == null || pageNum == null) {
throw new BusinessException("页码不能为空");
}
// 根据key设置相应的属性
switch (key) {
case "1":
break;
case "2":
Method userIdMethod = clazz.getMethod("getUserId");
if (StrUtil.isEmpty((String) userIdMethod.invoke(objects))) {
throw new BusinessException("学工号不能为空");
}
break;
case "3":
Method user = clazz.getMethod("getUserId");
Method getId = clazz.getMethod("getOrganizerId");
if (StrUtil.isEmpty((String) user.invoke(objects)) && StrUtil.isEmpty((String) getId.invoke(objects))) {
throw new BusinessException("学工号或主办单位ID不能为空");
}
}
}