AES简介
1、高级加密标准(AES,Advanced Encryption Standard)作为传统对称加密标准DES的替代者,美国国家标准与技术研究所(NIST)于1997年提出征集该算法的公告。
2、1999年3月22日,NIST从15个候选算法中选出 5个算法进入下一轮。在2000年10月2日,以
安全性、性能、大小、实现特点等标准而最
终选定由比利时人的开发的Rijndael算法,
并于2001年正式发布AES标准。
流程图
AES的基本结构(准备阶段)
- 典型的SPN(代换–置换网络)结构
- AES又是分组密码,具体过程:将明文分为长度相等的组 (长度固定为128位,即每组16字节),每组逐次加密直到加密完整个明文。
- 密钥长度位下列三种:
- AES的处理单位是字节,128位的输入明文分组P和输入密钥K都被分成16个字节,分别记为:
P=P0P1…P15
K=K0K1…K15
- 明文分组用以字节为单位的正方形矩阵描述,称为状态矩阵。(规则:矩阵中字节的排列为从上到下、从左到右依次排 列,矩阵的每一列被称为1个32比特字)
整体流程
密钥扩充(加密前奏)
将密钥扩充,需要得到四十个新列,分组得到轮密钥。
CASE1:当W[i]中i为4的整数倍时,需要用T函数进行变换W[i-1],然后用W[i-1]与W[i-4]进行异或,最后得出W[i]
(Ps:T函数由3部分组成:字循环、字节代换和轮常量异或,这三个过程时T函数变换的充分必要条件)
CASE2:当W[i]中i不是4的整数倍时,只需要将W[i-1]与W[i-4]进行异或,最后得出W[i]
重复相同的流程所处所有的W
核心流程
轮函数示意图
-
字节代换(SubBytes 非线性)
定义了S盒:(S盒是由16*16的字节组成的矩阵,S盒不可逆)
我们通过S盒将明文分组中的元素逐个进行替换。
例如: 明文分组为:
第一个元素19,在S盒中寻找第1行第9列的元素即可,按照上述S盒找出为 2D 。 -
行移位 (ShiftRows 线性):为密码系统提供了扩展性
是一个简单的左循环位移操作。
规则 : 第n行就位移n字节
例如:
位移前
位移后
-
列混合 (MixColumns 非线性):为密码系统提供了扩展性
简单的矩阵相乘操作
将以下状态矩阵按列与固定矩阵相乘
得到相乘的结果换到原来的列位置上
然后逐列依次进行 -
轮密钥加
我们将密钥扩展得到的轮密钥与我们的明文分组矩阵进行逐列的异或操作,将得到结果替换
替换之后
之后便进行流程的循环,不同的AES-n位循环的次数都不同,最终得到密文
-
所有轮数的流程图
AES算法的实现
密钥扩展
//密钥对应的扩展数组
static int w[44];
/**
* 扩展密钥,结果是把w[44]中的每个元素初始化
*/
static void extendKey(char *key) {
for(int i = 0; i < 4; i++)
w[i] = getWordFromStr(key + i * 4);
for(int i = 4, j = 0; i < 44; i++) {
if( i % 4 == 0) {
w[i] = w[i - 4] ^ T(w[i - 1], j);
j++;//下一轮
}else {
w[i] = w[i - 4] ^ w[i - 1];
}
}
}
/**
* 常量轮值表
*/
static const int Rcon[10] = {
0x01000000, 0x02000000,
0x04000000, 0x08000000,
0x10000000, 0x20000000,
0x40000000, 0x80000000,
0x1b000000, 0x36000000 };
/**
* 密钥扩展中的T函数
*/
static int T(int num, int round) {
int numArray[4];
splitIntToArray(num, numArray);
leftLoop4int(numArray, 1);//字循环
//字节代换
for(int i = 0; i < 4; i++)
numArray[i] = getNumFromSBox(numArray[i]);
int result = mergeArrayToInt(numArray);
return result ^ Rcon[round];
}
字节代换
/**
* 根据索引,从S盒中获得元素
*/
static int getNumFromSBox(int index) {
int row = getLeft4Bit(index);
int col = getRight4Bit(index);
return S[row][col];
}
/**
* 字节代换
*/
static void subBytes(int array[4][4]){
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
array[i][j] = getNumFromSBox(array[i][j]);
}
行位移
/**
* 将数组中的元素循环左移step位
*/
static void leftLoop4int(int array[4], int step) {
int temp[4];
for(int i = 0; i < 4; i++)
temp[i] = array[i];
int index = step % 4 == 0 ? 0 : step % 4;
for(int i = 0; i < 4; i++){
array[i] = temp[index];
index++;
index = index % 4;
}
}
/**
* 行移位
*/
static void shiftRows(int array[4][4]) {
int rowTwo[4], rowThree[4], rowFour[4];
//复制状态矩阵的第2,3,4行
for(int i = 0; i < 4; i++) {
rowTwo[i] = array[1][i];
rowThree[i] = array[2][i];
rowFour[i] = array[3][i];
}
//循环左移相应的位数
leftLoop4int(rowTwo, 1);
leftLoop4int(rowThree, 2);
leftLoop4int(rowFour, 3);
//把左移后的行复制回状态矩阵中
for(int i = 0; i < 4; i++) {
array[1][i] = rowTwo[i];
array[2][i] = rowThree[i];
array[3][i] = rowFour[i];
}
}
列混合
/**
* 列混合要用到的矩阵
*/
static const int colM[4][4] = {
2, 3, 1, 1,
1, 2, 3, 1,
1, 1, 2, 3,
3, 1, 1, 2 };
static int GFMul2(int s) {
int result = s << 1;
int a7 = result & 0x00000100;
if(a7 != 0) {
result = result & 0x000000ff;
result = result ^ 0x1b;
}
return result;
}
static int GFMul3(int s) {
return GFMul2(s) ^ s;
}
/**
* GF上的二元运算
*/
static int GFMul(int n, int s) {
int result;
if(n == 1)
result = s;
else if(n == 2)
result = GFMul2(s);
else if(n == 3)
result = GFMul3(s);
else if(n == 0x9)
result = GFMul9(s);
else if(n == 0xb)//11
result = GFMul11(s);
else if(n == 0xd)//13
result = GFMul13(s);
else if(n == 0xe)//14
result = GFMul14(s);
return result;
}
/**
* 列混合
*/
static void mixColumns(int array[4][4]) {
int tempArray[4][4];
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
tempArray[i][j] = array[i][j];
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++){
array[i][j] = GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j])
^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);
}
}
轮密钥加
/**
* 轮密钥加
*/
static void addRoundKey(int array[4][4], int round) {
int warray[4];
for(int i = 0; i < 4; i++) {
splitIntToArray(w[ round * 4 + i], warray);
for(int j = 0; j < 4; j++) {
array[j][i] = array[j][i] ^ warray[j];
}
}
}
AES加密函数
/**
* 参数 p: 明文的字符串数组。
* 参数 plen: 明文的长度。
* 参数 key: 密钥的字符串数组。
*/
void aes(char *p, int plen, char *key){
int keylen = strlen(key);
if(plen == 0 || plen % 16 != 0) {
printf("明文字符长度必须为16的倍数!\n");
exit(0);
}
if(!checkKeyLen(keylen)) {
printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
exit(0);
}
extendKey(key);//扩展密钥
int pArray[4][4];
for(int k = 0; k < plen; k += 16) {
convertToIntArray(p + k, pArray);
addRoundKey(pArray, 0);//一开始的轮密钥加
for(int i = 1; i < 10; i++){
//前9轮
subBytes(pArray);//字节代换
shiftRows(pArray);//行移位
mixColumns(pArray);//列混合
addRoundKey(pArray, i);
}
//第10轮
subBytes(pArray);//字节代换
shiftRows(pArray);//行移位
addRoundKey(pArray, 10);
convertArrayToStr(pArray, p + k);
}
}
AES解密函数
/**
* 参数 c: 密文的字符串数组。
* 参数 clen: 密文的长度。
* 参数 key: 密钥的字符串数组。
*/
void deAes(char *c, int clen, char *key) {
int keylen = strlen(key);
if(clen == 0 || clen % 16 != 0) {
printf("密文字符长度必须为16的倍数!现在的长度为%d\n",clen);
exit(0);
}
if(!checkKeyLen(keylen)) {
printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
exit(0);
}
extendKey(key);//扩展密钥
int cArray[4][4];
for(int k = 0; k < clen; k += 16) {
convertToIntArray(c + k, cArray);
addRoundKey(cArray, 10);
int wArray[4][4];
for(int i = 9; i >= 1; i--) {
deSubBytes(cArray);
deShiftRows(cArray);
deMixColumns(cArray);
getArrayFrom4W(i, wArray);
deMixColumns(wArray);
addRoundTowArray(cArray, wArray);
}
deSubBytes(cArray);
deShiftRows(cArray);
addRoundKey(cArray, 0);
convertArrayToStr(cArray, c + k);
}
}