加解密算法的实现python_DES加密解密算法之python实现版

本文详细介绍了DES加密算法的背景、特点、工作流程,并提供了Python代码实现,包括初始置换、f函数、扩展置换、S盒、P盒等关键步骤。此外,还提到了DES算法的局限性和后续的AES标准。最后,文章提供了加密和解密的完整代码示例。
摘要由CSDN通过智能技术生成

一、DSE算法背景介绍

1. DES的采用

1979年,美国银行协会批准使用

1980年,美国国家标准局(ANSI)赞同DES作为私人使用的标准,称之为DEA(ANSI X.392)

1983年,国际化标准组织ISO赞同DES作为国际标准,称之为DEA-1

该标准规定每五年审查一次,计划十年后采用新标准

最近的一次评估是在1994年1月,已决定1998年12月以后,DES将不再作为联邦加密标准。

2.DES算法特点

1) 分组加密算法:

以64位为分组。64位一组的明文从算法一端输入,64位密文从另一端输出。

2) 对称算法:

加密和解密用同一密钥。

3) 有效密钥长度为56位。

密钥通常表示为64位数,但每个第8位用作奇偶校验,可以忽略。输入的64bit秘钥只有56bit作为有效位

二、DES算法描述

1、DES算法加密流程的文字描述

DES对64位的明文分组进行操作。通过一个初始置换,将明文分组分成左半部分和右半部分,各32位长。然后进行16轮完全相同的运算,这些运算被称为函数f,在运算过程中数据与密钥结合。经过16轮后,左、右半部分合在一起,经过一个末置换(初始置换的逆置换),这样该算法就完成了。

二、DES算法加密流程的图形描述

图一

图二

三、具体参数解释

1、IP置换和IP逆置换

IP置换作用于进行16轮f函数作用之前,IP逆置换作用于16轮f函数作用之后。IP置换和IP逆置换表如下图所示:

图三

该表的含义解释:例如IP置换表中的第一行第一列的数值为58,就代表将明文的第58位替换到第一位,例如明文初始的第58位是1,第1位是0,第39位是0,根据上表替换后的64位待加密文本为:第一位是1,第58位是0。之后提到的置换表也是这个意思。

2、f函数

经过初始置换后,进行16轮完全相同的运算。这些运算被称为f,在运算过程中数据与密钥结合。f函数作用于每轮的key值和每轮的待加密文本的右半部分,即Ki,Ri

f函数作用于每轮的key值和每轮的待加密文本的右半部分,即Ki,Ri

图四

函数|的输出经过一个异或运算,和左半部分结合,其结果成为新的右半部分,原来的右半部分成为新的左半部分。

图五

3、扩展置换,扩展置换将32位的R部分,扩展为48位

扩展表如图所示:

图六

4、S盒替换,S盒替换将扩展替换后与ki(第i轮KEY值)异或后的结果压缩为32位,每6位与一个S盒运算,运算后压缩为4位,共有八个S盒,分为S1,S2......S8。具体如下图所示

图七

S盒介绍,以第六个S盒,S6为例

图八

设入的六位为b1,b2,b3,b4,b5,b6,b1、b6位组合得到列号,b2,b3,b4,b5组合得到行号。具体实现看底下的代码。确定行号和列好后将6位替换为4位数据,数据段具体值即为行列相交处的值,例如3行4列即为5,5的二进制码位1001,将原来的6位替换为4位即1001

4、P盒替换

P盒替换将S盒替换之后的结果进行一次位置替换,替换表如图所示:

图九

5 最后讲一下重头戏——16轮秘钥生成

先上个图

图11

图中的置换选择1和置换选择2跟之前将的置换选择原理是一样的,在代码中你能看到置换表

这里也给出来吧

图12

C0,D0指的是将56位(注位都是指的bit)秘钥分为左右两部分,C0代表左半部分,D0是右半部分。循环左移指的是将bit位循环左移,移除的位补到末尾,l例如100010循环左移一位之后位000101

每轮秘钥生成的时候循环左移的次数都不一样,具体如下表

图13

四、以上都是文字加图表描述,下面直接上代码,代码我都加了详细的备注,大家结合上面的说明一定能读懂滴。有点长,大家细心看

#writter:liuyang@BUAASoftwareDepartment

#date:2014/05/14

#function:DEC加密、解密算法

#contact me:734056968@qq.com

#IP置换表

IP_table=[58, 50, 42, 34, 26, 18, 10,  2,

60, 52, 44, 36, 28, 20, 12,  4,

62, 54, 46, 38, 30, 22, 14,  6,

64, 56, 48, 40, 32, 24, 16,  8,

57, 49, 41, 33, 25, 17,  9,  1,

59, 51, 43, 35, 27, 19, 11,  3,

61, 53, 45, 37, 29, 21, 13,  5,

63, 55, 47, 39, 31, 23, 15,  7

]

#逆IP置换表

_IP_table=[40,  8, 48, 16, 56, 24, 64, 32,

39,  7, 47, 15, 55, 23, 63, 31,

38,  6, 46, 14, 54, 22, 62, 30,

37,  5, 45, 13, 53, 21, 61, 29,

36,  4, 44, 12, 52, 20, 60, 28,

35,  3, 43, 11, 51, 19, 59, 27,

34,  2, 42, 10, 50, 18, 58, 26,

33,  1, 41,  9, 49, 17, 57, 25

]

#S盒中的S1盒

S1=[14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,

0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,

4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,

15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13

]

#S盒中的S2盒

S2=[15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,

3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,

0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,

13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9

]

#S盒中的S3盒

S3=[10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,

13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,

13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,

1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12

]

#S盒中的S4盒

S4=[7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,

13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,

10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,

3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14

]

#S盒中的S5盒

S5=[2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,

14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,

4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,

11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3

]

#S盒中的S6盒

S6=[12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,

10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,

9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,

4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13

]

#S盒中的S7盒

S7=[4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,

13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,

1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,

6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12

]

#S盒中的S8盒

S8=[13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,

1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,

7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,

2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11

]

# S盒

S=[S1,S2,S3,S4,S5,S6,S7,S8]

#P盒

P_table=[16,  7, 20, 21,

29, 12, 28, 17,

1, 15, 23, 26,

5, 18, 31, 10,

2,  8, 24, 14,

32, 27,  3,  9,

19, 13, 30,  6,

22, 11,  4, 25

]

#压缩置换表1,不考虑每字节的第8位,将64位密钥减至56位。然后进行一次密钥置换。

yasuo1_table=[ 57, 49, 41, 33, 25, 17,  9,

1, 58, 50, 42, 34, 26, 18,

10,  2, 59, 51, 43, 35, 27,

19, 11,  3, 60, 52, 44, 36,

63, 55, 47, 39, 31, 23, 15,

7, 62, 54, 46, 38, 30, 22,

14,  6, 61, 53, 45, 37, 29,

21, 13,  5, 28, 20, 12,  4

]

#压缩置换表2,用于将循环左移和右移后的56bit密钥压缩为48bit

yasuo2_table=[14, 17, 11, 24,  1,  5,

3, 28, 15,  6, 21, 10,

23, 19, 12,  4, 26,  8,

16,  7, 27, 20, 13,  2,

41, 52, 31, 37, 47, 55,

30, 40, 51, 45, 33, 48,

44, 49, 39, 56, 34, 53,

46, 42, 50, 36, 29, 32

]

#用于对数据进行扩展置换,将32bit数据扩展为48bit

extend_table=[32,  1,  2,  3,  4,  5,

4,  5,  6,  7,  8,  9,

8,  9, 10, 11, 12, 13,

12, 13, 14, 15, 16, 17,

16, 17, 18, 19, 20, 21,

20, 21, 22, 23, 24, 25,

24, 25, 26, 27, 28, 29,

28, 29, 30, 31, 32,1

]

#将字符转换为对应的Unicode码,中文用2个字节表示def char2unicode_ascii(intext,length):

outtext=[]

for i in range(length):

outtext.append(ord(intext[i]))

return outtext

#将Unicode码转为bit

def unicode2bit(intext,length):

outbit=[]

for i in range(length*16):

outbit.append((intext[int(i/16)]>>(i%16))&1)#一次左移一bit

return outbit

#将8位ASCII码转为bit

def byte2bit(inchar,length):

outbit=[]

for i in range(length*8):

outbit.append((inchar[int(i/8)]>>(i%8))&1)#一次左移一bit

return outbit

#将bit转为Unicode码

def bit2unicode(inbit,length):

out=[]

temp=0

for i in range(length):

temp=temp|(inbit[i]<

if i%16==15:

out.append(temp)

temp=0

return out

#将bit转为ascii 码

def bit2byte(inbit,length):

out=[]

temp=0

for i in range(length):

temp=temp|(inbit[i]<

if i%8==7:

out.append(temp)

temp=0

return out

#将unicode码转为字符(中文或英文)

def unicode2char(inbyte,length):

out=""

for i in range(length):

out=out+chr(inbyte[i])

return out

#生成每一轮的key

def createKeys(inkeys):

keyResult=[]

asciikey=char2unicode_ascii(inkeys,len(inkeys))

keyinit=byte2bit(asciikey,len(asciikey))

#    print("keyinit=",end='')

#    print(keyinit)

#初始化列表key0,key1

key0=[0 for i in range(56)]

key1=[0 for i in range(48)]

#进行密码压缩置换1,将64位密码压缩为56位

for i in range(56):

key0[i]=keyinit[yasuo1_table[i]-1]

#进行16轮的密码生成

for i in range(16):

#---------确定左移的次数----------

if (i==0 or i==1 or i==8 or i==15):

moveStep=1

else:

moveStep=2

#------------------------------

#--------分两部分,每28bit位一部分,进行循环左移------------

for j in range(moveStep):

for k in range(8):

temp=key0[k*7]

for m in range(7*k,7*k+6):

key0[m]=key0[m+1]

key0[k*7+6]=temp

temp=key0[0]

for k in range(27):

key0[k]=key0[k+1]

key0[27]=temp

temp=key0[28]

for k in  range(28,55):

key0[k]=key0[k+1]

key0[55]=temp

#-----------------------------------------------------

#------------对56位密钥进行压缩置换,压缩为48位-------------

for k in range(48):

key1[k]=key0[yasuo2_table[k]-1]

keyResult.extend(key1)

#------------------------------------------------------

return keyResult

def DES(text,key,optionType):

keyResult=createKeys(key)

finalTextOfBit=[0 for i in range(64)]

finalTextOfUnicode=[0 for i in range(4)]

#    print(keyResult)

if optionType==0:#选择的操作类型为加密

tempText=[0 for i in range(64)]#用于临时盛放IP逆置换之前,将L部分和R部分合并成64位的结果

extendR=[0 for i in range(48)]#用于盛放R部分的扩展结果

unicodeText=char2unicode_ascii(text,len(text))

#        print(unicodeText)

bitText=unicode2bit(unicodeText,len(unicodeText))

#        print(bitText)

initTrans=[0 for i in range(64)]#初始化,用于存放IP置换后的结果

#------------------进行初始IP置换---------------

for i in range(64):

initTrans[i]=bitText[IP_table[i]-1]

#将64位明文分为左右两部分

L=[initTrans[i] for i in range(32)]

R=[initTrans[i] for i in range(32,64)]

#开始进行16轮运算

for i in range(16):

tempR=R #用于临时盛放R

#-----------进行扩展,将32位扩展为48位--------

for j in range(48):

extendR[j]=R[extend_table[j]-1]

#           print(len(keyResult))

keyi=[keyResult[j] for j in range(i*48,i*48+48)]

#----------与key值进行异或运算----------------

XORResult=[0 for j in range(48)]

for j in range(48):

if keyi[j]!=extendR[j]:

XORResult[j]=1

SResult=[0 for k in range(32)]

#---------开始进行S盒替换-------------------

for k in range(8):

row=XORResult[k*6]*2+XORResult[k*6+5]

column=XORResult[k*6+1]*8+XORResult[k*6+2]*4+XORResult[k*6+3]*2+XORResult[k*6+4]

temp=S[k][row*16+column]

for m in range(4):

SResult[k*4+m]=(temp>>m)&1

#-----------------------------------------

PResult=[0 for k in range(32)]

#--------------开始进行P盒置换----------------

for k in range(32):

PResult[k]=SResult[P_table[k]-1]

#------------------------------------------

#--------------与L部分的数据进行异或------------

XORWithL=[0 for k in range(32)]

for k in range(32):

if L[k]!=PResult[k]:

XORWithL[k]=1

#----------------------------------------------

#-------------将临时保存的R部分值,即tempR复制给L------

L=tempR

R=XORWithL

#----交换左右两部分------

L,R=R,L

#-----合并为一部分

tempText=L

tempText.extend(R)

#-----------IP逆置换--------

for k in range(64):

finalTextOfBit[k]=tempText[_IP_table[k]-1]

finalTextOfUnicode=bit2byte(finalTextOfBit,len(finalTextOfBit))

#        print(finalTextOfUnicode)

finalTextOfChar=unicode2char(finalTextOfUnicode,len(finalTextOfUnicode))

#        print(finalTextOfChar)

return finalTextOfChar

else:#选择的操作类型为解密

tempText=[0 for i in range(64)]#用于临时盛放IP逆置换之前,将L部分和R部分合并成64位的结果

extendR=[0 for i in range(48)]#用于盛放R部分的扩展结果

unicodeText=char2unicode_ascii(text,len(text))

#        print(unicodeText)

bitText=byte2bit(unicodeText,len(unicodeText))

#        print(bitText)

initTrans=[0 for i in range(64)]#初始化,用于存放IP置换后的结果

#------------------进行初始IP置换---------------

for i in range(64):

initTrans[i]=bitText[IP_table[i]-1]

#将64位明文分为左右两部分

L=[initTrans[i] for i in range(32)]

R=[initTrans[i] for i in range(32,64)]

#-----------------开始16轮的循环-----------------

for i in range(15,-1,-1):

tempR=R #用于临时盛放R

#-----------进行扩展,将32位扩展为48位--------

for j in range(48):

extendR[j]=R[extend_table[j]-1]

keyi=[keyResult[j] for j in range(i*48,i*48+48)]

#----------与key值进行异或运算----------------

XORResult=[0 for j in range(48)]

for j in range(48):

if keyi[j]!=extendR[j]:

XORResult[j]=1

SResult=[0 for k in range(32)]

#---------开始进行S盒替换-------------------

for k in range(8):

row=XORResult[k*6]*2+XORResult[k*6+5]

column=XORResult[k*6+1]*8+XORResult[k*6+2]*4+XORResult[k*6+3]*2+XORResult[k*6+4]

temp=S[k][row*16+column]

for m in range(4):

SResult[k*4+m]=(temp>>m)&1

#-----------------------------------------

PResult=[0 for k in range(32)]

#--------------开始进行P盒置换----------------

for k in range(32):

PResult[k]=SResult[P_table[k]-1]

#------------------------------------------

#--------------与L部分的数据进行异或------------

XORWithL=[0 for k in range(32)]

for k in range(32):

if L[k]!=PResult[k]:

XORWithL[k]=1

#----------------------------------------------

#-------------将临时保存的R部分值,即tempR复制给L------

L=tempR

R=XORWithL

#----交换左右两部分------

L,R=R,L

#-----合并为一部分

tempText=L

tempText.extend(R)

#-----------IP逆置换--------

for k in range(64):

finalTextOfBit[k]=tempText[_IP_table[k]-1]

finalTextOfUnicode=bit2unicode(finalTextOfBit,len(finalTextOfBit))

#        print(finalTextOfUnicode)

finalTextOfChar=unicode2char(finalTextOfUnicode,len(finalTextOfUnicode))

#        print(finalTextOfChar)

return finalTextOfChar

def main():

text=input("请输入要操作的文本:  ")

print(" ".join(["输入的文本时",text]))

optionType=input("请选择是进行加密还是解密,加密输入0,解密输入1:  ")

while(not(optionType=='0' or optionType=='1')):

print("Wrong!!!选择的操作类型只能是0或者是1")

optionType=input("请选择是进行加密还是解密,加密输入0,解密输入1:  ")

length=len(text)

Result=""

if optionType=='0':

#        f=open('D:\encyptText.txt','w')

#----------若输入文本的长度不是4的整数倍,即不是64字节的整数倍,用空格补全(此处为了加密中文,用的是unicode编码,即用16字节表示一个字符)-------

text=text+(length%4)*" "

length=len(text)

key=input("请输入8位加密密码: ")

while(len(key)!=8):

print("wrong!!请输入8位密码")

key=input("请输入8位加密密码: ")

print("加密后的文本:",end=" ")

for i in range(int(length/4)):

tempText=[text[j] for j in range(i*4,i*4+4)]

Result="".join([Result,DES(tempText,key,int(optionType))])

#            f.write(Result)

print(Result)

if optionType=='1':

#----------若输入文本的长度不是8的整数倍,即不是64字节的整数倍,用空格补全(此处解密出来的密文用的是每8bit转换为一个ascii码,所以生成的八位表示的字符)-------

#        text=text+(length%8)*" "

length=len(text)

key=input("请输入8位解密密码: ")

while(len(key)!=8):

print("wrong!!请输入8位密码")

key=input("请输入8位解密密码: ")

print("解密后的文本:",end=" ")

for i in range(int(length/8)):

tempText=[text[j] for j in range(i*8,i*8+8)]

Result="".join([Result,DES(tempText,key,int(optionType))])

print(Result)

六、运行截图

图13

七、后记

1、要用于具体项目的话,要把编码格式弄清楚,看你项目中的编码格式是什么,unicode,utf-8,gdb等否则会出错

2、文本输入的时候不能有换行,如果需要换行加一下转换符,调一调

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值