基于python列表操作的AES加密算法

  1. 主算法:
    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置换等
    

     

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值