利用RSA+AES 前后端对数据进行加密处理 — 后端实现
前言
上一篇主要将了前端方面,现在来讲讲后端如何设计
RSAUtil
需要在resource 中创建privateKey.properties和publicKey.properties 两个文件保存公钥私钥
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Base64Utils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Properties;
import java.util.UUID;
import static org.eclipse.jdt.internal.compiler.parser.Parser.name;
/**
* 实现RSA加解密
* @author : lijialun
* @description:
*/
public class RSAUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(RSAUtil.class);
/** 算法名称 */
private static final String ALGORITHM = "RSA";
/** 默认密钥大小 */
private static final int KEY_SIZE = 1024;
/** 用来指定保存密钥对的文件名和存储的名称 */
private static final String PUBLIC_KEY_NAME = "publicKey";
private static final String PRIVATE_KEY_NAME = "privateKey";
private static final String PUBLIC_FILENAME = "publicKey.properties";
private static final String PRIVATE_FILENAME = "privateKey.properties";
private static Properties pubProperties;
private static Properties PriProperties;
/** 密钥对生成器 */
private static KeyPairGenerator keyPairGenerator = null;
private static KeyFactory keyFactory = null;
/** 缓存的密钥对 */
private static KeyPair keyPair = null;
/** Base64 编码/解码器 JDK1.8 */
private static Base64.Decoder decoder = Base64.getDecoder();
private static Base64.Encoder encoder = Base64.getEncoder();
/** 初始化密钥工厂 */
static{
try {
keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyFactory = KeyFactory.getInstance(ALGORITHM);
getInstanceForPub();
getInstanceForPri();
} catch (NoSuchAlgorithmException e) {
LOGGER.error(e.getMessage(),e);
}
}
/*初始化公钥config*/
private static Properties getInstanceForPub(){
if (pubProperties == null) {
Resource res =new ClassPathResource(PUBLIC_FILENAME);
pubProperties = new Properties();
try {
pubProperties.load(res.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
return pubProperties;
}
/*初始钥私钥config*/
private static Properties getInstanceForPri(){
if (PriProperties == null) {
Resource res =new ClassPathResource(PRIVATE_FILENAME);
PriProperties = new Properties();
try {
PriProperties.load(res.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
return PriProperties;
}
/** 私有构造器 */
private RSAUtil(){}
/**
* 生成密钥对
* 将密钥分别用Base64编码保存到#publicKey.properties#和#privateKey.properties#文件中
* 保存的默认名称分别为publicKey和privateKey
*
*
*/
public static synchronized void generateKeyPair(){
try {
keyPairGenerator.initialize(KEY_SIZE,new SecureRandom());
keyPair = keyPairGenerator.generateKeyPair();
} catch (InvalidParameterException e){
LOGGER.error("KeyPairGenerator does not support a key length of " + KEY_SIZE + ".",e);
} catch (NullPointerException e){
LOGGER.error("RSAUtils#key_pair_gen is null,can not generate KeyPairGenerator instance.",e);
}
RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
String publicKeyString = encoder.encodeToString(rsaPublicKey.getEncoded());
String privateKeyString = encoder.encodeToString(rsaPrivateKey.getEncoded());
System.out.println("公钥:"+publicKeyString);
System.out.println("私钥:"+privateKeyString);
storeKey(publicKeyString,PUBLIC_KEY_NAME,pubProperties,PUBLIC_FILENAME);
storeKey(privateKeyString,PRIVATE_KEY_NAME,PriProperties,PRIVATE_FILENAME);
}
/**
* 将指定的密钥字符串保存到文件中,如果找不到文件,就创建
* @param keyString 密钥的Base64编码字符串(值)
* @param keyName 保存在文件中的名称(键)
* @param properties 目标文件
*/
private static void storeKey(String keyString,String keyName,Properties properties,String fileName){
try {
Resource res =new ClassPathResource(fileName);
FileOutputStream oFile = new FileOutputStream(res.getFile(), false);
properties.setProperty(keyName,keyString);
properties.store(oFile, keyName);
oFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取密钥字符串
* @param keyName 需要获取的密钥名
* @param properties 密钥文件
* @return Base64编码的密钥字符串
*/
private static String getKeyString(String keyName,Properties properties){
return properties.getProperty(keyName);
}
/**
* 从文件获取RSA公钥
* @return RSA公钥
* @throws InvalidKeySpecException
*/
public static RSAPublicKey getPublicKey(){
try {
byte[] keyBytes = decoder.decode(getKeyString(PUBLIC_KEY_NAME,pubProperties));
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
RSAPublicKey rsa = (RSAPublicKey)keyFactory.generatePublic(x509EncodedKeySpec);
return rsa;
}catch (InvalidKeySpecException e) {
LOGGER.error("getPublicKey()#" + e.getMessage(),e);
}
return null;
}
/**
* 从文件获取RSA私钥
* @return RSA私钥
* @throws InvalidKeySpecException
*/
public static RSAPrivateKey getPrivateKey(){
try {
byte[] keyBytes = decoder.decode(getKeyString(PRIVATE_KEY_NAME,PriProperties));
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
return (RSAPrivateKey)keyFactory.generatePrivate(pkcs8EncodedKeySpec);
} catch (InvalidKeySpecException e) {
LOGGER.error("getPrivateKey()#" + e.getMessage(),e);
}
return null;
}
/**
* RSA公钥加密
*/
public static byte[] encryptByPublicKey(byte[] data) throws Exception {
// 对数据加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > 117) {
cache = cipher.doFinal(data, offSet, 117);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * 117;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
//私钥解密
public static byte[] decryptByPrivateKey(byte[] encryptedData) throws Exception {
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(getPrivateKey().getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > 128) {
cache = cipher.doFinal(encryptedData, offSet, 128);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * 128;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
/**
* 将char转换为byte
* @param c char
* @return byte
*/
private static byte toByte(char c){
return (byte)"0123456789ABCDEF".indexOf(c);
}
public static int getValidLength(byte[] bytes){
int i = 0;
if (null == bytes || 0 == bytes.length)
return i ;
for (; i < bytes.length; i++) {
if (bytes[i] == '\0')
break;
}
return i + 1;
}
}
AESUtil
/**
* Created by Administrator on 2019/7/5 0005.
*/
import java.math.BigInteger;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Decoder;
/**
* 实现AES加解密
* @author : lijialun
* @description:
*/
public class AESUtil {
//算法
private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
/**
* 将byte[]转为各种进制的字符串
* @param bytes byte[]
* @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
* @return 转换后的字符串
*/
public static String binary(byte[] bytes, int radix){
return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
}
/**
* base 64 encode
* @param bytes 待编码的byte[]
* @return 编码后的base 64 code
*/
public static String base64Encode(byte[] bytes){
return Base64.encodeBase64String(bytes);
}
/**
* base 64 decode
* @param base64Code 待解码的base 64 code
* @return 解码后的byte[]
* @throws Exception
*/
public static byte[] base64Decode(String base64Code) throws Exception{
return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
}
/**
* AES加密
* @param content 待加密的内容
* @param encryptKey 加密密钥
* @return 加密后的byte[]
* @throws Exception
*/
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
return cipher.doFinal(content.getBytes("utf-8"));
}
/**
* AES加密为base 64 code
* @param content 待加密的内容
* @param encryptKey 加密密钥
* @return 加密后的base 64 code
* @throws Exception
*/
public static String aesEncrypt(String content, String encryptKey) throws Exception {
return base64Encode(aesEncryptToBytes(content, encryptKey));
}
/**
* AES解密
* @param encryptBytes 待解密的byte[]
* @param decryptKey 解密密钥
* @return 解密后的String
* @throws Exception
*/
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
/**
* 将base 64 code AES解密
* @param encryptStr 待解密的base 64 code
* @param decryptKey 解密密钥
* @return 解密后的string
* @throws Exception
*/
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
}
}
OncePerRequestFilter 对请求参数进行解密
import com.datanew.util.AESUtil;
import com.datanew.util.RSAUtil;
import com.datanew.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
/**
* Created by Administrator on 2019/7/3 0003.
*/
@Component
public class MyRequestBodyAdvice extends OncePerRequestFilter {
Logger logger = LoggerFactory.getLogger(MyRequestBodyAdvice.class);
private HttpServletResponse httpServletResponse;
private String parametric;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
httpServletResponse = response;
String request_uri = request.getRequestURI();
parametric = request.getHeader("Parametric");
if(request_uri.indexOf("rsa") > -1){
filterChain.doFilter(request, response);
}else if(request.getHeader("Parametric") != null){
//这里可以或者controller的method对象之后可以获取自己设置的注解进行判断是否要解密
/*ServletContext sc = request.getSession().getServletContext();
XmlWebApplicationContext cxt = (XmlWebApplicationContext) WebApplicationContextUtils.findWebApplicationContext(sc);
Method[] methods = cxt.getBean("newsController").getClass().getDeclaredMethods();
for (Method method : methods) {
if(method.getName().equals("findNewsByType")){
System.out.println(method.getName());
}
}*/
ModifyParametersWrapper mParametersWrapper = new ModifyParametersWrapper(request);
filterChain.doFilter(mParametersWrapper, response);
}else{
filterChain.doFilter(request, response);
}
}
/**
* 继承HttpServletRequestWrapper,创建装饰类,以达到修改HttpServletRequest参数的目的
*/
private class ModifyParametersWrapper extends HttpServletRequestWrapper {
private Map<String, String[]> parameterMap; // 所有参数的Map集合
public ModifyParametersWrapper(HttpServletRequest request) {
super(request);
parameterMap = request.getParameterMap();
}
// 重写几个HttpServletRequestWrapper中的方法
/**
* 获取所有参数名
*
* @return 返回所有参数名
*/
@Override
public Enumeration<String> getParameterNames() {
Vector<String> vector = new Vector<String>(parameterMap.keySet());
return vector.elements();
}
/**
* 获取指定参数名的值,如果有重复的参数名,则返回第一个的值 接收一般变量 ,如text类型
*
* @param name
* 指定参数名
* @return 指定参数名的值
*/
@Override
public String getParameter(String name) {
String[] results = parameterMap.get(name);
if (results == null || results.length <= 0)
return null;
else {
System.out.println("修改之前: " + results[0]);
return results[0];
}
}
/**
* 获取指定参数名的所有值的数组,如:checkbox的所有数据
* 接收数组变量 ,如checkobx类型
*/
@Override
public String[] getParameterValues(String name) {
String[] results = parameterMap.get(name);
if (results == null || results.length <= 0)
return null;
else {
int length = results.length;
for (int i = 0; i < length; i++) {
System.out.println("修改之前2: " + results[i]);
if(!results[i].toString().equals("0")){
try {
//解码密钥获取AES密钥
byte[] rs = Base64.getDecoder().decode(parametric.getBytes());
String aesContext = new String(RSAUtil.decryptByPrivateKey(rs));
results[i] = modify(results[i].toString(),aesContext);
} catch (Exception e) {
logger.error("解密失败");
httpServletResponse.setHeader("Parametric","false");
return null;
}
}
}
return results;
}
}
/**
* 自定义的一个简单修改原参数的方法,即:给原来的参数值前面添加了一个修改标志的字符串
*
* @param result
* 原参数值
* @return 修改之后的值
*/
private String modify(String result,String key) throws Exception{
String str = new String(Base64.getDecoder().decode(result));
return AESUtil.aesDecrypt(str,key);
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/15314.html