情景:项目在涉及到账号注册和登陆时,遇到用户密码的加密和解密过程,网上不少加密算法如MD5加密算法、DES加密算法、Base64加密算法和AES加密算法等。
在此记录目前使用比较流行的AES加密算法
AES,高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。严格地说,AES和Rijndael加密法并不完全一样(虽然在实际应用中二者可以互换),因为Rijndael加密法可以支持更大范围的区块和密钥长度:AES的区块长度固定为128 比特,密钥长度则可以是128,192或256比特;而Rijndael使用的密钥和区块长度可以是32位的整数倍,以128位为下限,256比特为上限。包括AES-ECB,AES-CBC,AES-CTR,AES-OFB,AES-CFB
经过几年时间发展,AES加密算法已成为对称密钥加密中的算法之一,也被不少大佬们封装成加密的工具类,下面介绍一下大佬Wang926454【注:大佬真名咱也不知道,嘿嘿! 那默默地使用呗】封装的AES工具类吧,废话不多说上代码:
AesCipherUtil工具类
package com.seeker.system.util;
import com.seeker.system.exception.CustomUnauthorizedException;
import com.seeker.system.util.common.Base64ConvertUtil;
import com.seeker.system.util.common.HexConvertUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.*;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
/**
* AES加密解密工具类
* @author Wang926454
* @date 2018/8/31 16:39
*/
@Component
public class AesCipherUtil {
/**
* AES密码加密私钥(Base64加密)
*/
private static String encryptAESKey;
// private static final byte[] KEY = { 1, 1, 33, 82, -32, -85, -128, -65 };
@Value("${encryptAESKey}")
public void setEncryptAESKey(String encryptAESKey) {
AesCipherUtil.encryptAESKey = encryptAESKey;
}
/**
* logger
*/
private static final Logger logger = LoggerFactory.getLogger(AesCipherUtil.class);
/**
* 加密
* @param str
* @return java.lang.String
* @author Wang926454
* @date 2018/8/31 16:56
*/
public static String enCrypto(String str) {
try{
Security.addProvider(new com.sun.crypto.provider.SunJCE());
// 实例化支持AES算法的密钥生成器(算法名称命名需按规定,否则抛出异常)
// KeyGenerator 提供对称密钥生成器的功能,支持各种算法
KeyGenerator keygen = KeyGenerator.getInstance("AES");
// 将私钥encryptAESKey先Base64解密后转换为byte[]数组按128位初始化
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(Base64ConvertUtil.decode(encryptAESKey).getBytes());
keygen.init(128, secureRandom);
// SecretKey 负责保存对称密钥 生成密钥
SecretKey deskey = keygen.generateKey();
// 生成Cipher对象,指定其支持的AES算法,Cipher负责完成加密或解密工作
Cipher c = Cipher.getInstance("AES");
// 根据密钥,对Cipher对象进行初始化,ENCRYPT_MODE表示加密模式
c.init(Cipher.ENCRYPT_MODE, deskey);
byte[] src = str.getBytes();
// 该字节数组负责保存加密的结果
byte[] cipherByte = c.doFinal(src);
// 先将二进制转换成16进制,再返回Bsae64加密后的String
return Base64ConvertUtil.encode(HexConvertUtil.parseByte2HexStr(cipherByte));
} catch (NoSuchAlgorithmException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("getInstance()方法异常:" + e.getMessage());
} catch (UnsupportedEncodingException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("Bsae64加密异常:" + e.getMessage());
} catch (NoSuchPaddingException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("getInstance()方法异常:" + e.getMessage());
} catch (InvalidKeyException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("初始化Cipher对象异常:" + e.getMessage());
} catch (IllegalBlockSizeException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("加密异常,密钥有误:" + e.getMessage());
} catch (BadPaddingException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("加密异常,密钥有误:" + e.getMessage());
}
}
/**
* 解密
* @param str
* @return java.lang.String
* @author Wang926454
* @date 2018/8/31 16:56
*/
public static String deCrypto(String str) {
try{
Security.addProvider(new com.sun.crypto.provider.SunJCE());
// 实例化支持AES算法的密钥生成器(算法名称命名需按规定,否则抛出异常)
// KeyGenerator 提供对称密钥生成器的功能,支持各种算法
KeyGenerator keygen = KeyGenerator.getInstance("AES");
// 将私钥encryptAESKey先Base64解密后转换为byte[]数组按128位初始化
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(Base64ConvertUtil.decode(encryptAESKey).getBytes());
keygen.init(128, secureRandom);
// SecretKey 负责保存对称密钥 生成密钥
SecretKey deskey = keygen.generateKey();
// 生成Cipher对象,指定其支持的AES算法,Cipher负责完成加密或解密工作
Cipher c = Cipher.getInstance("AES");
// 根据密钥,对Cipher对象进行初始化,DECRYPT_MODE表示解密模式
c.init(Cipher.DECRYPT_MODE, deskey);
// 该字节数组负责保存加密的结果,先对str进行Bsae64解密,将16进制转换为二进制
byte[] cipherByte = c.doFinal(HexConvertUtil.parseHexStr2Byte(Base64ConvertUtil.decode(str)));
return new String(cipherByte);
} catch (NoSuchAlgorithmException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("getInstance()方法异常:" + e.getMessage());
} catch (UnsupportedEncodingException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("Bsae64加密异常:" + e.getMessage());
} catch (NoSuchPaddingException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("getInstance()方法异常:" + e.getMessage());
} catch (InvalidKeyException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("初始化Cipher对象异常:" + e.getMessage());
} catch (IllegalBlockSizeException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("解密异常,密钥有误:" + e.getMessage());
} catch (BadPaddingException e){
logger.error(e.getMessage());
throw new CustomUnauthorizedException("解密异常,密钥有误:" + e.getMessage());
}
}
}
在这个类之中需要其他几个公共类,不然会报错,下面是公共类,需要使用copy项目中创建一下,然后改一下上面类路径即可使用。
【1】CustomUnauthorizedException异常处理类
package com.seeker.system.exception;
/**
* 自定义401无权限异常(UnauthorizedException)
* @author Wang926454
* @date 2018/8/30 13:59
*/
public class CustomUnauthorizedException extends RuntimeException {
public CustomUnauthorizedException(String msg){
super(msg);
}
public CustomUnauthorizedException() {
super();
}
}
【2】Base64ConvertUtil类
package com.seeker.system.util.common;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
/**
* Base64工具
* @author Wang926454
* @date 2018/8/21 15:14
*/
public class Base64ConvertUtil {
/**
* 加密JDK1.8
* @param str
* @return java.lang.String
* @author Wang926454
* @date 2018/8/21 15:28
*/
public static String encode(String str) throws UnsupportedEncodingException {
byte[] encodeBytes = Base64.getEncoder().encode(str.getBytes("utf-8"));
return new String(encodeBytes);
}
/**
* 解密JDK1.8
* @param str
* @return java.lang.String
* @author Wang926454
* @date 2018/8/21 15:28
*/
public static String decode(String str) throws UnsupportedEncodingException {
byte[] decodeBytes = Base64.getDecoder().decode(str.getBytes("utf-8"));
return new String(decodeBytes);
}
public static void main(String[] args) throws UnsupportedEncodingException {
System.out.println(decode("U0JBUElKV1RkV2FuZzkyNjQ1NA=="));
}
}
【3】HexConvertUtil 进制转换类
package com.seeker.system.util.common;
/**
* 进制转换工具
* @author Wang926454
* @date 2018/8/31 17:23
*/
public class HexConvertUtil {
/**
* 1
*/
private static final Integer INTEGER_1 = 1;
/**
* 2
*/
private static final Integer INTEGER_2 = 2;
/**
* 将二进制转换成16进制
* @param buff
* @return java.lang.String
* @author Wang926454
* @date 2018/8/31 17:20
*/
public static String parseByte2HexStr(byte[] buff) {
StringBuffer sb = new StringBuffer();
for (int i = 0, len = buff.length; i < len; i++) {
String hex = Integer.toHexString(buff[i] & 0xFF);
if (hex.length() == INTEGER_1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
* @param hexStr
* @return byte[]
* @author Wang926454
* @date 2018/8/31 17:21
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < INTEGER_1){
return null;
}
byte[] result = new byte[hexStr.length() / INTEGER_2];
for (int i = 0, len = hexStr.length() / INTEGER_2;i < len; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
【4】配置文件config.properties,【注:如果不配置AES密码加密密钥会报错的】
# AES密码加密私钥(Base64加密)
encryptAESKey=V2FuZzkyNjQ1NGRTQkFQSUpXVA==
这边账号密码的加密方式是【登录名+密码】,当然也可不用加上用户名,根据自己需要来用哦,例如项目中调用:
//注册时对密码AES加密
String key = AesCipherUtil.enCrypto(sysUser.getLoginName() + sysUser.getPassword());
// 密码进行AES解密
String key = AesCipherUtil.deCrypto(sysUser.getPassword());
OK 这次就到这里啦