密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。
这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一 [1] 。
该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijdael之名命之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 “Rhine doll”。)
AES的分组长度是128bit,三种可选密钥长度128bit,192bit和256bit,轮数分别为10、12和14
常见五中工作模式:
ECB (ElectronicCodebook,电子密码本)
优点:简单、可并行计算、误差不传递
缺点:不能隐藏明文模式(比如图像加密轮廓仍在)、主动攻击(改明文,后续内容不影响,只要误差不传递该缺点就存在)
用途:需要并行加密的应用
CBC (Cipher Block Chaining,密码分组链接)∶
优点:不容易主动攻击(误差传递)、适合长报文,是SSL、IPSec标准
缺点:无法并行、误差传递
用途:长报文传输,SSL和IPSec
CFB (CipherFeedback,密码反馈)︰
优点:不容易主动攻击(误差传递),分组转变为流模式,可加密小于分组数据缺点:无法并行、误差传递
OFB (OutputFeedback,输出反馈)︰
优点:分组转为流模式、可加密小于分组数据
缺点:主动攻击(改明文,后续内容不影响,只要误差不传递该缺点就存在)
用途:通信信道质量不高时使用,比如卫星通信
CTR (Counter,计数器模式)∶
描述:计算器模式不常见,在CTR模式中,有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文,相当于一次一密。这种加密方式简单快速,安全可靠,而且可以并行加密,但是在计算器不能维持很长的情况下,密钥只能使用一次。
优点:并行、一次一密、不传递误差
缺点:主动攻击(改明文,后续内容不影响,只要误差不传递该缺点就存在)
总结
分组模式: ECB、CBC和CTR;
流模式: CFB、OFB
传递误差: CBC、CFB
不传递误差: ECB、OFB和CTR
可并行: ECB、CTR
不可并行: CBC、OFB、CFB
我们输入的明文会被分割成大小相同的明文块,一个明文块大小为16字节、128位,如果最后一块小于16k那就需要涉及填充和链加密模式了。
假设明文块为:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
上述明文块按照顺序,从上往下,从左到右变换成以下明文矩阵
0 4 8 12
1 5 9 13
2 6 10 14
3 7 11 15
每个位置占8位,第n个字节对应的位置(i , j)可以按以下方式计算
i = n%4;
j = n/4;(向下取整)
n = i + 4j;
同样的,密钥也是16字节 128位
其中的明文矩阵为字节表示的4x4的矩阵,而状态矩阵是将明文矩阵转为十六进制后的矩阵。
一个明文块16k 转变成 4 X 4(16进制)的矩阵,与子密钥生成的初始矩阵4 X 4(16进制),做一个异或。
由于后续要做10轮加密操作,每轮都要使用一个4X4的矩阵。那么单单一个子密钥生成的4X4的矩阵自然是不够的,所以需要对密钥做扩展。也就是把4X4字节的子密钥 ——> 4X43轮密钥,从4列扩展为44列(这里需要注意的是: 初始变换已经用了第0列到第三列,所以10轮加密从第4列开始取)
比如第i轮(i ∈ [1,10])加密,使用第4i到 4i + 3列的数据作为子密钥矩阵。第1轮,使用第4列,到第4 + 3列,最后一轮使用第40列,到43列作为密钥矩阵。
假设i是我们要生成的扩展子密钥列数,如果 i 为四的倍数,那么该列:Wi = Wi-4 ⊕ T(Wi-1)
其中T函数表示三个操作:
将Wi-1列赋值到 Wi上,列【b0, b1, b2 ,b3】更改为 【b1 , b2 , b3 , b0】(注意,这里是列,应该是竖起来的,我这里为了方便所以是横的)
使用S盒代换,与下面的S_Box一致
与同轮(第一轮和常量矩阵第一列 第二轮和常量矩阵第二列),给定的矩阵进行同列⊕。可以看出每列对应的i为:4 8 12 16 20 24 28 32 36 40
当i不是四的倍数时:Wi = Wi-4 ⊕ Wi-1,只做一个异或。
S-box的替换。比如00,表示用 第0行 第0列 对应的是0x63 ,所以00替换成63。 这里的0x表示的是十六进制。
除开第一行,第二行往左移动一位,第二行往左移动第二位,第三行往左移动第三位。(只算明文列数4–也就是128字节)
左乘一个给定的 4 X 4矩阵,进行单个结果有限域上的二元运算(GF2^8)
可以点这里详细了解X乘运算.
与密钥扩展得到的10轮密钥中的一组逐字节做异或(与对应位置上的数据做一个异或)。比如明文状态矩阵为4列(即明文块占128位 16字节),第 i 轮选取轮密钥的W[ 4 * i ] ~ W[ 4* i + 3]。 比如第一轮 i=1.那么取的轮密钥矩阵中的是4 ~ 7列。
与前九轮相比 最后一轮没有列混合,其他三位操作一样。
然后将得到的密文矩阵转为密文状态矩阵再转为密文输出。
JDK链接,有兴趣的自己详细了解。下文只介绍简单使用涉及到类以及方法。
该类提供了一个对称密钥生成器的功能。
//生成一个AES算法的密钥生成器
KeyGenerator kg = KeyGenerator.getInstance("AES");
//使用给定字节数组生成安全随机密码对象,并用该对象初始化该密钥生成器(生成密钥长度为128位)
kg.init(128, new SecureRandom(rule.getBytes("UTF-8")));
//生成一个种子密钥。
SecretKey ruleKey = kg.generateKey();
该接口的目的是为所有密钥(不同算法的密钥)接口分组。
它可以用于从字节数组构造一个SecretKey 。
//从给定的字节数组构造一个aes密钥 skCode为给定的字节数组 按AES算法生成密钥
SecretKey aesKey = new SecretKeySpec(skCode , "AES");
该类提供主要的加密、解密操作。
//获取实例
Cipher cp = Cipher.getInstance("AES");
//用密钥初始化此密码 其中前一个参数表示加密(设置为:Cipher.DECRYPT_MODE就是解密) aesKey为密钥
cp.init(Cipher.ENCRYPT_MODE , aesKey);
//需要加密的字符串的字节数组
byte[] contenCode = text.getBytes("UTF-8");
//加密后得到的是字节数组
byte[] enCode = cp.doFinal(contenCode);
/*
* @description 加解密整合到一个方法中来
* @author 三文鱼
* @date 9:41 2022/3/18
* @param rule 自己设置的密钥
* @param text 需要加密的明文或者解密的密文
* @param encrypt true表示加密 false表示解密
* @return java.lang.String 返回加密或者解密过的字符串
**/
public static String getContrary(String rule , String text , boolean encrypt ) throws Exception {
String result = "";
try{
//生成一个AES算法的密钥生成器
KeyGenerator kg = KeyGenerator.getInstance("AES");
//使用给定的随机源(可以看作你自己设置的密码,但对于程序而言,你输入的只是一个生成密钥的”种子“)
// 初始化该密钥生成器(生成密钥长度为128位)
kg.init(128, new SecureRandom(rule.getBytes("UTF-8")));
//生成一个种子密钥。
SecretKey ruleKey = kg.generateKey();
//获取其主要编码格式的密钥
byte[] skCode = ruleKey.getEncoded();
//从给定的字节数组构造一个aes密钥
SecretKey aesKey = new SecretKeySpec(skCode , "AES");
//该类提供加密和解密的加密密码的功能。 它构成了Java加密扩展(JCE)框架的核心。
Cipher cp = Cipher.getInstance("AES");
//判断是否是加密
if(encrypt) {
//用密钥初始化
cp.init(Cipher.ENCRYPT_MODE , aesKey);
byte[] contenCode = text.getBytes("UTF-8");
//加密
byte[] enCode = cp.doFinal(contenCode);
//按照base64编码
result = new BASE64Encoder().encode(enCode);
}else{
cp.init(Cipher.DECRYPT_MODE , aesKey);
//将密文按照base64解码
byte[] enCode = new BASE64Decoder().decodeBuffer(text);
//解密生成明文字节数组
byte[] decryptCode = cp.doFinal(enCode);
//明文字节数组生成明文
result = new String(decryptCode , "UTF-8");
}
return result;
}catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
可厉害的土豆: AES加密过程详解| 对称加密| Rijndael-128| 密码学| 信息安全
我有一个小脑瓜 : 现代密码学|AES加密算法
百度百科: AES
百度文库: AES加密模式优缺点及用途