1.AES简介
AES的全称是Advanced Encryption Standard,意思是高级加密标准。它的出现主要是为了取代DES加密算法的,因为我们都知道DES算法的密钥长度是56Bit,因此算法的理论安全强度是2的56次方。但二十世纪中后期正是计算机飞速发展的阶段,元器件制造工艺的进步使得计算机的处理能力越来越强,虽然出现了3DES的加密方法,但由于它的加密时间是DES算法的3倍多,64Bit的分组大小相对较小,所以还是不能满足人们对安全性的要求。于是1997年1月2号,美国国家标准技术研究所宣布希望征集高级加密标准,用以取代DES。AES也得到了全世界很多密码工作者的响应,先后有很多人提交了自己设计的算法。最终有5个候选算法进入最后一轮:Rijndael,Serpent,Twofish,RC6和MARS。最终经过安全性分析、软硬件性能评估等严格的步骤,Rijndael算法获胜。
在密码标准征集中,所有AES候选提交方案都必须满足以下标准:
- 分组大小为128位的分组密码。
- 必须支持三种密码标准:128位、192位和256位。
- 比提交的其他算法更安全。
- 在软件和硬件实现上都很高效。
AES密码与分组密码Rijndael基本上完全一致,Rijndael分组大小和密钥大小都可以为128位、192位和256位。然而AES只要求分组大小为128位,因此只有分组长度为128Bit的Rijndael才称为AES算法。本文只对分组大小128位,密钥长度也为128位的Rijndael算法进行分析。密钥长度为192位和256位的处理方式和128位的处理方式类似,只不过密钥长度每增加64位,算法的循环次数就增加2轮,128位循环10轮、192位循环12轮、256位循环14轮。
2.AES具体数学知识
略....感兴趣同学可以自行查资料
3.AES加解密重要构成
1.密钥
密钥是AES算法实现加密和解密的根本。对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。AES支持三种长度的密钥:128位,192位,256位。平时大家所说的AES128,AES192,AES256,实际上就是指的AES算法对不同长度密钥的使用。
2.填充
要想了解填充的概念,我们先要了解AES的分组加密特性。什么是分组加密呢?我们来看看下面这张图:AES算法在对明文加密的时候,并不是把整个明文一股脑加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度128bit。这些明文块经过AES加密器的复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密结果。假如一段明文长度是192bit,如果按每128bit一个明文块来拆分的话,第二个明文块只有64bit,不足128bit。这时候怎么办呢?就需要对明文块进行填充(Padding)。
填充涉及以下三种填充模式:
NoPadding:
不做任何填充,但是要求明文必须是16字节的整数倍。
PKCS5Padding(默认):
如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6}
ISO10126Padding:
如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字节,最后一个字符值等于缺少的字符数,其他字符填充随机数。比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为{1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
4.Java代码Demo
接口api代码如下:
controller层:
service接口:
impl实现类:
工具类:
package com.example.demo.utils;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Encoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
@Component
public class AESUtil {
private static final String IV = "3412566146136412";
private static final String ENCODING = "UTF-8";
private static final String SECRET_KEY = "1234234234234112";
/**
* AES Decrypt Method
*
* @param ciphertext the text need to decrypt
* @return cleartext
* */
public static String decrypt(String ciphertext) {
byte[] buffer;
byte[] bytes = Base64.getDecoder().decode(ciphertext);
IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
SecretKeySpec secretKeySpec = new SecretKeySpec(AESUtil.SECRET_KEY.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE,secretKeySpec,ivParameterSpec);
buffer = cipher.doFinal(bytes);
return new String(buffer,ENCODING);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* AES Encrypt Method
*
* @param cleartext the text need to decrypt
* @return ciphertext
* */
public static String encrypt(String cleartext){
try{
byte[] raw = AESUtil.SECRET_KEY.getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(AESUtil.IV.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivParameterSpec);
byte[] bytes = cipher.doFinal(cleartext.getBytes(StandardCharsets.UTF_8));
return new BASE64Encoder().encode(bytes);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
return null;
}
}
测试类:
得到结果如下:
启动服务,我们用postman验证
前方介绍文字摘自知乎:密码学基础:AES加密算法 - 知乎
什么是AES加密?详解AES加密算法原理流程 - 知乎
代码原创手打不易 ,谢谢关注