之前在网上看了好多关于DES加解密的文章,很多都是直接贴代码,然而大多数都不能运行。花了一天写了个能运行的程序,其中有参考网上的一些好的代码。希望入了密码学坑的同学能得到帮助。python刚上手,代码很长,希望大家多多给出建议。
def keychanged(key):#秘钥初始置换,置换选择1
pc1=(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, 33, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4)
changed_key=''
for i in range(56):
changed_key+=key[pc1[i]-1]
return changed_key
#将Unicode字符转换为16进制数
def tohex(string):
return_string=''
for i in string:
return_string+="%02x"%ord(i)
return return_string
#将16进制数转换为2进制数
def _functionCharToA(code):
return_code=''
lens = len(code)
lens=lens%16
for key in code:
code_ord=int(key,16)
return_code+=_functionTos(code_ord,4)
if lens!=0:
return_code+='0'*(16-lens)*4###如16进制数不为16倍数,则将剩余补为16位
return return_code
#将16进制数转换为4位2进制数
def _functionTos(o,lens):
return_code=''
for i in range(lens):
return_code=str(o>>i &1)+return_code
return return_code
###将2进制字符串转换为16进制字符串
def binTohex(string):
lens = len(string)
tohex = ''
for i in range(0,lens,4):
list = string[i]+string[i+1]+string[i+2]+string[i+3]
tohex +="%x"%int(list,2)
return tohex
###将16进制转换为unicode字符
def tounicode(string):
return_string=''
string_len=len(string)
for i in range(0,string_len,2):
return_string+=chr(int(string[i:i+2],16))
return return_string
#num = tohex(string)
#dnum = _functionCharToA(num)
#changedkey = keychanged(dnum)
#key_l = changedkey[0:28]
#key_r = changedkey[28:56]
###密钥可以转换为2进制数了
def roundKey(initkey):
pc2= (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)
d = (1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1)
keylist = []
key_l = initkey[0:28]
key_r = initkey[28:56]
for i in range(16):
key_l = key_l[d[i]:28]+key_l[0:d[i]]
key_r = key_r[d[i]:28]+key_r[0:d[i]]
key = key_l+key_r
return_list = ''
for i in range(48):#密钥置换选择2
return_list+=key[pc2[i]-1]
keylist.append(return_list)
return keylist
###将轮密钥存在keylist中
#keylist = []
#keylist = roundKey(changedkey)
#print(keylist)
###密钥生成器完毕
###以下是对明文的处理######
def _codefirstchange(code):#明文初始置换
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)
changed_code=''
for i in range(64):
changed_code+=code[ip[i]-1]
return changed_code
#changetext = tohex(cleartext)
#binarytext = _functionCharToA(changetext)
#print(binarytext)
#textfirstchange = _codefirstchange(binarytext)
#print(len(textfirstchange))
#text_l = textfirstchange[0:32]
#text_r = textfirstchange[32:64]
#print("明文初始置换后:"+text_l+","+text_r)
####明文初始置换完毕
###F函数#####
#扩展置换E
def _functionE(code):
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)
return_list=''
for i in range(48):
return_list+=code[e[i]-1]
return return_list
#expandtext_r = _functionE(text_r)
#print("text_r扩展置换后:"+expandtext_r)
####异或
def _codeyihuo(code,key):
code_len=len(key)
return_list=''
for i in range(code_len):
if code[i]==key[i]:
return_list+='0'
else:
return_list+='1'
return return_list
#yihuotext_r = _codeyihuo(expandtext_r,keylist[0])
#print("异或后的的text_r:"+yihuotext_r)
####S盒
def _functionS(key):
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]]]
return_list=''
for i in range(8):
row=int(str(key[i*6])+str(key[i*6+5]),2)#选择行
raw=int(str( key[i*6+1])+str(key[i*6+2])+str(key[i*6+3])+str(key[i*6+4]),2)#选择列
return_list+=_functionTos(s[i][row][raw],4)#选择一个数,并转换为4位2进制数
return return_list
#afterSboxtext_r = _functionS(yihuotext_r)
#print("经过S盒后:"+afterSboxtext_r)
####置换P
def _functionP(code):#置换P
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)
return_list=''
for i in range(32):
return_list+=code[p[i]-1]
return return_list
#afterPpermutetext_r = _functionP(afterSboxtext_r)
#print("F函数输出:"+afterPpermutetext_r)
#nowtext_r = _codeyihuo(afterPpermutetext_r,text_l)
#print("一轮迭代后的text_r:"+nowtext_r)
#逆初始置换
def _functionCodeChange(code):
ip_1=(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)
changed_code=''
for i in range(64):
changed_code+=code[ip_1[i]-1]
return changed_code
###要不设计成加密64位2进制串的吧
###输入的明文与密钥都是二进制字符串
def Aencryption(binaryText,binaryKey,operate):
turn_len = len(binaryText)
output = ''
keylist = []
firstchangedkey = keychanged(binaryKey)
keylist = roundKey(firstchangedkey)#keylist存上了每轮的密钥
if(operate == "de"):###解密时将密钥列表逆转
keylist = keylist[::-1]
for i in range(0,turn_len,64):
#指导书中将只需对64bit进行加解密即可
run_code = binaryText[i:i+64]###每次选择64位明文进行加密
run_code = _codefirstchange(run_code)###对明文进行初始置换
for j in range(16):
#取出明文的左右32位
code_l=run_code[0:32]
code_r=run_code[32:64]
#进行左右置换
run_code = code_r
#将右边32位扩展置换为48位
#与本轮密钥进行异或
#进入S盒进行代替选择
#进入置换P
code_r = _functionE(code_r)
code_r = _codeyihuo(code_r,keylist[j])
code_r = _functionS(code_r)
#将明文左边32位于F函数中出来值进行异或
code_r= _codeyihuo(code_l,code_r)
#将一轮加密后的左右两边密文置换合并,
run_code += code_r
#32位互换
code_l=run_code[0:32]
code_r=run_code[32:64]
run_code=code_r+code_l
##此时output为2进制数
output += _functionCodeChange(run_code)
return(output)
#明文和密钥可能不是64位,key中一个字符4位,所以key长度必须大于16,
#但这里已经在16进制转换为二进制数时处理了
operate = input("加密请输入:en\n解密请输入:de\n")
while(operate!="en" and operate!="de"):
print("输入格式错误,请重新输入!")
operate = input("加密请输入:en\n解密请输入:de\n")
if(operate =="en"):
way = input("ECB加密模式请输入:ECB\nCBC加密模式请输入:CBC\n")
while(way!="ECB" and way!="CBC"):
print("输入格式错误,请重新输入!")
way = input("ECB模式请输入:ECB\nCBC模式请输入:CBC\n")
elif(operate == "de"):
print("进入ECB解密模式")
way = "ECB"
rage = []
IV = "0011000100110011001100110011011000110110001110000011010100110101"#初始向量,CBC加密时使用
rage.append(IV)
if(operate == "en" and way == "CBC"):
cleartext = input("请输入需要加密的字符串:")
key = input("请输入密钥:")
output = ''
changekey = tohex(key)
binarykey = _functionCharToA(changekey)
changetext = tohex(cleartext)
binarytext = _functionCharToA(changetext)
lens = len(binarytext)
j = 0
for i in range(0,lens,64):
mixbinarytext = _codeyihuo(binarytext[i:i+64],rage[j])
miwen = Aencryption(mixbinarytext,binarykey,operate)###miwen此时为二进制数
output += miwen
rage.append(miwen)
j = j+1
print("密文:"+output)
mitohex = binTohex(output)
realtext = tounicode(mitohex)
print("密文:"+realtext)
choose = input("是否要进行解密?(y/n):")
if(choose == 'y'):
operate ="de"
output = ''
cleartext = input("请输入需要解密的字符串:")
key = input("请输入密钥:")
changetext = tohex(cleartext)
binarytext = _functionCharToA(changetext)
print(binarytext)
changekey = tohex(key)
binarykey = _functionCharToA(changekey)
lens = len(binarytext)#计算密文长度
j = 0
for i in range(0,lens,64):
run_code = binarytext[i:i+64]
afterDesText = Aencryption(run_code,binarykey,operate)###miwen此时为二进制数
mingwen = _codeyihuo(afterDesText,rage[j])
output += mingwen
j = j+1
print("明文:"+output)
texttohex = binTohex(output)
realtext = tounicode(texttohex)
print("明文:"+realtext)
elif(operate == "en" and way =="ECB"):
cleartext = input("请输入需要加密的字符串:")
key = input("请输入密钥:")
changetext = tohex(cleartext)
binarytext = _functionCharToA(changetext)
changekey = tohex(key)
binarykey = _functionCharToA(changekey)
mingwen = Aencryption(binarytext,binarykey,operate)###miwen此时为二进制数
print("密文:"+mingwen)
mitohex = binTohex(mingwen)
realtext = tounicode(mitohex)
print("密文:"+realtext)
choose = input("是否要ECB进行解密?(y/n):")
if(choose == 'y'):
operate = "de"
cleartext = input("请输入需要解密的字符串:")
key = input("请输入密钥:")
changetext = tohex(cleartext)
binarytext = _functionCharToA(changetext)
changekey = tohex(key)
binarykey = _functionCharToA(changekey)
mingwen = Aencryption(binarytext,binarykey,operate)###miwen此时为二进制数
print("明文:"+mingwen)
tohex = binTohex(mingwen)
realtext = tounicode(tohex)
print("明文:"+realtext)
elif(operate == "de" and way =="ECB"):
cleartext = input("请输入需要解密的字符串:")
key = input("请输入密钥:")
changetext = tohex(cleartext)
binarytext = _functionCharToA(changetext)
changekey = tohex(key)
binarykey = _functionCharToA(changekey)
mingwen = Aencryption(binarytext,binarykey,operate)###miwen此时为二进制数
print("明文:"+mingwen)
tohex = binTohex(mingwen)
realtext = tounicode(tohex)
print("明文:"+realtext)