密码学课程设计之DES对称加密

前言

最近在进行密码学课程设计, 感觉拿python进行设计会显得比较简洁易懂,本人python比较渣渣,所以就拿出来练一练。用零零碎碎的时间写了五六天才把主干部分写完,真是菜哭我自己了。在此还需要感谢一叶飘零学长的博客,遇到困惑时果然飘零学长的博客就是最好的去处。

正文

加密原理

FoEdsg.md.png

密钥生成

1.输入8位字符密钥转换为64位二进制;

2.经过64位密钥经过PC-1置换为56位;

3.将56位分成两部分分别进行循环左移;

4.左移后组合,再进入PC-2置换为48位,第一轮密钥生成结束;

5.循环左移以后的两部分继续循环左移,再次进入PC-2置换,生成48位子密钥,如此进行16轮,存储16个48位的子密钥

加密处理

1.输入的字符先转换为二进制,每64位为一组进行加密;

2.每一组64位的二进制先进行IP置换打乱;

3.然后将64位分成2部分,分别放入Li和Ri

4.将Ri经过F函数处理,再与Li异或,然后将值赋给R(i+1)

5.将Ri赋值给L(i+1)

6.最后一轮,直接将Ri赋给R(i+1),再将Ri经过F函数处理,再与Li异或,然后将值赋给L(i+1)

7.将L和R合并后经过逆IP盒,得到密文C

F函数

1.先将输入的32位Ri进行扩展置换E,转换为48位

2.再与生成的子密钥进行异或

3.将异或后的值经过S盒压缩为32位

4.再进行P置换打乱顺序

加密详细过程

各个置换dict

dic_IP=[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]

dic_key1=[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]

dic_key2=[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]

dic_e=[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]

dic_s=[[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],[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],[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],[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],[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],[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],[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],[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]]

dic_p=[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]

dic_n=[1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]

dic_IP2=[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]

初始IP置换

将初始明文字符转换为64位二进制,并进行第一次IP置换。

需要注意的就是在python中用format函数非常方便,没有bin函数开头的0b,在这里需要将转换的二进制字符补足8位(在左边补0即可)

def init_p(p):
	s1=""
	res=""
	for i in range(8):
		b='{:08b}'.format(ord(p[i]))
		s1+=b
	for i in range(64):
		res+=s1[dic_IP[i]-1]
	return res            

字符串的循环左移

生成16个子密钥时需要循环左移函数,使用到的就是py的切片,先需要对密钥56位分为两部分,分别28位,然后这两部分分别循环左移

def zuoyi(n,ki):
	temp=ki[n:len(ki)]
	temp=temp+ki[0:n]
	return temp

密钥初始编排-PC1

需要对输入的8个字符进行二进制转换并补足64位,然后将这64位字符进行PC-1置换,从64位置换为56位

def init_pc_1(k):
	k1=""
	k2=""
	for i in range(8):
		b='{:08b}'.format(ord(k[i]))
		k1+=b                            
	for i in range(56):
		k2+=k1[dic_key1[i]-1]
	return k2        

密钥二次编排-PC2

将每次循环左移的密钥组合后进行PC-2置换,由56位转换为48位,并存储

def init_pc_2(k):
	res=""
	for i in range(48):
		res+=k[dic_key2[i]-1]            #将56位转换为48位
	return res                 

按位异或

两个相同长度的字符进行按位异或

def xor(r_e,ki):
	res=""
	for i in range(len(r_e)):
		xor_res=int(r_e[i],10)^int(ki[i],10)
		if xor_res==1:
			res+="1"
		else:
			res+="0"
	return res

E盒扩展

将转换为二进制的64位明文分成两部分,Li和Ri,需要将Ri从32位二进制置换为48位,需要经过E盒扩展

def box_e(r):
	temp_r=""
	for i in range(48):
		temp_r+=(r[dic_e[i]-1])          #将32位扩展为48位
	return temp_r

S盒处理

这里有8个S盒,从E盒出来的48位数据分为8组,每组6位,分别进入8个S盒,上面将这8个S盒分别装入列表,并将这8个列表装入一个大列表,类似于C++里的二维数组。

将6位中的首位和末位组合并转换为10进制,为行

将6位中剩下的4位组合转换为10进制,为列

查找到对应行列的S盒中的值,将其转换为二进制字符并存储在res中

def box_s(r):
	j=0
	res=""
	for i in range(0,len(r),6):                     #步长为6
		begins=r[i:i+6]
		hang=int(begins[0]+begins[5],2)
		lie=int(begins[1:5],2)
		num='{:04b}'.format(dic_s[j][16*hang+lie])  #将s盒中对应数字转为二进制字符串并补满4位
		res+=num
		j=j+1
	return res

P盒置换

def box_p(r):
	res=""
	for i in range(32):
		res+=r[dic_p[i]-1]
	return res

生成16个子密钥

64位密钥先经过pc1置换为56位,分成两部分,分别循环左移,组合后进行二次密钥编排,将产生的16个子密钥按序存储在keylist中

def key_list(key):
	temp_1=init_pc_1(key)
	k_l=temp_1[0:28]
	k_r=temp_1[28:56]
	for i in range(16):
		k_l=zuoyi(dic_n[i],k_l)          #前28位左移n
		k_r=zuoyi(dic_n[i],k_r)          #后28位左移n
		key_yiwei=k_l+k_r
		key_res=init_pc_2(key_yiwei)
		keylist.append(key_res)

F函数

先E盒置换,再与子密钥异或,再S盒处理,最后进行P盒处理

def fun_F(str1,key):
	res_e=box_e(str1)               
	res_xor=xor(res_e,key)
	res_s=box_s(res_xor)
	res_p=box_p(res_s)
	return res_p

IP逆置换

def  IP_NI(c):
	res=""
	for i in range(64):
		res+=c[dic_IP2[i]-1]
	return res

加密一组

8个字符的加密

def DES_encode_one_group(p,k):
	p_bin=init_p(p)        #str 64
	p_left=p_bin[0:32]     #str 32 left
	p_right=p_bin[32:]     #str 32 right
	key_list(k)          #生成16个子密钥
	for i in range(15):    #16轮迭代
		p_temp=p_right                  #暂存
		fin_r=fun_F(p_right,keylist[i]) #Ri经过F函数
		p_right=xor(fin_r,p_left)       #Ri
		p_left=p_temp                   #Li
	final_right=p_right
	final_left=xor(fun_F(p_right,keylist[15]),p_left)
	fin=final_left+final_right
	fin=IP_NI(fin)
	return fin

加密全部

8个字符一组进行分组,每组分别进行加密

def DES_encode(p,k):
	res=""
	i=0
	while p[i:i+8]!="":
		res+=DES_encode_one_group(p[i:i+8],key)
		i=i+8
	return res

解密一组

一组64位二进制进行解密

def DES_decode_one_group(c):
	cipher=""
	#key_list(k)
	for i in range(64):
		cipher+=c[dic_IP[i]-1]        #c经过IP1置换放入cipher
	cipher_left=cipher[0:32]
	cipher_right=cipher[32:]
	i=15
	while i>0:
		cipher_temp=cipher_right
		cipher_right=xor(fun_F(cipher_right,keylist[i]),cipher_left)
		cipher_left=cipher_temp
		i=i-1
	fin_right=cipher_right
	fin_left=xor(fun_F(cipher_right,keylist[0]),cipher_left)
	final=fin_left+fin_right
	final=IP_NI(final)
	ming=""
	for x in range(0,64,8):
		ming+=chr(int(final[x:x+8],2))
	return ming

解密全部

每组64位二进制,分组解密

def DES_decode(c):
	i=0
	res=""
	while c[i:i+64]!="":
		res+=DES_decode_one_group(c[i:i+64])
		i=i+64
	return res

运行结果及正确性分析

输入8个字符作为明文,8个字符作为密钥,得出密文为一串比特流,输入这串比特流,用上面生成的子密钥进行解密得到明文为先前输入的8个明文字符,验证了算法的正确性;

FI0I41.png

算法安全性分析

一重DES算法的密钥过短,只有56位有效密钥位,所以不具备很高的安全性,下面分析中间相遇攻击;

中间相遇攻击分析:

在 DES 的基础上,衍生了以下两种加密方式

1.双重 DES,使用两个密钥,长度为112比特,加密方程为C=Ek2(Ek1(P)),但是双重DES是不可以抵抗中间相遇攻击的,构造如下,即分别枚举 K1 和 K2 分别对 P 进行加密和对 C 进行解密。

I=Ek1(P) J=Dk2(C)

在我们对 P 进行加密完毕后,可以对加密结果进行排序,当我们对 C 进行解密时,可以每解密一个,就去对应的表中查询,看看是否相等,如此进行中间相遇攻击。计算量大概在2^56左右。和一重DES的复杂度相当;

2.三重DES,加密方式如下,3 个不同的密钥,k1,k2,k3 互相独立,一共 168 比特。可以抵御中间相遇攻击;

C=Ek3(Dk2(Ek1(P))) P=Dk1(Ek2(Dk3(C)))

有效性和合理性分析

DES 现在已经不被视为一种安全的加密算法,拿DES来进行加密已经认为是不合理的,主要原因是它使用的56位密钥过短,为了提供实用所需的安全性,可以使用 DES 的派生算法 三重DES 来进行加密,现在的三重DES是具备安全性的,可以抵抗中间相遇攻击,比较合理有效;

算法编写过程中遇到的问题及解决

1.算法编写过程中,Feistel网络密码结构中的子密钥每一轮都需要更新;

2.一开始写十六轮迭代时,直接就是写16轮循环,每次得到的R作为下次加密的L,而上一轮得到的异或结果作为R,这样得到的结果是错误的,因为Feistel网络密码结构中第16轮迭代时,右部分直接就是第十五轮得到的R15,左部分是R15经过F函数后与L15异或得到的,并不是简单的16轮重复迭代;

3.一开始的解密过程错误,是因为我直接简单的拿加密的算法当解密的算法了,没有观察到,解密时的每一轮迭代中,子密钥是从第16个到第1个倒序添加的,这点格外重要;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值