- 主算法:
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
另,该算法已经作为课程作业上交,学弟学妹可以借鉴,但是不能照搬,否则后果自负。
创作不易,望支持。