RIJNDAEL 加密算法

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


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)处理后的字节值再进行如下定义的仿射变换:

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)=8if len(e) == 8:for i in  range(0,8,2):#每次加2a = 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):  # 每次加2a = 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):#每次加2if 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 + br1.append(a)elif i%8 == 4:#处理第2行a = A[i]b = A[i + 1]a = a + br2.append(a)else:#处理第3行a = A[i]b = A[i + 1]a = a + br3.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)为:
c(x)=‘03’x3+‘01’x2+‘01’x+‘02’c(x) = ‘03’x^3 + ‘01’x^2 + ‘01’x + ‘02’ c(x)=‘03’x3+‘01’x2+‘01’x+‘02’
因为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=63A0.append(a)#A0=[63,e0,63,89]elif i<16:a = r[i]b = r[i + 1]a = a + bA1.append(a)#A1=['51','7c','63','63']elif i < 24:a = r[i]b = r[i + 1]a = a + bA2.append(a)else:a = r[i]b = r[i + 1]a = a + bA3.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):#循环Afor j in range(4):#循环Cfor i in range(4):#两位16进制相乘if flag == 1:d = xiangcheng_16(C[j][i],A[k][i])#d为2为16进制D[i] = delse:d = xiangcheng_16_jiemi(C[j][i], A[k][i])  # d为2为16进制D[i] = dfor i in range(4):#异或后即是[1,1]if i == 0:z = D[i]else:z = yihuo_16(z,D[i])B[k][j] = zfor i in range(4):a = B[i]b_1 = [str(i) for i in a]b = ''.join(b_1)E[i] = be = ''.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]的字组成。

#!!千万要注意格式化输入输出的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加密和解密。
感想:想写好一篇博客实在是太难,太花费时间了,写了一大堆下来连自己都看不太明白。现在主要是为了记录,后续慢慢修改吧。写得太乱了,欢迎批评。

源码:https://github.com/QYQ323/cryptology.git

AES算法加解密及简单图像化界面实现相关推荐

  1. AES方式加解密的简单介绍

    上面一篇文章介绍了使用DES方式进行加解密( DES方式加解密的简单介绍),我们说了DES由于使用8个字节(64bit)密钥进行加解密,所以安全性不够(当然这里的不够都是相对的),所以现在使用了密钥更 ...

  2. RSA,AES算法加解密

    密码的前世今生 密码Cryptology,是一种混淆人们视听的一种技术.将可以被正常认知的信息转变成不可以被识别的信息.有交流就有信息,有信息的传递,自然会产生秘密,这是文明发展的必然.密码的出生自然 ...

  3. SM2国密算法加解密

    接口安全设计原则的一个点就是数据不能明文传输,除了https这个必须的请求外,接口数据加密也是一个重要的方式,下面介绍一下SM2国密算法加解密的使用方式. 这里我就针对目前前后端分离架构的方式来简单介 ...

  4. java 和 c# 下的RSA证书+AES+DES加解密实现

    java 和 c# 下的RSA+AES+DES加解密实现 前言 在实际应用中,经常有需要使用加解密的情况,RSA\AES\DES是比较常用的几种加解密方式,使用和实现方式都比较成熟可靠,本文简要介绍一 ...

  5. GPG对文件加解密的简单实现

    解密时如何覆盖已经存在的解密后文件,而不是弹出询问框是否覆盖 初识GPG 加解密实现 gui加解密 生成密钥 命令行方式加解密 信任度设置 方法一 方法二 参考链接 解密时如何覆盖已经存在的解密后文件 ...

  6. 国密SM2算法的只求理解不求甚解 (4/5)SM2算法加解密协议

    国密SM2算法的只求理解不求甚解 (1/5)前置数学知识:模运算 国密SM2算法的只求理解不求甚解 (2/5)前置数学知识:平面几何 国密SM2算法的只求理解不求甚解 (3/5)SM2算法数学模型 国 ...

  7. RSA算法加解密的C语言实现

    RSA算法加解密的C语言实现 一. 实现的功能 二. 源代码 一. 实现的功能 用户输入明文 自动随机生成较大的数p和q,并对它们进行素性检测,检测成功之后,程序继续 计算Φ(n)的值,并求出它的所有 ...

  8. ElGamal算法加解密

    文章目录 ElGamal算法加解密 算法流程 代码实现 测试数据 运行结果 ElGamal算法加解密 算法流程 参数选取:素数p,生成元g,小于p的随机非负整数x 产生密钥:公钥: y = g ^ x ...

  9. php aes 256 加解密,PHP完整的AES加解密算法使用及例子(256位)

    依赖PHP自身的mcrypt扩展 class aes { // CRYPTO_CIPHER_BLOCK_SIZE 32 private $_secret_key = 'default_secret_k ...

最新文章

  1. Hadoop集群的基本操作(三:HBase的基本操作)
  2. 机器学习模型评估与超参数调优详解
  3. Linux 增大Swap
  4. Oracle:FOR循环语句练习
  5. Anaconda简介:它是什么,以及如何安装
  6. 注册制后st还有投资价值吗?
  7. LFSR(线性反馈移位寄存器)
  8. 游戏太难通关?教你用CE和Python写一个属于自己的植物大战僵尸修改器(无限阳光,无限金币,无冷却时间)
  9. 驻波在物理上的应用与魅力
  10. JAVA Signal Handing
  11. Python数据可视化:分析38个城市的居住自由指数
  12. 印象笔记,为知笔记和Effie哪个更适合商业机构提案人员?
  13. 【再聚乌镇】百余家大数据企业齐聚,发布七大榜单两大产业地图,共览大数据产业全景!...
  14. JavaScript-百炼成仙(第1节掌握JavaScript基础1.1-1.21)
  15. 关于weinre教程使用的补充(weinre-jar-1.6.1.zip下载)
  16. 北京小学几年级学计算机,北京小学低年级开学时间2021最新消息
  17. 小孔成像总结_【初中物理】物理解题技巧+方法总结
  18. 解密了一封300多年前的信,“透视”书信首次实现
  19. 前端ThinkJS框架解析
  20. 人声计算机音乐,如何去除音乐中的人声?

热门文章

  1. 大数据在保险界的应用
  2. 图像配准(image registration)与图像融合(image fusion)
  3. 联发科嵌入式实习面经
  4. 数据库中码、超码、主码、候选码
  5. 团队精神(Teamwork)
  6. win10如何修改C盘User下的用户名
  7. 除了这门升级中的V2Pro课程,恐怕你找不到更好的学验证的途径了
  8. CSS样式表中的颜色表
  9. Python干货项目:【新闻急先锋】新闻API获取谷歌头条新闻
  10. 单片机C51使用一个按键控制继电器开关通断