package cn.codesensi.util;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
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.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;
public class AESUtil {
private static final String ALGORITHM = "AES";
// private static final String AES_CBC_PADDING = "AES/CBC/PKCS5PADDING";
private static final String AES_CBC_PADDING = "AES/CBC/PKCS7PADDING";
// private static final String AES_ECB_PADDING = "AES/ECB/PKCS5PADDING";
private static final String AES_ECB_PADDING = "AES/ECB/PKCS7PADDING";
// PKCS5PADDING必需
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 生成密钥
*
* @param size 密钥位数,可选128/192/256,越大越安全,但效率越低
* @param seed 加密强随机数种子,同一个种子生成的密钥相同
* @return 密钥
*/
public static byte[] getKey(Integer size, byte[] seed) throws Exception {
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
// 加密强随机数
SecureRandom sr = new SecureRandom();
sr.setSeed(seed);
kg.init(size, sr);
SecretKey sk = kg.generateKey();
return sk.getEncoded();
}
/**
* Aes加密(CBC工作模式)
*
* @param key 密钥,长度可选16/24/32
* @param iv 初始化向量,长度必须等于16
* @param data 明文
* @return 密文
*/
public static byte[] encodeCBC(byte[] key, byte[] iv, byte[] data) throws Exception {
// 获取SecretKey对象
SecretKeySpec sks = new SecretKeySpec(key, ALGORITHM);
// 获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
// 初始化向量
IvParameterSpec ips = new IvParameterSpec(iv);
// 用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
cipher.init(Cipher.ENCRYPT_MODE, sks, ips);
// 执行加密操作
return cipher.doFinal(data);
}
/**
* Aes解密(ECB工作模式)
*
* @param key 密钥,长度可选16/24/32
* @param iv 初始化向量,长度必须等于16
* @param data 密文
* @return 明文
*/
public static byte[] decodeCBC(byte[] key, byte[] iv, byte[] data) throws Exception {
// 获取SecretKey对象
SecretKeySpec sks = new SecretKeySpec(key, ALGORITHM);
// 获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
// 初始化向量
IvParameterSpec ips = new IvParameterSpec(iv);
// 用密钥和一组算法参数规范初始化此Cipher对象(解密模式)
cipher.init(Cipher.DECRYPT_MODE, sks, ips);
// 执行解密操作
return cipher.doFinal(data);
}
/**
* Aes加密(ECB工作模式),不要IV
*
* @param key 密钥,长度可选16/24/32
* @param data 明文
* @return 密文
*/
public static byte[] encodeECB(byte[] key, byte[] data) throws Exception {
// 获取SecretKey对象
SecretKeySpec sks = new SecretKeySpec(key, ALGORITHM);
// 获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(AES_ECB_PADDING);
// 用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
cipher.init(Cipher.ENCRYPT_MODE, sks);
// 执行加密操作
return cipher.doFinal(data);
}
/**
* Aes解密(ECB工作模式),不要IV
*
* @param key 密钥,长度可选16/24/32
* @param data 密文
* @return 明文
*/
public static byte[] decodeECB(byte[] key, byte[] data) throws Exception {
// 获取SecretKey对象
SecretKeySpec sks = new SecretKeySpec(key, ALGORITHM);
// 获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(AES_ECB_PADDING);
// 用密钥和一组算法参数规范初始化此Cipher对象(解密模式)
cipher.init(Cipher.DECRYPT_MODE, sks);
// 执行解密操作
return cipher.doFinal(data);
}
public static void main(String[] args) throws Exception {
// 定义原始数据
String seed = "abcdefg123";// 加密强随机数种子,同一个种子生成的密钥相同
byte[] seedBytes = seed.getBytes(StandardCharsets.UTF_8);
System.out.println("用于生成密钥的种子:" + seed);
Integer size = 256;// 密钥位数 可选128、192、256 越大越安全,但效率越低
System.out.println("密钥位数:" + size);
String iv = "12345678abcdefgh";// 初始化向量,长度必须等于16
byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
System.out.println("CBC加密偏移量:" + iv);
String original = "让我们测试一下叭";
byte[] data = original.getBytes(StandardCharsets.UTF_8);
System.out.println("待加密的数据:" + original);
System.out.println();
System.out.println("------------------生成密钥------------------");
byte[] keyBytes = getKey(size, seedBytes);
System.out.println("生成的密钥转Base64字符串:" + Base64.getEncoder().encodeToString(keyBytes));
System.out.println();
System.out.println("------------------AES之ECB加密转base64------------------");
byte[] encodeECBBytes = encodeECB(keyBytes, data);
String encodeECB = Base64.getEncoder().encodeToString(encodeECBBytes);
System.out.println("ECB加密后转Base64的数据:" + encodeECB);
System.out.println();
System.out.println("------------------AES之ECB解密------------------");
// 将Base64编码后的解密结果转换回去
byte[] decodeECBBytes = Base64.getDecoder().decode(encodeECB);
byte[] decodeECB = decodeECB(keyBytes, decodeECBBytes);
System.out.println("ECB解密后转字符串数据:" + new String(decodeECB, StandardCharsets.UTF_8));
System.out.println();
System.out.println("------------------AES之CBC加密转base64------------------");
byte[] encodeCBCByte = encodeCBC(keyBytes, ivBytes, data);
String encodeCBC = Base64.getEncoder().encodeToString(encodeCBCByte);
System.out.println("CBC加密后转Base64的数据:" + encodeCBC);
System.out.println();
System.out.println("------------------AES之CBC解密------------------");
// 将Base64编码后的解密结果转换回去
byte[] decodeCCBBytes = Base64.getDecoder().decode(encodeCBC);
byte[] decodeStr = decodeCBC(keyBytes, ivBytes, decodeCCBBytes);
System.out.println("CBC解密后转字符串数据:" + new String(decodeStr, StandardCharsets.UTF_8));
}
}
评论