RIJNDAEL 加密算法

注意:本文实现的AES算法的密钥,明文,密文均为128位,后续可能会添加192位或256位的密钥。函数flag参数默认是1,即加密,在解密调用时改为0即可。

先放个运行效果:

AES 可以生成 aes如何制作_python


AES 可以生成 aes如何制作_tkinter_02


RIJNDAEL算法仍然采用分组密码的一种通用结构:对轮函数实施迭代的结构。只是轮函数结构采用的是代替/置换网络结构(SP结构),没有采用DES的Feistel结构。RIJNDAEL的轮函数由以下三层组成:

  1. 非线性层:进行非线性S盒变换ByteSub,由16个S盒并置而成,具有混淆的作用;
  2. 线性混合层:进行行移位变换ShiftRow和列混合变换MixColumn以确保多轮之上的高度扩散;
  3. 密钥加层:进行轮密钥加变换AddRoundKey,将轮密钥简单地异或到中间状态上 ,实现密钥的加密控制作用。

轮函数

轮函数结构采用的是代替/置换网络结构(SP结构),由S盒变换ByteSub、行移位变换ShiftRow、列混合变换MixColumn、轮密钥加变换AddRoundKey组成。伪代码如下:

Round(State,RoundKey)
{	ByteSub(State);
	ShiftRow(State);
	MixColumn(State);
	AddRoundKey(State,RoundKey);
}

最后一轮的轮函数有所不同:

FinalRound(State,RoundKey)
{	ByteSub(State);
	ShiftRow(State);
	AddRoundKey(State,RoundKey);
}

(1)S盒变换ByteSub

ByteSub变换是按字节进行的代替变换,它是非线性字节变换,主要按以下两步进行:

1)把字节的逆用它的乘法逆来代替,其中‘00’的逆就是它自己。a(x)b(x) mod m(x) = 1

2)经1)处理后的字节值再进行如下定义的仿射变换:

AES 可以生成 aes如何制作_tkinter_03


ByteSub变换相当于DES的S盒。它为加密算法提供非线性,是决定加密算法安全性的关键。为确保加密算法是可逆的,ByteSub变换必须是可逆的。

#输入8位的16进制,也就是一个字
#S盒运算
def SubByte(E,flag=1):#flag默认为1是加密
    if flag == 1:
        S = ['63', '7c', '77', '7b', 'f2', '6b', '6f', 'c5', '30', '01', '67', '2b', 'fe', 'd7', 'ab', '76',
             'ca', '82', 'c9', '7d', 'fa', '59', '47', 'f0', 'ad', 'd4', 'a2', 'af', '9c', 'a4', '72', 'c0',
             'b7', 'fd', '93', '26', '36', '3f', 'f7', 'cc', '34', 'a5', 'e5', 'f1', '71', 'd8', '31', '15',
             '04', 'c7', '23', 'c3', '18', '96', '05', '9a', '07', '12', '80', 'e2', 'eb', '27', 'b2', '75',
             '09', '83', '2c', '1a', '1b', '6e', '5a', 'a0', '52', '3b', 'd6', 'b3', '29', 'e3', '2f', '84',
             '53', 'd1', '00', 'ed', '20', 'fc', 'b1', '5b', '6a', 'cb', 'be', '39', '4a', '4c', '58', 'cf',
             'd0', 'ef', 'aa', 'fb', '43', '4d', '33', '85', '45', 'f9', '02', '7f', '50', '3c', '9f', 'a8',
             '51', 'a3', '40', '8f', '92', '9d', '38', 'f5', 'bc', 'b6', 'da', '21', '10', 'ff', 'f3', 'd2',
             'cd', '0c', '13', 'ec', '5f', '97', '44', '17', 'c4', 'a7', '7e', '3d', '64', '5d', '19', '73',
             '60', '81', '4f', 'dc', '22', '2a', '90', '88', '46', 'ee', 'b8', '14', 'de', '5e', '0b', 'db',
             'e0', '32', '3a', '0a', '49', '06', '24', '5c', 'c2', 'd3', 'ac', '62', '91', '95', 'e4', '79',
             'e7', 'c8', '37', '6d', '8d', 'd5', '4e', 'a9', '6c', '56', 'f4', 'ea', '65', '7a', 'ae', '08',
             'ba', '78', '25', '2e', '1c', 'a6', 'b4', 'c6', 'e8', 'dd', '74', '1f', '4b', 'bd', '8b', '8a',
             '70', '3e', 'b5', '66', '48', '03', 'f6', '0e', '61', '35', '57', 'b9', '86', 'c1', '1d', '9e',
             'e1', 'f8', '98', '11', '69', 'd9', '8e', '94', '9b', '1e', '87', 'e9', 'ce', '55', '28', 'df',
             '8c', 'a1', '89', '0d', 'bf', 'e6', '42', '68', '41', '99', '2d', '0f', 'b0', '54', 'bb', '16']
    else:#逆S盒表
        S = ['52', '09', '6a', 'd5', '30', '36', 'a5', '38', 'bf', '40', 'a3', '9e', '81', 'f3', 'd7', 'fb',
             '7c', 'e3', '39', '82', '9b', '2f', 'ff', '87', '34', '8e', '43', '44', 'c4', 'de', 'e9', 'cb',
             '54', '7b', '94', '32', 'a6', 'c2', '23', '3d', 'ee', '4c', '95', '0b', '42', 'fa', 'c3', '4e',
             '08', '2e', 'a1', '66', '28', 'd9', '24', 'b2', '76', '5b', 'a2', '49', '6d', '8b', 'd1', '25',
             '72', 'f8', 'f6', '64', '86', '68', '98', '16', 'd4', 'a4', '5c', 'cc', '5d', '65', 'b6', '92',
             '6c', '70', '48', '50', 'fd', 'ed', 'b9', 'da', '5e', '15', '46', '57', 'a7', '8d', '9d', '84',
             '90', 'd8', 'ab', '00', '8c', 'bc', 'd3', '0a', 'f7', 'e4', '58', '05', 'b8', 'b3', '45', '06',
             'd0', '2c', '1e', '8f', 'ca', '3f', '0f', '02', 'c1', 'af', 'bd', '03', '01', '13', '8a', '6b',
             '3a', '91', '11', '41', '4f', '67', 'dc', 'ea', '97', 'f2', 'cf', 'ce', 'f0', 'b4', 'e6', '73',
             '96', 'ac', '74', '22', 'e7', 'ad', '35', '85', 'e2', 'f9', '37', 'e8', '1c', '75', 'df', '6e',
             '47', 'f1', '1a', '71', '1d', '29', 'c5', '89', '6f', 'b7', '62', '0e', 'aa', '18', 'be', '1b',
             'fc', '56', '3e', '4b', 'c6', 'd2', '79', '20', '9a', 'db', 'c0', 'fe', '78', 'cd', '5a', 'f4',
             '1f', 'dd', 'a8', '33', '88', '07', 'c7', '31', 'b1', '12', '10', '59', '27', '80', 'ec', '5f',
             '60', '51', '7f', 'a9', '19', 'b5', '4a', '0d', '2d', 'e5', '7a', '9f', '93', 'c9', '9c', 'ef',
             'a0', 'e0', '3b', '4d', 'ae', '2a', 'f5', 'b0', 'c8', 'eb', 'bb', '3c', '83', '53', '99', '61',
             '17', '2b', '04', '7e', 'ba', '77', 'd6', '26', 'e1', '69', '14', '63', '55', '21', '0c', '7d']
    A = []
    e = list(E)#len(e)=8
    if len(e) == 8:
        for i in  range(0,8,2):#每次加2
            a = int(e[i],16)#高位16进制转换为10进制
            b = int(e[i+1],16)#低位16进制转换为10进制
            c = S[a*16+b]#找到对应的16进制
            A.append(c)
        B = ''.join(A)
    else:
        for i in range(0, 32, 2):  # 每次加2
            a = int(e[i], 16)  # 高位16进制转换为10进制
            b = int(e[i + 1], 16)  # 低位16进制转换为10进制
            c = S[a * 16 + b]  # 找到对应的16进制
            A.append(c)
        B = ''.join(A)
    return B

(2)行移位变换ShiftRow

在ShiftRow变换中,第0行不移位,第1行循环左移1字节,第2行循环左移2字节,第3行循环左移3字节。

#行移位变换函数
def ShiftRow(B,flag=1):
    A = list(B)
    r0 = []
    r1 = []
    r2 = []
    r3 = []
    R = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
    for i in  range(0,32,2):#每次加2
        if i%8 == 0:#处理第0行
            a = A[i]#'6'
            b = A[i+1]#'3'
            a = a + b#'63'
            r0.append(a)
        elif i%8 == 2:#处理第1行
            a = A[i]
            b = A[i + 1]
            a = a + b
            r1.append(a)
        elif i%8 == 4:#处理第2行
            a = A[i]
            b = A[i + 1]
            a = a + b
            r2.append(a)
        else:#处理第3行
            a = A[i]
            b = A[i + 1]
            a = a + b
            r3.append(a)
    if flag == 1:
        r1 = r1[1:] + r1[:1]#第1行循环左移一个字节
        r2 = r2[2:] + r2[:2]#第2行循环左移两个字节
        r3 = r3[3:] + r3[:3]#第3行循环左移三个字节
    else:
        r1 = r1[3:] + r1[:3]  # 第1行循环左移一个字节
        r2 = r2[2:] + r2[:2]  # 第2行循环左移两个字节
        r3 = r3[1:] + r3[:1]  # 第3行循环左移三个字节
    for i in range(16):
        if i%4 == 0:
            R[i] = r0[i//4]
        elif i%4 == 1:
            R[i] = r1[(i-1)//4]
        elif i%4 ==2:
            R[i] = r2[(i-2)//4]
        else:
            R[i] = r3[(i-3)//4]
    r = ''.join(R)
    #print(r)
    return r

(3)列混合变换MixColumn

在MixColumn变换中,把状态的每一列看做GF(2^8)上的多项式,并于一个固定多项式c(x)相乘后模多项式 x^4+1,其中c(x)为:
AES 可以生成 aes如何制作_AES 可以生成_04
因为c(x)与x^4+1是互素,从而保证c(x)存在逆多项式d(x),使c(x)d(x)=1 mod x^4+1。只有逆多项式d(x)存在,才能正确解密。

#列混合变换函数
def MixColumn(r,flag=1):
    r = list(r)
    A0 = []
    A1 = []
    A2 = []
    A3 = []
    B0 = [0,0,0,0]
    B1 = [0,0,0,0]
    B2 = [0,0,0,0]
    B3 = [0,0,0,0]
    D = [0,0,0,0]
    E = [0,0,0,0]
    for i in range(0,32,2):
        if i < 8:
            a = r[i]
            b = r[i+1]
            a = a + b #a=63
            A0.append(a)#A0=[63,e0,63,89]
        elif i<16:
            a = r[i]
            b = r[i + 1]
            a = a + b
            A1.append(a)#A1=['51','7c','63','63']
        elif i < 24:
            a = r[i]
            b = r[i + 1]
            a = a + b
            A2.append(a)
        else:
            a = r[i]
            b = r[i + 1]
            a = a + b
            A3.append(a)
    A = [A0,A1,A2,A3]#[['63','e0','63','89'],['51','7c','63','63'],['63','63', 'b7','7c'], ['8e','63','63','b7']]
    if flag == 1:#矩阵乘积形式的矩阵
        C = [['02', '03', '01', '01'], ['01', '02', '03', '01'],['01', '01', '02', '03'], ['03', '01', '01', '02']]
    else:
        C = [['0E', '0B', '0D', '09'], ['09', '0E', '0B', '0D'],['0D', '09', '0E', '0B'], ['0B', '0D', '09', '0E']]
    B = [B0,B1,B2,B3]
    for k in range(4):#循环A
        for j in range(4):#循环C
            for i in range(4):#两位16进制相乘
                if flag == 1:
                    d = xiangcheng_16(C[j][i],A[k][i])#d为2为16进制
                    D[i] = d
                else:
                    d = xiangcheng_16_jiemi(C[j][i], A[k][i])  # d为2为16进制
                    D[i] = d
            for i in range(4):#异或后即是[1,1]
                if i == 0:
                    z = D[i]
                else:
                    z = yihuo_16(z,D[i])
                B[k][j] = z

    for i in range(4):
        a = B[i]
        b_1 = [str(i) for i in a]
        b = ''.join(b_1)
        E[i] = b
    e = ''.join(E)
    return e

(4)轮密钥加变换AddRoundKey

AddRoundKey变换是利用轮密钥对状态进行模2相加的变换。轮密钥长度等于数据块长度。轮密钥根据轮密钥产生算法通过主密钥扩展和选择得到。

#轮密钥加函数,输入状态和密钥,RoundKey是32位字符串
#轮密钥与经过列混合之后的数相加
#RoundKey是32位16进制
def AddRoundKey(State,RoundKey):
    k = list(RoundKey)
    d = list(State)
    E = []
    for i in range(32):
        a = int(k[i], 16)#16进制转换为10进制
        b = int(d[i], 16)
        e =a ^ b        #10进制可以进行异或
        e = format(e,'x')#异或后的值转换为16进制
        E.append(e)     #16进制以列表存放
    E =''.join(E)       #转换为字符串
    return E

轮密钥产生算法

本文主要针对128位的密钥展开。
轮密钥根据轮密钥产生算法有主密钥产生得到。轮密钥产生分为两步:密钥扩展和轮密钥选择,且遵循以下原则:

  1. 轮密钥的比特总数为数据块长度与轮数加1 的乘积。例如,对于128位的分组长度和10轮迭代,轮函数的总长度为128*(10+1)=1048位。
  2. 首先将用户密钥扩展成一个扩展密钥。
  3. 再从扩展密钥中选出轮密钥:第一个轮密钥由扩展密钥中的前Nb个字组成,第二个轮密钥由接下来的Nb个字组成,以此类推。

(1)密钥扩展

用一个字(四个字节)元素的一维数组W[Nb*(Nr+1)]存储扩展密钥。把主密钥放在数组W最开始的Nk个字中,其他的字由它前面的字经过处理后得到。
符号说明:CipherKey表示主密钥,它是一个有Nk个密钥字的一维数组。W为存储扩展密钥的一维数组。因为是针对128位的主密钥,Nk=4,Nb=4,Nr=10。

针对Nk<=6的密钥扩展策略
KeyExpansion(CipherKey,W)
{	For (I=0;I<Nk;I++)	
		W[I] = CipherKey[I];
	For (I=Nk;I<Nb*(Nr+1);I++)
	{	Temp = W[I-1];
		IF(I%Nk==0)
			Temp=SubByte(Rotl(Temp))⨁Rcon[I/Nk];
		W[I] = W[I-Nk]⨁Temp;
	}
}

最前面的Nk个字是由主密钥填充的。这之后的每一个字W[I]等于前面的W[I-1]与Nk个位置之前的字W[I-Nk]的异或。如果I是Nk的整数倍,在异或之前要先对W[I-1]进行Rotl变换和SubByte变换,再异或一个轮常数Rcon。
其中Rotl是对一个字里的字节以字节为单位进行循环移位的函数,设W=(A,B,C,D),则Rotl(W)=(B,C,D,A)。
轮常数Rcon与Nk无关,且定义为:

Rcon[i] = (RC[i],'00','00','00')
RC[0] = ‘01’
RC[i] = xtime(RC[i-1])
#在GF(2^8)中,
#a(x)b(x) mod m(x) = 1
#倍增函数xtime(b(x))定义为 x*b(x) mod m(x)

使用轮函数Rcon的目的是为了防止不同轮的轮密钥存在相似性。由于轮函数Rcon是变化的,可使不同轮的轮密钥有明显的不同。

(2)轮密钥选择

轮密钥I由轮密钥缓冲区W[Nb * I]到W[Nb*(I+1)-1]的字组成。

AES 可以生成 aes如何制作_python_05

#!!千万要注意格式化输入输出的16进制或者2进制数据的位数
#密钥扩展函数
#CipherKey是一个4字的数组,W是一个44字的数组
#输入的密钥是32位的16进制,也就是要先分成4个字
def KeyExpansion(CipherKey):
    C = list(CipherKey)
    c = [[],[],[],[]]
    for i in range(32):
        if i < 8:#每8位放一个列表
            c[0].append(C[i])
        elif i < 16:
            c[1].append(C[i])
        elif i < 24:
            c[2].append(C[i])
        else:
            c[3].append(C[i])
    for i in range(4):
        c[i] = ''.join(c[i])#把c[i]由列表化为字符串,字符串长8位

    W = [0 for i in range(44)]
    #为了增大效率,将计算得出的倍增函数结果直接存储
    #b列表存放计算之后的轮常数Rcon,RC[0]...
    b = ['01000000','02000000', '04000000', '08000000', '10000000', '20000000',
         '40000000', '80000000', '1b000000', '36000000', '6c000000']
    for i in range(4):#前4个字就是首轮密钥
        W[i] = c[i]
    #开始扩展
    for i in range(4,44):
        Temp = W[i-1]
        if i%4==0:
            a = Rotl(Temp)#a为一个8位的字符串,对一个字里的字节以字节为单位进行循环移位的函数
            x = SubByte(a)#输入一个8位的16进制,也就是一个字,S盒变换
            Temp = yihuo_32(x,b[(i//4)-1])

        W[i] = yihuo_32(W[i - 4], Temp)
    return W #生成扩展密钥

#两个8位16进制数,即32位2进制的异或运算
def yihuo_32(a0,a1):
    A = []
    ten_a0 = int(a0,16)
    ten_a1 = int(a1, 16)
    ten_bin_a0 = '{:032b}'.format(ten_a0)
    ten_bin_a1 = '{:032b}'.format(ten_a1)
    list_a0 = list(ten_bin_a0)
    list_a1 = list(ten_bin_a1)
    for i in range(32):
        a = int(list_a0[i])^int(list_a1[i])
        A.append(a)
    c_1 = [str(i) for i in A]
    c = ''.join(c_1)
    c = int(c, 2)
    c = '{:08x}'.format(c)#这一步16进制没规定规格坑死人
    return c

#左循环移位函数,输入一个字,以字节为单位左移,输出也是一个字的字符串
#对一个字里的字节以字节为单位进行循环移位的函数
def Rotl(W):
    a = list(W)#有八位
    a = a[2:] + a[:2]#左移两位16进制数
    b = ''.join(a)#重新转换为字符串
    return b

解密算法的过程之后有时间再补上,代码已经实现了AES加密和解密。
感想:想写好一篇博客实在是太难,太花费时间了,写了一大堆下来连自己都看不太明白。现在主要是为了记录,后续慢慢修改吧。写得太乱了,欢迎批评。