简介
AES加密方式的全称是Advanced Encryption Standard,这里的Advanced当然是相对于DES来说的。AES加密根据其使用的密钥长度又细分成AES-128、AES-192和AES-256这三种AES加密方式,其中AES-128对应128bit密钥长度,AES-192对应192bit,AES-256对应256bit,从道理上说密钥长度越长,机密的安全等级就越高,但是密钥越长加解密对硬件的性能消耗就越厉害。
本文以AES-256为例来讲解AES加密方式在Java中的实现;以此类推可实现128、192。
废话不多说上代码:
package com.ytx.wallet;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
/**
* @author zhanghe
* @des AES加密算法util
* @date 2020-09-14
*/
public class AESUtil {
/**
* 加密算法
*/
private static final String EncryptAlgorithm = "AES";
/**
* 加密模式、填充方式
*/
private static final String Cipher_Mode = "AES/ECB/PKCS7Padding";
/**
* 编码
*/
private static final String Encode = "UTF-8";
/**
* 密钥长度(16-AES128、24-AES192、32-AES256)
*/
private static final int Secret_Key_Size = 32;
/**
* 密钥编码
*/
private static final String Key_Encode = "UTF-8";
/**
* 避免重复new生成多个BouncyCastleProvider对象,因为GC回收不了,会造成内存溢出
* 只在第一次调用decrypt()方法时才new 对象
*/
public static boolean initialized = false;
/**
* AES/ECB/PKCS7Padding 加密
*
* @param content
* @param key 密钥
* @return aes加密后 转base64
* @throws Exception
*/
public static String aesPKCS7PaddingEncrypt(String content, String key) throws Exception {
try {
initialize();
//声明一个Cipher对象
Cipher cipher = Cipher.getInstance(Cipher_Mode);
//获取key
byte[] realKey = getSecretKey(key);
//使用密钥初始化cipher
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(realKey, EncryptAlgorithm));
//进行加密操作,实际上执行的是Cipher的doFinal方法
byte[] data = cipher.doFinal(content.getBytes(Encode));
//对加密结果进行base64编码
String result = new Base64().encodeToString(data);
return result;
} catch (Exception e) {
e.printStackTrace();
throw new Exception("AES加密失败:content=" + content + " key=" + key);
}
}
/**
* AES/ECB/PKCS7Padding 解密
*
* @param content
* @param key 密钥
* @return 先转base64 再解密
* @throws Exception
*/
public static String aesPKCS7PaddingDecrypt(String content, String key) throws Exception {
try {
initialize();
//对密文进行base64解码
byte[] decodeBytes = Base64.decodeBase64(content);
//声明一个Cipher对象
Cipher cipher = Cipher.getInstance(Cipher_Mode);
//根据密钥种子生成key
byte[] realKey = getSecretKey(key);
//使用密钥初始化cipher,这里和加密操作的唯一区别是设置的MODE不一样
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(realKey, EncryptAlgorithm));
//进行加密操作,实际上执行的还是Cipher的doFinal方法
byte[] realBytes = cipher.doFinal(decodeBytes);
//获取原文
return new String(realBytes, Encode);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("AES解密失败:Aescontent = " + e.fillInStackTrace(), e);
}
}
/**
* 对密钥key进行处理:如密钥长度不够位数的则 以指定paddingChar 进行填充;
* 此处用空格字符填充,也可以 0 填充,具体可根据实际项目需求做变更
*
* @param key
* @return
* @throws Exception
*/
public static byte[] getSecretKey(String key) throws Exception {
//定义填充字符 可以是空格也可以是 '0' 此处使用 '0'
final byte paddingChar = '0';
//初始化指定字节密钥数组,密钥长度(16-AES128、24-AES192、32-AES256)
byte[] realKey = new byte[Secret_Key_Size];
//获取指定字符编码密钥数组
byte[] byteKey = key.getBytes(Key_Encode);
//位数不足填充处理
for (int i = 0; i < realKey.length; i++) {
if (i < byteKey.length) {
realKey[i] = byteKey[i];
} else {
realKey[i] = paddingChar;
}
}
return realKey;
}
/**
* BouncyCastle作为安全提供,防止我们加密解密时候因为jdk内置的不支持改模式运行报错。
*/
public static void initialize() {
if (initialized)
return;
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
public static void main(String[] args) throws Exception {
//此处以AES256为例
//密钥种子
String keyStr = "123456789012345678901234567890qq";
System.out.println("加密32位密钥种子:" + keyStr);
//加密前
String content = "this is encrypt content !";
System.out.println("加密原文: " + content);
//加密后
String encryptStr = aesPKCS7PaddingEncrypt(content, keyStr);
System.out.println("使用AES加密后:" + encryptStr);
//解密后
String decryptStr = aesPKCS7PaddingDecrypt(encryptStr, keyStr);
System.out.println("使用AES解密后:" + decryptStr);
}
}