安全检查时要求账号和密码加密后才能存到数据库中,要求加密算法如下:
1)分组密码算法:AES(密钥长度在128位及以上)(GCM或CBC模式)
2)流密码算法:AES(密钥长度在128位及以上)(OFB或CTR模式)、chacha20
3)非对称加密算法:RSA(2048位及以上)、ECC(256位以上)
4)哈希算法:SHA2、SHA3
5)密钥交换算法:DSA/DH(密钥长度2048位及以上)、ECDH(密钥长度223及以上)
6)HMAC(基于哈希的消息验证码)算法:HMAC-SHA2
因此将原来普通的Base64加密换成AES 128位CBC加密。
对AES加密要求:1、CBC模式或CFB模式必须保证每次加密的IV是安全随机数。2、加密时不能使用固定的IV(如:写死在代码里,或固定在配置文件中)。
下面附上代码:
package com.util;
import org.apache.log4j.Logger;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
/**
* @program
* @description AES128位CBC模式加解密
* @create 2019-04-03 14:55
**/
public class AESUtil
{
public final static String ENCODING = "UTF-8";
private static Logger log = Logger.getLogger(AESUtil.class);
/**
* @param buf 二进制
* @return java.lang.String
* @description 将二进制转换成16进制
* @date 2019/5/8 9:49
*/
public static String parseByte2HexStr(byte[] buf)
{
if (null == buf)
{
return null;
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++)
{
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1)
{
hex = '0' + hex;
}
sb.append(hex.toUpperCase(Locale.US));
}
return sb.toString();
}
/**
* @param hexStr 16进制
* @return byte[]
* @description 将16进制转换为二进制
* @date 2019/5/8 9:50
*/
public static byte[] parseHexStr2Byte(String hexStr)
{
if (hexStr.length() < 1)
{
return null;
}
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; 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;
}
/**
* @return java.lang.String
* @description 生成base64 编码后的AES128位密钥
* @date 2019/5/8 9:51
*/
public static String getAESKey()
{
KeyGenerator kg = null;
try
{
kg = KeyGenerator.getInstance("AES");
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
kg.init(128);// 要生成多少位,只需要修改这里即可128, 192或256
SecretKey sk = kg.generateKey();
byte[] b = sk.getEncoded();
String hexKey = parseByte2HexStr(b);
return hexKey;
}
/**
* @param base64Key base64编码后的 AES key
* @param text 待加密的字符串
* @return byte[] 加密后的byte[] 数组
* @description AES加密
* @date 2019/5/8 9:51
*/
public static byte[] getAESEncode(String base64Key, String text)
{
if (text == null)
{
return null;
}
byte[] raw = base64Key.getBytes(Charset.forName(ENCODING));
if (raw.length != 32)
{
throw new IllegalArgumentException("Invalid key size.");
}
byte[] encodeResult = null;
try
{
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
/**
* aes-cbc模式加密在加密和解密是需要一个初始化向量(Initialization Vector, IV),在每次加密之前或者解密之后,使用初始化向量与明文或密文异或。
*/
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(parseHexStr2Byte(base64Key)));
encodeResult = cipher.doFinal(text.getBytes(Charset.forName(ENCODING)));
}
catch (Exception e)
{
e.printStackTrace();
}
return encodeResult;
}
/**
* @param base64Key base64编码后的 AES key
* @param text 待解密的字符串
* @return byte[] 解密后的byte[] 数组
* @description AES解密
* @date 2019/5/8 9:51
*/
public static String getAESDecode(String base64Key, byte[] text)
{
if (null == text)
{
return null;
}
byte[] raw = base64Key.getBytes(Charset.forName(ENCODING));
if (raw.length != 32)
{
throw new IllegalArgumentException("Invalid key size.");
}
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = null;
byte[] original = null;
try
{
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(parseHexStr2Byte(base64Key)));
original = cipher.doFinal(text);
}
catch (Exception e)
{
e.printStackTrace();
}
return new String(original, Charset.forName(ENCODING));
}
}
测试代码:
public static void main(String[] args)
{
String text = "java并发编程实战";
//加密明文
String hexKey = AESUtil.getAESKey();
System.out.println("加密明文: " + hexKey);
//加密密文
byte[] encodeByte = AESUtil.getAESEncode(hexKey, text);
System.out.println("加密密文: " + AESUtil.parseByte2HexStr(encodeByte));
//解密
String decodeTest = AESUtil.getAESDecode(hexKey, encodeByte);
System.out.println("解密结果: " + decodeTest);
}
结果:
加密明文: 4A324B30F70EEB38382B1C950486215D
加密密文: 7C8C9F50BAFA244261D4793E857A9383C9740BCCA05A897ED2162ADD1CAF5306
解密结果: java并发编程实战
Process finished with exit code 0