AES实现
实验内容
实现128位高级加密标准AES对信息的加密与解密。
具体算法
分组长度128bit,密钥长度128bit
圈数round=10
域GF(2^8)的不可约多项式为x^8+x^4+x^3+x+1
字节替代
对每一个字节本身进行替代
首先是在有限域GF(2^8)上求乘法逆,00映射到自身。求有限域乘法逆调用的是上次实验中的求逆的子程序。使用的是扩展欧几里得算法。
接下来进行如下的仿射变换:乘以矩阵
计算出这个表,迭代的时候直接在表中找映射值。
将字节代换的表使用一个长度为256的数组存储,索引对应的是二进制串的数值。每一个位置存储一个8位的二进制串。对于每一个8位的二进制串,通过上述方法计算出它的字节替换结果之后填入表对应位置中。同时,也可以将逆字节代换表的对应位置也填上,只要将索引同值换一下位置即可。
在程序中,使用全局变量Sbox和Inv_Sbox来分别表示字节代换和逆字节代换。在CreateSbox函数中,计算S盒以及逆S盒,更新这两个全局变量。
1 | /*创建S盒以及逆S盒*/ |
字节移位
分组长度为4的情况下,后三行循环移位字节量如下,循环左移
C1:1,C2:2,C3:3
ByteRotation函数中,接收一个二进制串的vector,以及循环左移移位量,这个vector代表的是一个word,即四个字节。这里进行的是对这四个字节进行循环左移指定位数的操作。
全局变量定义了SHIFT和INV_SHIFT,分别代表加密时每一行循环左移的移位量以及解密时每一行循环左移的移位量。在对应的加解密程序中确定每一行的移位量。
1 |
|
列混合
加密的时候,相当于乘一个矩阵,矩阵如下
在MixColumn函数中,接收一个使用vector表示的矩阵,对此矩阵进行列混合操作。这里调用的mul函数是进行域乘法的子程序
解密的时候,相当于乘以上面矩阵在有限域下的逆矩阵,即
1 | /*列混合加密*/ |
圈密相加
将圈密钥与状态按比特异或,圈密钥长度为分组长度128bit。AddRoundKey函数接收一个矩阵以及轮数作为输入,取相对应轮数的圈密钥,加到矩阵上
1 | void AddRoundKey(vector<vector<byte_def>> &input, int round){ |
密钥扩展
密钥总长度=分组长度*(圈数+1)
最开始明文需要异或密钥,以及每一轮最后需要异或密钥
初始密钥K0,K1,K2,K3
SubWord子程序对输入的word的每一个字节进行S盒操作,RotWord子程序对输入的word进行一个字节的移位。
在密钥扩展的子程序KeyExpansion中,接收一个初始的矩阵,即圈密钥0。依据这个初始密钥生成剩下的10个圈密钥。使用一个全局变量expand_key来存储每一轮使用的圈密钥。密钥扩展中需要用到的Rcon使用全局变量来定义。由于这里的一个word使用了四个byte来表示,而Rcon的后面三个byte全为0,因此其实只需要对word的第一个byte进行异或Rcon的第一个byte即可。Rcon的定义只取了它每一个的第一个byte
1 | vector<vector<vector<byte_def>>> expand_key; |
AES加密
函数void AES(vector
encode函数接收字符串明文作为输入,循环读入长度为16的字符串,将这16个字符串转化成AES输入的矩阵,先异或一下IV之后放进AES子程序中进行加密,加密完之后,密文作为下一组的IV,更新IV的值,并将密文存入ciphertext变量中。其中,将明文转换为矩阵通过一个名为Padding的函数进行,在此函数中,读入一定长度的字符串,先判断长度是否小于等于16,再计算此字符串的长度比16少多少,将少的长度记为n,将字符串填充为16长度的时候补充0x0n。
AES解密
函数void Inv_AES(vector
decode函数接收密文,ciphertext。循环读入16个字节,将这16个字节依序放入矩阵中,将此矩阵放到AES解密的子程序里面进行解密,最后再异或一下IV,并更新IV为这一组原来的密文,供下一组解密使用。
运行截图
计算出来的S盒以及逆S盒
w_key计算
圈密钥
加密解密结果
结果分析
S盒的计算以及逆S盒,对比书上给出的S盒以及这里计算出的S盒,结果相同说明S盒计算无误。另外,S盒的索引值以及其对应的值,刚好与逆S盒的值和索引一一相互对应回去。说明逆S盒计算也无误。(比如S盒中索引为00的地方值是63,逆S盒中索引为63的地方值为00)
w_key的计算,根据书上给出的算法实现。手动计算了一下粗略验证了w5和w6,发现计算的结果无误,可以推定w_key的算法实现无误
圈密钥的生成。一个圈密钥是由四个wkey生成的,其中要注意的是从wkey到圈密钥的排放顺序,wkey0对应的是圈密钥的第一列,wkey1是第二列,以此类推。可以看到圈密钥输出的结果正是4个wkey按照给定规则排列成的。
程序加密的结果和网站加密的结果相同,且能够正确解密出密文,说明加密和解密的结果无误。
网站加密结果
1 | //cipher key "yaojieqian" |