- 主算法:
import copy import multi_Num import AES_sbox sbox = AES_sbox.s_box() RC = [1, 2, 4, 8, 16, 32, 64, 128, 27, 54] # 将RC以十进制表示 def rowmix(rowMix_s): # rowmix_s是一个矩阵 for i in range(0, 4): temp = copy.deepcopy(rowMix_s[i]) # 深拷贝数组 for j in range(0, 4): if i > 0: rowMix_s[i][j - i] = temp[j] return rowMix_s def colunmix(columMix): # columMix是一个整型矩阵 a = [[1 for i in range(0, 4)] for i in range(0, 4)] for i in range(0, 4): a[i][i] = 2 a[i][(i + 1) % 4] = 3 # 生成列混淆的左乘矩阵 b = copy.deepcopy(columMix) # 深拷贝,a,b指向内存中的不同单元 for i in range(0, 4): for j in range(0, 4): temp1 = 0 for k in range(0, 4): temp = multi_Num.multi_multiplication(b[k][j], a[i][k])[0] if temp > 255: # 最左边移位是一的时要去掉,再与27异或 temp = int(bin(temp)[-8:], 2) ^ 27 temp1 ^= temp columMix[i][j] = temp1 return columMix def g(w, j): # w是一组密钥,j是对应的轮数 w_1 = w[1:] + w[:1] for i in range(0, 4): # 当w下标%4=0时产生w' x = int('{:08b}'.format(w_1[i])[:4], 2) # sbox寻址的x,高四位 y = int('{:08b}'.format(w_1[i])[4:8], 2) # sbox寻址的y,低四位 g_list.append(sbox[x][y]) # g_list便于检验经过g函数的s盒置换是否正确,打印即可 w_1[i] = int(sbox[x][y], 16) w_1[0] ^= RC[j] # 第一个数与对应RC中的元素异或 return w_1 def sbox_change(w): # w是整型矩阵 for i in range(0, 4): # 当w下标%4=0时产生w' for j in range(0, 4): x = int('{:08b}'.format(w[i][j])[:4], 2) y = int('{:08b}'.format(w[i][j])[4:8], 2) # print("明文的s置换", sbox[x][y]) s盒置换验证 w[i][j] = int(sbox[x][y], 16) return w def key_plus(w_1, w_4): # w_1,w_4为整型列表 w4 = copy.deepcopy(w_4) for i in range(0, 4): w4[i] = w_1[i] ^ w4[i] # 当w下标%4!=0时产生w' return w4 def key_extneds(key): # key为二维列表即矩阵 w = [[0 for i in range(0, 4)]for i in range(0, 44)] for i in range(0, 4): for j in range(0, 4): w[i][j] = key[j][i] # 输入密钥被直接赋值给扩展密钥数组的前四个字 for i in range(4, 44): if i % 4 == 0: w[i] = key_plus(w[i-4], g(w[i-1], i//4-1)) # i//4是对应RC的下标 else: w[i] = key_plus(w[i-1], w[i-4]) for i in range(0, 4): for j in range(0, 4): w[i][j] = key[i][j] # 输入密钥被直接赋值给扩展密钥数组的前四个字 w_temp = [n for a in w for n in a] # 用w_temp列表存放所有的密钥,顺序为从左到右 for i in range(4, 44): # 对行列进行转化 for j in range(0, 4): if i % 4 == 0: w[i][j] = w_temp[4*(i+j)] else: w[i][j] = w_temp[4*(i+j)-3*(i % 4)] # 通过观察总结出公式 print("密钥空间:", w) return w def toMatrix(a): # 将十六进制字符数组转化成二维整型数组 tomatrix = [[0 for i in range(0, 4)] for i in range(0, 4)] if a == 0: print("明文示例:", "01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10") list = input("输入明文!(十六进制,空格隔开)\n").split() # 用list存放输入的明文或密钥 else: print("密钥示例:", "0f 15 71 c9 47 d9 e8 59 0c b7 ad d6 af 7f 67 98") list = input("输入密钥!(十六进制,空格隔开)\n").split() for i in range(0, 16): list[i] = int(list[i], 16) # 将list中的字符转换成十进制整数 for i in range(0, 4): k = i for j in range(0, 4): tomatrix[i][j] = list[k] # 由于输入的时候是按顺序从左到右输入,所以要将其转化成对应的行和列 k += 4 return tomatrix # 输入密钥,以空格隔开 def display_w(w): # 以十六进制展示密钥空间,需要直接调用即可 for i in range(0, 44): for j in range(0, 4): print('{:02x}'.format(w[i][j])) print(w[i]) def tohex(matrix): # 将每一轮结束列表以十六进制展示 hex16 = [] for i in range(0, 4): for j in range(0, 4): hex16.append("{:02x}".format(matrix[i][j])) return ''.join(hex16) def AES_single(plain, w_time): # 单轮aes加密 for i in range(0, 4): # 轮密钥加 for j in range(0, 4): plain[i][j] ^= w[i+w_time][j] # plain[i][j] = '{:02x}'.format(plain[i][j]),检验每次轮开始前是否正确 print(w_time//4, "轮开始: ", tohex(plain)) s_plain = sbox_change(plain) # sbox置换 if w_time // 4 < 10: # 控制第9轮的显示 print("字节代替后:", tohex(s_plain)) row_plain = rowmix(s_plain) # 行变换 print("行移位后: ", tohex(row_plain)) if w_time // 4 < 9: # 控制第十轮的显示 plain = colunmix(row_plain) # 列混淆 print("列混淆后: ", tohex(plain)) return plain def start(): # 算法开始 w_time = 0 for i in range(0, 11): AES_single(plain, w_time) w_time += 4 if __name__ == '__main__': g_list = [] plain = toMatrix(0) # 明文转化成矩阵 0代表输入明文 key = toMatrix(1) # 1代表输入密钥 w = key_extneds(key) # 密钥拓展 start() # 本AES算法主要使用列表处理输入的明文和密钥,及进行行移位,列混淆,密钥扩展等操作,其中密钥扩展和明文输入时,采用十六进制+空格的方式输入, # 由于顺序输入的原因,起初行列和书本上的行列有差异,后来使用列表存储,然后再观察结构,利用第77~88行代码将行列互换,达到了要求 # 本AES算法涉及到的知识点有:函数定义、参数传递、列表浅拷贝与深拷贝、for循环、列表解析、二维列表、format置换等
- multi_Num基于GF(2^8)域上的运算
def multi_plus(n1, n2): # 多项式加法 return n1 ^ n2 def multi_multiplication(n1, n2): # 多项式乘法 temp = bin(n2)[2:] s = 0 while len(temp) > 0: if int(temp[0]) > 0: s ^= n1 << len(temp) - 1 temp = temp[1:] return s, multi_division(s, 283)[1] def multi_division(n1, n2, q=0): # 多项式除法运算 if n1 < n2: return 0, n1 elif n2 == 0: return 0 else: delta = len(bin(n1)) - len(bin(n2)) q += 1 << delta r = (n2 << delta) ^ n1 if r >= n2: return multi_division(r, n2, q) else: return q, r def multi_gcd(n1, n2): # 多项式求最大公因式(欧几里得算法) if n1 == 0: return n2 elif n2 == 0: return n1 if n1 - n2 >= 0: n1 = multi_division(n1, n2)[1] return multi_gcd(n1, n2) else: # s1比s2小,则将s1,s2互换,继续运算 n1, n2 = n2, n1 return multi_gcd(n1, n2) def multi_niyuan(n1, n2, v1=1, v2=0, w1=0, w2=1): # GF(2^8)域求乘法逆元,原理和整数的扩展欧几里得算法几乎一致,但是必须先定义多项式的模运算、加法运算和乘法运算 s1, s2 = n1, n2 if n2 == 0: return 0 if multi_gcd(s1, s2) != 1: return "没有逆元" else: rx = multi_division(n1, n2)[1] # multi_rx返回的是一个列表,装载着余数和商 qx = multi_division(n1, n2)[0] n1, n2 = n2, rx v1, v2 = v2, multi_plus(v1, multi_multiplication(v2, qx)[1]) w1, w2 = w2, multi_plus(w1, multi_multiplication(w2, qx)[1]) if rx != 0: return multi_niyuan(n1, n2, v1, v2, w1, w2) else: return w1 def menu(): n1 = int(input("请输入n1\n")) n2 = int(input("请输入n2\n")) choose = input("请选择功能:\n" "1.ax+bx\n" "2.ax·bx\n" "3.ax/bx\n" "4.求ax mod(bx)的逆元\n" "5.gcd(ax,bx)\n") if choose == '1': print('和是:', multi_plus(n1, n2)) elif choose == '2': print('GF(2)上乘积是:', multi_multiplication(n1, n2)[0], " GF(2^8)上乘积是:", multi_multiplication(n1, n2)[1]) elif choose == '3': print('商是:', multi_division(n1, n2)[0], ' 余数是:', multi_division(n1, n2)[1]) elif choose == '4': print('逆元是:', multi_niyuan(n1, n2)) elif choose == '5': print('gcd是:', multi_gcd(n1, n2)) else: print("输入有误,请重试!") if __name__ == '__main__': while True: menu()
- 用于生成S盒的Aes_sbox
import multi_Num def change(temp): c = '01100011' ss = '' for n in range(0, 8): ss += str(int(temp[n]) ^ int(temp[(n + 4) % 8]) ^ int(temp[(n + 3) % 8]) ^ int(temp[(n + 2) % 8]) ^ int(temp[(n + 1) % 8]) ^ int(c[n])) return ss def change2(temp): c = '00000101' ss = '' for n in range(0, 8): ss += str(int(temp[(n + 6) % 8]) ^ int(temp[(n + 3) % 8]) ^ int(temp[(n + 1) % 8]) ^ int(c[n])) return ss def s_box(): sbox = [['' for i in range(0, 16)] for i in range(0, 16)] for i in range(0, 16): for j in range(0, 16): sbox[i][j] = '{:02x}'.format(int(change(list('{:08b}'.format(multi_Num.multi_niyuan(283, i * 16 + j)))), 2)) return sbox def s_box_reverse(): rbox = [['' for i in range(0, 16)] for i in range(0, 16)] for i in range(0, 16): for j in range(0, 16): rbox[i][j] = '{:02x}'.format(multi_Num.multi_niyuan(283, int(change2(list('{:08b}'.format(i * 16 + j))), 2))) return rbox
@Nickname4th Hainu University 2018.12.9
另,该算法已经作为课程作业上交,学弟学妹可以借鉴,但是不能照搬,否则后果自负。
创作不易,望支持。
基于python列表操作的AES加密算法
最新推荐文章于 2024-04-30 19:59:16 发布