实例详解AES算法 您所在的位置:网站首页 密码学RSA算法例题 实例详解AES算法

实例详解AES算法

2024-07-11 13:56| 来源: 网络整理| 查看: 265

AES算法流程

  稍微百度下就可知道,AES算法分为四个步骤:轮密钥加,字节代替,行移位和列混淆,本文以一个实例来讲解AES算法中的每一个步骤干了什么,精确到每个数字的变换。

写在前面

  AES算法其实有很多种,根据秘钥长度的不同分为AES-128,AES-192,AES-256,本文以AES-128为例。   至于AES的加密模式,ECB,CBC等,其实和AES加密流程没有关系,不同的模式只是对输入的数据做处理(异或等),加密过程没有丝毫差别。   最后的实现采用python完成,无第三方模块。

密钥扩展

  在开始加密之前,至少需要一个密钥,AES-128代表密钥长度为128位,也就是16字节。而加密流程一共要循环10轮,每一轮都需要不同的密钥,我们自然不可能设置长度为1280位的密钥,所以需要密钥扩展这个步骤,这个流程将产生10组长度均为128位的密钥。 假设现在有个密钥为’2b7e151628aed2a6abf7158809cf4f3c’,那么扩展秘钥是多少?   很明显,这个密钥长度是16字节(128位),每两位十六进制的数代表1字节。那么可以将这个密钥化为矩阵的形式:   在这里插入图片描述   下一步,官方说法是将初始密钥转为4个32位的字,其实就是将这个密钥分成四组,每一列就是一组,这样就有了四个变量:W0=2B7E1516,W1=28AED2A6,W2=ABF71588,W3=09CF4F3C。   现在,就要求扩展秘钥了,其实就是求W4,W5,W6…W43,而且很明显,每四个W组成完整的一组密钥。   怎么求呢?现在先交个底,求每组密钥的第一个分组(W4,W8,W12…)比其他的分组要复杂得多。   先把公式给出来,看不懂也没关系,有个印象就好:   在这里插入图片描述   可以看到,在求W4,W8…时走的是另一条路,重点在于函数g干了什么,我也不想直接甩概念性的东西出来,那个没有意义,还是看实例来的清楚。   现在是正式的过程,W4很明显是W0与g(W3)的进行异或得结果,那么函数g对W3干了什么?下面就是。   先将W3左移一个字节,得到W3’=CF4F3C09,然后将这个值进行S盒映射,这个S盒呢,是个固定的东西,可以理解为一个一对一的字典,它的样子如下: 在这里插入图片描述   查字典的方法不用我多说,将W3’进行S盒映射后,得到W3"=8A84EB01。   有些烧脑了,现在呢要将W3"与一个叫做Rcon的向量异或,这个向量长这样:   Rcon=[0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36]   其实Rcon就是一个长度为10的数组,里面的每个数字都是十六进制形式,计算的密钥分组是属于哪个密钥的,就与Rcon中对应序号的值做异或,比如现在所求得W4属于第一组密钥,那么W3"就要与RCon[0]做异或,以此类推,求第十组密钥W40时需要W39"与Rcon[9]做异或。   现在好像有问题了,这两个值位数不一样怎么异或?其实很简单,就像下面这样:   在这里插入图片描述   不足的位数在后面补0就行了,实质上所有Rcon中的值都只影响W3"的第一个字节(前8位),通过异或,就得到了W3"’,写成十六进制形式是W3"’=8B84EB01。   上述呢,其实就是函数g干的事,下面就可以得出结果了。   最后,将W3"'与W0进行异或,就得到了W4,也就是第一组扩展密钥的第一组。   在这里插入图片描述   将W4写成十六进制形式W4=A0FAFE17。   然后,就是把第一组扩展密钥的其他分组(W5,W6,W7)求出来,这三组就简单得多,根据公式,W5是W1与W4异或得到,W6是W2与W5异或得到,W7是W3与W5异或得到,过程如下:   在这里插入图片描述   将W5写成十六进制形式就是W5=88542CB1,以此类推,W6=23A33939,W7=2A6C7605。   现在,就完整求出了第一组扩展密钥,同样写成矩阵形式:   在这里插入图片描述 下一步,就是求扩展密钥的第二组(W8,W9,W10,W11),过程和上面几乎一样,W8需要W4与g(W7)异或得到,其余的就是直接异或。直至求出第十组扩展密钥。

加密过程

  密钥有了,现在来完整梳理一下加密的流程,其实百度就一大堆,这里简单说一下,加密过程就是:先进行一次轮密钥加(使用初始秘钥),然后循环9次字节代替,行移位,列混淆,轮密钥加(使用9组扩展秘钥),最后再进行一次字节代替,行移位,轮密钥加(使用最后一组扩展秘钥)。

轮密钥加

  初始时刻,需要对明文进行处理,使其长度变为和密钥一样的128位,这里先不讨论,因为这不是加密的过程,后面我会放上详细的明文初始化过程。   现在,我们已经有了经过处理的明文’3243f6a8885a308d313198a2e0370734’,同样写成4×4的矩阵形式:   在这里插入图片描述   那么轮密钥加之后的结果是多少?假设密钥如下:   在这里插入图片描述   轮密钥加其实很简单,其实就是明文与密文的异或运算而已,只是计算过程繁杂。   相同位置的明文和密文都化为二进制形式,进行异或运算,以第一个字节为例:   在这里插入图片描述   其他结果依次类推,异或后的矩阵为:   在这里插入图片描述

字节代替

  这个比较简单,字节代替是通过S盒映射完成的,和密钥扩展的S盒一样,可以直接查S盒。跟查字典一样,和前面密钥扩展的步骤一模一样。上面经过轮密钥加的矩阵再经过字节代替的结果如下:   在这里插入图片描述

行移位

这个也比较简单,就是矩阵的第一行不变,第二行循环左移一位,第三行循环左移两位,第四行循环左移三位,如下:   在这里插入图片描述

列混淆

  我认为列混淆是AES加密中最复杂的了,但过程却是一句话就可以概括:左乘一个固定的矩阵。   固定矩阵如下:   在这里插入图片描述   过程图解如下:   在这里插入图片描述

  在这里插入图片描述   “⊕”是异或,但那个“×”号不是简单的乘法,规则如下:

满足乘法分配律,即03×S=01×S⊕02×S。×01和普通乘法×1一样,是其本身。×02表示左移一位,最右边补0,若原始的数值最高位为1,需要将移位后的结果与1B(00011011)进行异或,如果不是则不用异或。   假设原始矩阵为在这里插入图片描述求经过列混淆的矩阵。   同样以第一个字节为例,左乘是行×列,即固定矩阵的一行与原始矩阵的一列相乘。 在这里插入图片描述   其他元素是同样的方法,最终得到的结果矩阵如下:   在这里插入图片描述 至此,AES加密算法的所有步骤都已经介绍完毕,剩下的就是上述步骤的不断重复。 明文初始化

  关于明文的初始化,就是将明文化为128位(16字节)的过程,转化过程其实很简单,就是将数据(可识别的文字,如hello word)转为字节流,然后再将字节流转为十六进制字符串就OK,转换的方法百度一大堆。   稍微有点儿问题的就是假设转换的字符串的位数不够128位怎么办?其实这个就是AES加密中的字符填充问题,将原本不足128位的字符填充至128位。至于超过128位的,分组就可以了,一组128位,最后一组同样需要字符填充,然后将每组数据加密后得到的密文连接起来就是完整密文。   字符填充的办法,其实也是百度一大堆的,这里简单说两种:

PKCS7Padding:差几个字节就填充几,假设明文有10个字节,距离16字节差6字节,就在十六进制字符串后添加6个06,如果刚好16字节,就要在后面添加16个16。ZerosPadding:缺多少补多少个0,差6个字节就在后面补6个00。 关于解密

  解密其实就是加密的逆推,第一步同样是轮密钥加,而后进入循环解密阶段,一共10轮,按顺序分别执行逆行移位,逆字节代替,轮密钥加,逆向列混淆,同样第10轮去掉逆向列混淆输出明文,但此时扩展秘钥的顺序要反过来。   逆行移位:第一行不变,第二行循环右移一位,第三行循环右移两位,第四行循环右移三位。   逆字节代替:操作步骤和字节代替一样,只不过需要映射的S盒变成了逆S盒,其实就是S盒反过来,键值互换,这点用python做非常方便。   逆列混淆:步骤和列混淆一样,仅仅是固定矩阵不同。   在这里插入图片描述   这里的乘法也是和列混淆中的乘法一样,所有的9,B,D,E其实都是通过分解为1或者2进行计算的。   逆列混淆矩阵和列混淆矩阵的乘积刚好是单位矩阵。

实现(python)

  python解释器是python3.6

# -*- coding: utf-8 -*- import re import binascii class Aes: s_box = { # 字节替换s盒 '0x00': '0x63', '0x01': '0x7c', '0x02': '0x77', '0x03': '0x7b', '0x04': '0xf2', '0x05': '0x6b', '0x06': '0x6f', '0x07': '0xc5', '0x08': '0x30', '0x09': '0x01', '0x0a': '0x67', '0x0b': '0x2b', '0x0c': '0xfe', '0x0d': '0xd7', '0x0e': '0xab', '0x0f': '0x76', '0x10': '0xca', '0x11': '0x82', '0x12': '0xc9', '0x13': '0x7d', '0x14': '0xfa', '0x15': '0x59', '0x16': '0x47', '0x17': '0xf0', '0x18': '0xad', '0x19': '0xd4', '0x1a': '0xa2', '0x1b': '0xaf', '0x1c': '0x9c', '0x1d': '0xa4', '0x1e': '0x72', '0x1f': '0xc0', '0x20': '0xb7', '0x21': '0xfd', '0x22': '0x93', '0x23': '0x26', '0x24': '0x36', '0x25': '0x3f', '0x26': '0xf7', '0x27': '0xcc', '0x28': '0x34', '0x29': '0xa5', '0x2a': '0xe5', '0x2b': '0xf1', '0x2c': '0x71', '0x2d': '0xd8', '0x2e': '0x31', '0x2f': '0x15', '0x30': '0x04', '0x31': '0xc7', '0x32': '0x23', '0x33': '0xc3', '0x34': '0x18', '0x35': '0x96', '0x36': '0x05', '0x37': '0x9a', '0x38': '0x07', '0x39': '0x12', '0x3a': '0x80', '0x3b': '0xe2', '0x3c': '0xeb', '0x3d': '0x27', '0x3e': '0xb2', '0x3f': '0x75', '0x40': '0x09', '0x41': '0x83', '0x42': '0x2c', '0x43': '0x1a', '0x44': '0x1b', '0x45': '0x6e', '0x46': '0x5a', '0x47': '0xa0', '0x48': '0x52', '0x49': '0x3b', '0x4a': '0xd6', '0x4b': '0xb3', '0x4c': '0x29', '0x4d': '0xe3', '0x4e': '0x2f', '0x4f': '0x84', '0x50': '0x53', '0x51': '0xd1', '0x52': '0x00', '0x53': '0xed', '0x54': '0x20', '0x55': '0xfc', '0x56': '0xb1', '0x57': '0x5b', '0x58': '0x6a', '0x59': '0xcb', '0x5a': '0xbe', '0x5b': '0x39', '0x5c': '0x4a', '0x5d': '0x4c', '0x5e': '0x58', '0x5f': '0xcf', '0x60': '0xd0', '0x61': '0xef', '0x62': '0xaa', '0x63': '0xfb', '0x64': '0x43', '0x65': '0x4d', '0x66': '0x33', '0x67': '0x85', '0x68': '0x45', '0x69': '0xf9', '0x6a': '0x02', '0x6b': '0x7f', '0x6c': '0x50', '0x6d': '0x3c', '0x6e': '0x9f', '0x6f': '0xa8', '0x70': '0x51', '0x71': '0xa3', '0x72': '0x40', '0x73': '0x8f', '0x74': '0x92', '0x75': '0x9d', '0x76': '0x38', '0x77': '0xf5', '0x78': '0xbc', '0x79': '0xb6', '0x7a': '0xda', '0x7b': '0x21', '0x7c': '0x10', '0x7d': '0xff', '0x7e': '0xf3', '0x7f': '0xd2', '0x80': '0xcd', '0x81': '0x0c', '0x82': '0x13', '0x83': '0xec', '0x84': '0x5f', '0x85': '0x97', '0x86': '0x44', '0x87': '0x17', '0x88': '0xc4', '0x89': '0xa7', '0x8a': '0x7e', '0x8b': '0x3d', '0x8c': '0x64', '0x8d': '0x5d', '0x8e': '0x19', '0x8f': '0x73', '0x90': '0x60', '0x91': '0x81', '0x92': '0x4f', '0x93': '0xdc', '0x94': '0x22', '0x95': '0x2a', '0x96': '0x90', '0x97': '0x88', '0x98': '0x46', '0x99': '0xee', '0x9a': '0xb8', '0x9b': '0x14', '0x9c': '0xde', '0x9d': '0x5e', '0x9e': '0x0b', '0x9f': '0xdb', '0xa0': '0xe0', '0xa1': '0x32', '0xa2': '0x3a', '0xa3': '0x0a', '0xa4': '0x49', '0xa5': '0x06', '0xa6': '0x24', '0xa7': '0x5c', '0xa8': '0xc2', '0xa9': '0xd3', '0xaa': '0xac', '0xab': '0x62', '0xac': '0x91', '0xad': '0x95', '0xae': '0xe4', '0xaf': '0x79', '0xb0': '0xe7', '0xb1': '0xc8', '0xb2': '0x37', '0xb3': '0x6d', '0xb4': '0x8d', '0xb5': '0xd5', '0xb6': '0x4e', '0xb7': '0xa9', '0xb8': '0x6c', '0xb9': '0x56', '0xba': '0xf4', '0xbb': '0xea', '0xbc': '0x65', '0xbd': '0x7a', '0xbe': '0xae', '0xbf': '0x08', '0xc0': '0xba', '0xc1': '0x78', '0xc2': '0x25', '0xc3': '0x2e', '0xc4': '0x1c', '0xc5': '0xa6', '0xc6': '0xb4', '0xc7': '0xc6', '0xc8': '0xe8', '0xc9': '0xdd', '0xca': '0x74', '0xcb': '0x1f', '0xcc': '0x4b', '0xcd': '0xbd', '0xce': '0x8b', '0xcf': '0x8a', '0xd0': '0x70', '0xd1': '0x3e', '0xd2': '0xb5', '0xd3': '0x66', '0xd4': '0x48', '0xd5': '0x03', '0xd6': '0xf6', '0xd7': '0x0e', '0xd8': '0x61', '0xd9': '0x35', '0xda': '0x57', '0xdb': '0xb9', '0xdc': '0x86', '0xdd': '0xc1', '0xde': '0x1d', '0xdf': '0x9e', '0xe0': '0xe1', '0xe1': '0xf8', '0xe2': '0x98', '0xe3': '0x11', '0xe4': '0x69', '0xe5': '0xd9', '0xe6': '0x8e', '0xe7': '0x94', '0xe8': '0x9b', '0xe9': '0x1e', '0xea': '0x87', '0xeb': '0xe9', '0xec': '0xce', '0xed': '0x55', '0xee': '0x28', '0xef': '0xdf', '0xf0': '0x8c', '0xf1': '0xa1', '0xf2': '0x89', '0xf3': '0x0d', '0xf4': '0xbf', '0xf5': '0xe6', '0xf6': '0x42', '0xf7': '0x68', '0xf8': '0x41', '0xf9': '0x99', '0xfa': '0x2d', '0xfb': '0x0f', '0xfc': '0xb0', '0xfd': '0x54', '0xfe': '0xbb', '0xff': '0x16' } ns_box = { # 逆字节替换s盒 } Rcon = { # Rcon生成密钥的表 1: ['0x01', '0x00', '0x00', '0x00'], 2: ['0x02', '0x00', '0x00', '0x00'], 3: ['0x04', '0x00', '0x00', '0x00'], 4: ['0x08', '0x00', '0x00', '0x00'], 5: ['0x10', '0x00', '0x00', '0x00'], 6: ['0x20', '0x00', '0x00', '0x00'], 7: ['0x40', '0x00', '0x00', '0x00'], 8: ['0x80', '0x00', '0x00', '0x00'], 9: ['0x1B', '0x00', '0x00', '0x00'], 10: ['0x36', '0x00', '0x00', '0x00'] } Matrix = [ # 列混淆 ['0x02', '0x03', '0x01', '0x01'], ['0x01', '0x02', '0x03', '0x01'], ['0x01', '0x01', '0x02', '0x03'], ['0x03', '0x01', '0x01', '0x02'] ] ReMatrix = [ # 逆列混淆 ['0x0e', '0x0b', '0x0d', '0x09'], ['0x09', '0x0e', '0x0b', '0x0d'], ['0x0d', '0x09', '0x0e', '0x0b'], ['0x0b', '0x0d', '0x09', '0x0e'] ] plaintext = [[], [], [], []] # 存放明文 plaintext1 = [[], [], [], []] # 最后输出的密文 subkey = [[], [], [], []] # 存放密钥 def __init__(self, key): # 构造函数,同时生成密钥 for i in range(4): for j in range(0, 8, 2): self.subkey[i].append("0x" + key[i * 8 + j:i * 8 + j + 2]) # 将密钥变成二维矩阵 # print(self.subkey) for i in range(4, 44): # 生成密钥 if i % 4 != 0: # 如果不是4的倍数,那么直接异或 tmp = xor_32(self.subkey[i - 1], self.subkey[i - 4]) self.subkey.append(tmp) else: # 4的倍数的时候执行 tmp1 = self.subkey[i - 1][1:] tmp1.append(self.subkey[i - 1][0]) # print(tmp1) for m in range(4): tmp1[m] = self.s_box[tmp1[m]] # tmp1 = self.s_box['cf'] # 字节代替 tmp1 = xor_32(tmp1, self.Rcon[i / 4]) # 和Rcon异或 self.subkey.append(xor_32(tmp1, self.subkey[i - 4])) # print(self.subkey) def AddRoundKey(self, round): # 轮密钥加 for i in range(4): self.plaintext[i] = xor_32(self.plaintext[i], self.subkey[round * 4 + i]) # print(self.plaintext) def PlainSubBytes(self): # 字节代替 for i in range(4): for j in range(4): self.plaintext[i][j] = self.s_box[self.plaintext[i][j]] # print(self.plaintext) def RePlainSubBytes(self): # 逆字节代替 for i in range(4): for j in range(4): self.plaintext[i][j] = self.ns_box[self.plaintext[i][j]] def ShiftRows(self): # 行移位 p1, p2, p3, p4 = self.plaintext[0][1], self.plaintext[1][1], self.plaintext[2][1], self.plaintext[3][1] self.plaintext[0][1] = p2 self.plaintext[1][1] = p3 self.plaintext[2][1] = p4 self.plaintext[3][1] = p1 p1, p2, p3, p4 = self.plaintext[0][2], self.plaintext[1][2], self.plaintext[2][2], self.plaintext[3][2] self.plaintext[0][2] = p3 self.plaintext[1][2] = p4 self.plaintext[2][2] = p1 self.plaintext[3][2] = p2 p1, p2, p3, p4 = self.plaintext[0][3], self.plaintext[1][3], self.plaintext[2][3], self.plaintext[3][3] self.plaintext[0][3] = p4 self.plaintext[1][3] = p1 self.plaintext[2][3] = p2 self.plaintext[3][3] = p3 # print(self.plaintext) def ReShiftRows(self): # 逆行移位 p1, p2, p3, p4 = self.plaintext[0][1], self.plaintext[1][1], self.plaintext[2][1], self.plaintext[3][1] self.plaintext[3][1] = p3 self.plaintext[2][1] = p2 self.plaintext[0][1] = p4 self.plaintext[1][1] = p1 p1, p2, p3, p4 = self.plaintext[0][2], self.plaintext[1][2], self.plaintext[2][2], self.plaintext[3][2] self.plaintext[0][2] = p3 self.plaintext[1][2] = p4 self.plaintext[2][2] = p1 self.plaintext[3][2] = p2 p1, p2, p3, p4 = self.plaintext[0][3], self.plaintext[1][3], self.plaintext[2][3], self.plaintext[3][3] self.plaintext[0][3] = p2 self.plaintext[1][3] = p3 self.plaintext[2][3] = p4 self.plaintext[3][3] = p1 def MixColumns(self): # 列混淆 for i in range(4): for j in range(4): self.plaintext1[i].append(MatrixMulti(self.Matrix[j], self.plaintext[i])) # print(self.plaintext1) def ReMixColumns(self): # 逆列混淆 for i in range(4): for j in range(4): self.plaintext1[i].append(MatrixMulti(self.ReMatrix[j], self.plaintext[i])) def AESEncryption(self, plaintext): # AES单组加密函数 self.plaintext = [[], [], [], []] for i in range(4): for j in range(0, 8, 2): self.plaintext[i].append("0x" + plaintext[i * 8 + j:i * 8 + j + 2]) self.AddRoundKey(0) for i in range(9): self.PlainSubBytes() self.ShiftRows() self.MixColumns() self.plaintext = self.plaintext1 self.plaintext1 = [[], [], [], []] # 重置 self.AddRoundKey(i + 1) self.PlainSubBytes() # 最后一轮字节代替 self.ShiftRows() # 最后一轮行移位 self.AddRoundKey(10) # 最后一轮轮密钥加 return Matrixtostr(self.plaintext) def AESDecryption(self, cipher): # AES单组解密函数 self.plaintext = [[], [], [], []] for i in range(4): for j in range(0, 8, 2): self.plaintext[i].append('0x' + cipher[i * 8 + j:i * 8 + j + 2]) # 16进制转成2进制 self.ns_box = dict(zip(self.s_box.values(), self.s_box.keys())) # s盒键值互换,变为逆S盒 # print(self.ns_box) self.AddRoundKey(10) for i in range(9): self.ReShiftRows() self.RePlainSubBytes() self.AddRoundKey(9-i) self.ReMixColumns() self.plaintext = self.plaintext1 self.plaintext1 = [[], [], [], []] self.ReShiftRows() self.RePlainSubBytes() self.AddRoundKey(0) return Matrixtostr(self.plaintext) def Encryption(self, text): # 加密函数 group = PlaintextGroup(TextToByte(text), 32, 1) # print(group) cipher = "" for i in range(len(group)): cipher = cipher + self.AESEncryption(group[i]) return cipher def Decryption(self, cipher): # 解密函数 group = PlaintextGroup(cipher, 32, 0) # print(group) text = '' for i in range(len(group)): text = text + self.AESDecryption(group[i]) text = ByteToText(text) return text def xor_32(start, end): # 32位进行异或 a = [] for i in range(0, 4): xor_tmp = "" b = hextobin(start[i]) c = hextobin(end[i]) for j in range(8): xor_tmp += str(int(b[j], 10) ^ int(c[j], 10)) a.append(bintohex(xor_tmp)) return a def xor_8(begin, end): # 8位异或 xor_8_tmp = "" for i in range(8): xor_8_tmp += str(int(begin[i]) ^ int(end[i])) return xor_8_tmp def hextobin(word): # 把十六进制转换成二进制 word = bin(int(word, 16))[2:] # 去除掉最前面的0b for i in range(0, 8-len(word)): # 补全八位 word = '0'+word return word def bintohex(word): # 把二进制转换十六进制 word = hex(int(word, 2)) if len(word) == 4: return word elif len(word)


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有