AES加密解密与代码实现详解
先搞定 AES 算法,基本变换包括 SubBytes(字节替代)、ShiftRows(行移 位)、MixColumns(列混淆)、AddRoundKey(轮密钥加) 其算法一般描述为 明文及密钥的组织排列方式 ByteSubstitution(字节替代) 非线性的字节替代,单独处理每个字节: 求该字节在有限域 GF(28)上的乘法逆,“0“被映射为自身,即对于α∈GF(28), 求 β∈GF(28), 使得 α·β=β·α=1mod(x8+x4+x2+x+1)。 对上一步求得的乘法逆作仿射变换 yi=xi + x(i+4)mod8 + x(i+6)mod8 + x(i+7)mod8 + ci (其中 ci是 6310即 011000112的第 i 位),用矩阵表示为 本来打算把求乘法逆和仿射变换算法敲上去,最后还是放弃了.直接打置换表 下面是逆置换表,解密时使用 这里遇到问题了, 本来用纯 c 初始化数组很正常, 封装成类以后发现不能初始化, 不管是声明、构造函数都无法初始化,百歌谷度了一通后没有任何答案,无奈只 能在构造函数中声明一个局部变量数组并初始化,然后用 memcpy,(成员变 量名为 Sbox/InvSbox,局部变量名 sBox/invsBox) ShiftRows(行移位变换) 行移位变换完成基于行的循环位移操作,变换方法: 即行移位变换作用于行上,第 0 行不变,第 1 行循环左移 1 个字节,第 2 行循 环左移 2 个字节,第 3 行循环左移 3 个字节。 MixColumns(列混淆变换) 逐列混合,方法: b(x) = (03·x3 + 01·x2 + 01·x + 02) · a(x) mod(x4 + 1) 其中 FFmul 为有限域 GF(28)上的乘法,标准算法应该是循环 8 次(b 与 a 的 每一位相乘,结果相加),但这里只用到最低 2 位,解密时用到的逆列混淆也 只用了低 4 位,所以在这里高 4 位的运算是多余的,只计算低 4 位。 AddRoundKey(轮密钥加变换) 简单来说就是逐字节相加,有限域 GF(28)上的加法是模 2 加法,即异或 void AES::AddRoundKey(unsigned charchar state[][4], unsigned charchar k[][4]) { intint r,c; for(c=0; c4; c++) { for(r=0; r4; r++) { state[r][c] ^= k[r][c]; } } } KeyExpansionKeyExpansion(密钥扩展)(密钥扩展) 将输入的密钥扩展为 11 组 128 位密钥组,其中第 0 组为输入密钥本身 其后第 n 组第 i 列 为 第 n-1 组第 i 列 与 第 n 组第 i-1 列之和(模 2 加法, 1= i =3) 对于每一组 第一列即 i=0,有特殊的处理 将前一列即第 n-1 组第 3 列的 4 个字节循环左移 1 个字节, 并对每个字节进行字节替代变换 SubBytes 将第一行(即第一个字节)与轮常量 rc[n]相加 最后再与前一组该列相加 void AES::KeyExpansion(unsigned charchar* key, unsigned charchar w[][4][4]) { intint i,j,r,c; unsigned charchar rc[] = {0 x01, 0 x02, 0 x04, 0 x08, 0 x10, 0 x20, 0 x40, 0 x80, 0 x1b, 0 x36}; for(r=0; r4; r++) { for(c=0; c4; c++) { w[0][r][c] = key[r+c*4]; } } for(i=1; i=10; i++) { for(j=0; j4; j++) { unsigned charchar t[4]; for(r=0; r4; r++) { t[r] = j ? w[i][r][j-1] : w[i-1][r][3]; } if(j == 0) { unsigned charchar temp = t[0]; for(r=0; r3; r++) { t[r] = Sbox[t[(r+1)%4]]; } t[3] = Sbox[temp]; t[0] ^= rc[i-1]; } for(r=0; r4; r++) { w[i][r][j] = w[i-1][r][j] ^ t[r]; } } } } 解密的基本运算解密的基本运算 AES 解密算法与加密不同,基本运算中除了 AddRoundKey(轮密钥加)不变 外,其余的都需要进行逆变换,即 InvSubBytes(逆字节替代)、InvShiftRows(逆行移位)、InvMixColumns (逆列混淆) 加密过程加密过程 先将输入的明文按列序组合成 4*4 的矩阵, 直接与第 0 组密钥 (即输入的密钥) 相加(异或),作为轮加密的输入 然后循环 10 次进行 SubBytes、ShiftRows、MixColumns、AddRoundKey 运算,最后恢复原序列 需要注意的是最后一轮并不进行 MixColumns(列混淆变换) unsigned charchar* AES::Cipher(unsigned charchar* ) { unsigned charchar state[4][4]; intint i,r,c; for(r=0; r4; r++){ for(c=0; c4 ;c++) { state[r][c] = [c*4+r]; } } AddRoundKey(state,w[0]); for(i=1; i=10; i++){ SubBytes(state); ShiftRows(state); if(i!=10)MixColumns(state); AddRoundKey(state,w[i]); } for(r=0; r4; r++) { for(c=0; c4 ;c++){ [c*4+r] = state[r][c]; } } return ; } 解密过程解密过程 unsigned charchar* AES::InvCipher(unsigned charchar* ) { unsigned charchar state[4][4]; intint i,r,c; for(r=0; r4; r++) { for(c=0; c=0; i--) { InvShiftRows(state); InvSubBytes(state); AddRoundKey(state, w[i]); if(i)InvMixColumns(state); } for(r=0; r4; r++) { for(c=0; c4 ;c++) { [c*4+r] = state[r][c]; } } return ; } 对外部数据的加密对外部数据的加密/ /解密解密 至此已经实现了 AES 加密与解密的原型, 在使用的时候一般处理的是字符串等,