SpringBoot 实现对提供的接口进行 AES (加密,解密)

业务来源:

最近工作中,领导要求给别的项目组的小伙伴提供几个接口,要求对接口的参数进行解密操作,然后对返回的数据进行加密操作。

这时我想到了AES

AES 是对称加密算法,优点:加密速度快;缺点:如果秘钥丢失,就容易解密密文,安全性相对比较差。

代码案例:

请求参数格式:

javascript 复制代码
{
 "appId": "queryLectureListByPage",
 "data": "eIVh49T2zKQrtcrhVi6BXcXljN4XFlZc9csQiyayIE1eYeIatVNc9gOTL6HHYj29arBEV3TXMVnQxGIR2EHMfICQz+Aq5ldGk0ys13Rgiqk="
}

响应的参数格式:

javascript 复制代码
{
    "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=="
}

生成密钥:

java 复制代码
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加密解密工具类:
java 复制代码
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);
    }
    
}
业务层核心代码:
java 复制代码
    @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不能为空");
                }
        }

    }
相关推荐
苹果醋39 分钟前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
Hello.Reader28 分钟前
深入解析 Apache APISIX
java·apache
盛派网络小助手1 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
菠萝蚊鸭1 小时前
Dhatim FastExcel 读写 Excel 文件
java·excel·fastexcel
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
007php0071 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
∝请叫*我简单先生1 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
ssr——ssss1 小时前
SSM-期末项目 - 基于SSM的宠物信息管理系统
java·ssm
一棵星1 小时前
Java模拟Mqtt客户端连接Mqtt Broker
java·开发语言
鲤籽鲲2 小时前
C# Random 随机数 全面解析
android·java·c#