AES加解密简单实现
//密钥
private static String secretKey = "12345678123456781234567812345678";
//加密串字符编码方式
private static String charset = "utf8";
//偏移量
private static int offset = 16;
//算法(AES)、工作模式(CBC)、填充方式(PKCS5Padding)
private static String transformation = "AES/CBC/PKCS5Padding";
//算法
private static String algorithm = "AES";
/**
*@desc: 加密
*
*@date: 10:19
*/
public static String encrypt(String content){
return encrypt(content,secretKey);
}
/**
*@desc: 解密
*
*@date: 10:18
*/
public static String decrypt(String content){
return decrypt(content,secretKey);
}
/**
*@desc: 带密钥加密
*
*@date: 10:19
*/
public static String encrypt(String content,String secretKey){
try {
Cipher cipher = getCipher(Cipher.ENCRYPT_MODE,secretKey);
byte[] bytes = content.getBytes(charset);
byte[] res = cipher.doFinal(bytes);
return Base64.getEncoder().encodeToString(res);
} catch (Exception e) {
log.error("AES encrypt failed!reason:{}",e);
}
return null;
}
/**
*@desc: 带密钥解密
*
*@date: 10:20
*/
public static String decrypt(String content,String secretKey){
try {
Cipher cipher = getCipher(Cipher.DECRYPT_MODE,secretKey);
byte[] res = cipher.doFinal(Base64.getDecoder().decode(content));
return new String(res);
} catch (Exception e) {
log.error("AES decrypt failed!reason:{}",e);
}
return null;
}
/**
*@desc: 获取Cipher密码管理器
*
*@date: 11:04
*/
public static Cipher getCipher(int type,String secretKey) throws Exception {
SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(),algorithm);
IvParameterSpec iv = new IvParameterSpec(secretKey.getBytes(),0,offset);
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(type,sks,iv);
return cipher;
}
public static void main(String[] args) {
String content = "Admin123Admin123Admin123Admin123Admin123Admin123Admin123Admin123Admin123Admin123";
String encryptString = encrypt(content);
String decryptString = decrypt(encryptString);
System.out.println("encrypt===>"+encryptString+"\ndecrypt===>"+decryptString);
}
下面是帮助理解AES加解密算法的源码方法:
这个方法在Cipher类中,将var0转换为我们使用的算法(AES)、工作模式(CBC)、填充方式(PKCS5Padding)
private static List getTransforms(String var0) throws NoSuchAlgorithmException {
String[] var1 = tokenizeTransformation(var0);
String var2 = var1[0];
String var3 = var1[1];
String var4 = var1[2];
if (var3 != null && var3.length() == 0) {
var3 = null;
}
if (var4 != null && var4.length() == 0) {
var4 = null;
}
if (var3 == null && var4 == null) {
Cipher.Transform var6 = new Cipher.Transform(var2, "", (String)null, (String)null);
return Collections.singletonList(var6);
} else {
ArrayList var5 = new ArrayList(4);
var5.add(new Cipher.Transform(var2, "/" + var3 + "/" + var4, (String)null, (String)null));
var5.add(new Cipher.Transform(var2, "/" + var3, (String)null, var4));
var5.add(new Cipher.Transform(var2, "//" + var4, var3, (String)null));
var5.add(new Cipher.Transform(var2, "", var3, var4));
return var5;
}
这俩方法在AESCipher和CipherCore类中,可以看出PKCS5Padding填充块大小blockSize为固定16
protected AESCipher(int var1) {
this.core = new CipherCore(new AESCrypt(), 16);
this.fixedKeySize = var1;
}
CipherCore(SymmetricCipher var1, int var2) {
this.blockSize = var2;
this.unitBytes = var2;
this.diffBlocksize = var2;
this.buffer = new byte[this.blockSize * 2];
this.cipher = new ElectronicCodeBook(var1);
this.padding = new PKCS5Padding(this.blockSize);
}
此方法在CipherCore 类中,根据工作模式设置相应的密码管理器
void setMode(String var1) throws NoSuchAlgorithmException {
if (var1 == null) {
throw new NoSuchAlgorithmException("null mode");
} else {
String var2 = var1.toUpperCase(Locale.ENGLISH);
if (!var2.equals("ECB")) {
SymmetricCipher var3 = this.cipher.getEmbeddedCipher();
if (var2.equals("CBC")) {
this.cipherMode = 1;
this.cipher = new CipherBlockChaining(var3);
} else if (var2.equals("CTS")) {
this.cipherMode = 6;
this.cipher = new CipherTextStealing(var3);
this.minBytes = this.blockSize + 1;
this.padding = null;
} else if (var2.equals("CTR")) {
this.cipherMode = 5;
this.cipher = new CounterMode(var3);
this.unitBytes = 1;
this.padding = null;
} else if (var2.equals("GCM")) {
if (this.blockSize != 16) {
throw new NoSuchAlgorithmException("GCM mode can only be used for AES cipher");
}
this.cipherMode = 7;
this.cipher = new GaloisCounterMode(var3);
this.padding = null;
} else if (var2.startsWith("CFB")) {
this.cipherMode = 2;
this.unitBytes = getNumOfUnit(var1, "CFB".length(), this.blockSize);
this.cipher = new CipherFeedback(var3, this.unitBytes);
} else if (var2.startsWith("OFB")) {
this.cipherMode = 3;
this.unitBytes = getNumOfUnit(var1, "OFB".length(), this.blockSize);
this.cipher = new OutputFeedback(var3, this.unitBytes);
} else {
if (!var2.equals("PCBC")) {
throw new NoSuchAlgorithmException("Cipher mode: " + var1 + " not found");
}
this.cipherMode = 4;
this.cipher = new PCBC(var3);
}
}
}
}
此方法在Cipher类中,设置填充方式
void setModePadding(CipherSpi var1) throws NoSuchAlgorithmException, NoSuchPaddingException {
if (this.mode != null) {
var1.engineSetMode(this.mode);
}
if (this.pad != null) {
var1.engineSetPadding(this.pad);
}
}
此方法在IvParameterSpec类中,可以看出向量不能小于偏移量长度
public IvParameterSpec(byte[] var1, int var2, int var3) {
if (var1 == null) {
throw new IllegalArgumentException("IV missing");
} else if (var1.length - var2 < var3) {
throw new IllegalArgumentException("IV buffer too short for given offset/length combination");
} else if (var3 < 0) {
throw new ArrayIndexOutOfBoundsException("len is negative");
} else {
this.iv = new byte[var3];
System.arraycopy(var1, var2, this.iv, 0, var3);
}
}
在AESCrypt类和AESConstants 接口中,可以判断出密钥长度是否合理
static final boolean isKeySizeValid(int var0) {
for(int var1 = 0; var1 < AES_KEYSIZES.length; ++var1) {
if (var0 == AES_KEYSIZES[var1]) {
return true;
}
}
return false;
}
//AES要块大小,以及AES密钥要求的长度类型
interface AESConstants {
int AES_BLOCK_SIZE = 16;
int[] AES_KEYSIZES = new int[]{16, 24, 32};
}
此方法在CipherCore类中,可以判断出向量长度是否合理
else if (var3 instanceof IvParameterSpec) {
var7 = ((IvParameterSpec)var3).getIV();
if (var7 == null || var7.length != this.blockSize) {
throw new InvalidAlgorithmParameterException("Wrong IV length: must be " + this.blockSize + " bytes long");
}
}