這是自行制作的一個DES文本加密工具
最終效果圖:

本加密器支持UTF-8字符的加解密(包含中文),由於其中的編碼方式與常用編碼方式不同,加密結果與網上工具不同,但是能實現正常加解密。
最終目標:
目的是設計一個基於ECB模式,短塊加密使用填充法的DES加密解密器,以此來實現對文本的加解密,其文本的處理還用到了base64編碼。
實驗內容:
該des加密軟件我采用的是python語言編寫。主程序分了四個大的模塊,
一個負責圖形化界面的編寫及綜合作用的mainfunc.py文件;
一個負責DES的加解密的DES.py文件;
一個負責字符串的處理以及base64編碼的handle.py文件;
最后一個setup.py用於打包程序
以下將做詳細介紹。
首先來介紹軟解加解密的主要流程
對秘鑰的處理:
由於用戶輸入的秘鑰是8個字符,故首先要將其轉化為64位的二進制字符串,該功能由handle.py中的keyencode函數實現:

加密流程:
1用戶輸入的明文為任意字符串(包含中文字符以及英文字母以及標點符號),首先要進行分組處理,分組成64位二進制一組的二進制字符串,最后一組不足64位的使用填充法,該部分由handle.py中的encode函數處理

2 接着根據之前得到的64位秘鑰以及明文,依次進行DES加密,得到包含所有64位密文的數組
3 接着要將各64位的密文連在一起得到二進制的密文字符串,再對其進行base64編碼得到最終的輸出字符串,該部分由handle.py中的base64encode函數處理。

解密流程:
1 解密首先要對得到的密文字符串進行反base64編碼處理,去掉后面添加的‘=’,接着將其根據base64的編碼規則轉化為二進制字符串,然后去掉之前添加的‘0’字符,然后將字符串進行分組,分為64位一組。這一部分由handle.py中的base64decode函數完成。

2接着根據之前得到的64位秘鑰以及密文,依次進行DES解密,得到包含所有64位明文的數組。
3接着要對得到的包含所有64位明文的數組進行處理,首先去掉之前填充的多余的字符,接着對二進制字符串進行反編碼得到源字符串。該部分由handle.py中的decode函數得到。

DES部分:
接着來編寫DES加密模塊,DES加解密流程完全按照書本上DES加解密流程實現,實現過程也沒有什么難點,在此就不做過多介紹。
實驗難點:
本次實驗的DES加解密編程較為順利,在字符串的操作上開始遇到了一點困難,之后比較順利。主要是在字符串與二進制串的轉換,字符編碼上遇到了一些問題。
1.填充法的選擇
由於初始的明文轉化為64位二進制字符串后,最后一組並不一定是64位,故要進行處理,我這里運用的是比較直觀的填充法,具體是PKCS5方法,在PKCS5方法中Block = 8bytes。Padding特點:對於Block=8bytes(64bits塊)進行填充字節的值的取值范圍在[1, 8].解碼過程中,從最后一個字節看起,首先確定它表示的值1<=n<=8,然后檢驗最后n個字節的值是否相同,若相同最后刪去最后n個字節即可得到完整的信息.特殊情況:若字符串恰好夠分成完整的塊,不多不少.則最后8個字節為:(IN HEX) 08 08 08 08 08 08 08 08
我在代碼中已經實現:

2.中英文編碼
這個問題實則比較麻煩,在我使用的python2.7版本中默認英文字符占一個字節,即八位,中文字符占據兩個字節,即兩個字節。如果中英文混在一起將無法區分。
一開始,我想到的解決方法是將中文字符16位中最高位置1,因為英文8位最高位為0,故可以將其區分,解碼時在進行還原。但結果發現,有一部分中文字符最高位為0,故此法不通。
因此,我只好將英文字符也擴展到16位,高8位置0,我最終的代碼也按此實現,但是此方法對加密的安全性應該有一定的影響。例如,對於全英文的文本,所需要破解的字符串瞬間減到一半。
但暫時沒有想到更好的方法。
以下為我的代碼實現:

附上最終源碼:
mainfunc.py
#-*- coding=utf-8 -*-
import wx
import wx.lib.buttons as buttons
from lib import DES
from lib import handle
class newframe(wx.Frame):
def __init__(self): #主框架
wx.Frame.__init__(self,None,-1,u'DES加解密工具',size=(820,760),pos=(500,100))
self.SetMinSize((820,760))
self.SetMaxSize((820,760))
self.panel=wx.Panel(self,-1)
self.panelpic=wx.Image('./diary.jpg',wx.BITMAP_TYPE_JPEG,).Scale(820,760).ConvertToBitmap()
self.picbk=wx.StaticBitmap(parent=self.panel,pos=(0,0),bitmap=self.panelpic)
self.initstatictext()
self.textctrl()
self.buttoninit()
self.buttonbind()
def initstatictext(self): #定義文本
self.text1=wx.StaticText(self.picbk,-1,u'請輸入加解密秘鑰(僅八位長):',pos=(40,10),size=(-1,25),style=wx.TE_CENTER)#,size=(240,25))
self.text2=wx.StaticText(self.picbk,-1,u'未加密文本:',pos=(40,60),size=(-1,25),style=wx.TE_CENTER)#,size=(240,25))
self.text3=wx.StaticText(self.picbk,-1,u'加密后文本:',pos=(40,400),size=(-1,25),style=wx.TE_CENTER)#,size=(240,25))
self.text1.SetBackgroundColour('AQUAMARINE')
self.text2.SetBackgroundColour('AQUAMARINE')
self.text3.SetBackgroundColour('AQUAMARINE')
def textctrl(self): #定義文本框
font2 = wx.Font(12, wx.DECORATIVE, wx.NORMAL, wx.NORMAL)
self.ctrl1=wx.TextCtrl(self.picbk,-1,'',pos=(30,100),size=(750,250), style=wx.TE_MULTILINE|wx.TE_RICH2)
self.ctrl1.SetBackgroundColour('sky blue')
self.ctrl1.SetFont(font2)
self.ctrl2=wx.TextCtrl(self.picbk,-1,'',pos=(270,10),size=(150,28))
self.ctrl2.SetBackgroundColour('sky blue')
self.ctrl2.SetFont(font2)
self.ctrl3=wx.TextCtrl(self.picbk,-1,'',pos=(30,450),size=(750,250), style=wx.TE_MULTILINE|wx.TE_RICH2)
self.ctrl3.SetBackgroundColour('sky blue')
self.ctrl3.SetFont(font2)
def buttoninit(self): #定義按鈕
self.button1=buttons.GenButton(self.picbk,-1,u'加密',pos=(240,380),size=(-1,50))
self.button2=buttons.GenButton(self.picbk,-1,u'解密',pos=(540,380),size=(-1,50))
self.button1.SetBezelWidth(5)
self.button2.SetBezelWidth(5)
self.button1.SetBackgroundColour("CORAL")
self.button2.SetBackgroundColour("CORAL")
def buttonbind(self): #按鈕事件綁定
self.button1.Bind(wx.EVT_BUTTON,self.encode)
self.button2.Bind(wx.EVT_BUTTON,self.decode)
def encode(self,evt): #加密事件
out=[]
password=self.ctrl2.GetValue()
password=handle.keyencode(password)
text=self.ctrl1.GetValue()
text=handle.encode(text)
for one in text:
a=DES.desencode(password,one)
out.append(a)
cipher=handle.base64encode(out)
self.ctrl3.SetLabelText(cipher)
def decode(self,evt): #解密事件
cipherlist=[]
outlist=[]
password=self.ctrl2.GetValue()
password=handle.keyencode(password)
ciphertext=self.ctrl3.GetValue()
cipherlist=handle.base64decode(ciphertext)
for one in cipherlist:
outlist.append(DES.desdecode(password,one))
outstring=handle.decode(outlist)
self.ctrl1.SetLabelText(outstring)
if __name__=='__main__':
newapp=wx.App(False)
frame=newframe()
frame.Show()
newapp.MainLoop()
handle.py
#-*- coding=utf-8 -*-
base='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
def keyencode(key): #該部分將秘鑰串轉化為64位二進制形式
out=''
for i in key: #將每一個字符轉化為二進制形式
out+=str(bin(ord(i))).replace('0b','').zfill(8)
return out
def encode(string): #該部分主要是將明文字符串轉化為每64位一組二進制明文
out1=''
text=[]
for i in string: #將每一個字符轉化為二進制
temp=str(bin(ord(i))).replace('0b','')
out1+=temp.zfill(16)
time=len(out1)/64
for i in range(time+1): #對二進制字符串進行分組,每64位一組
text.append(out1[64*i:64*(i+1)])
length=len(text[time])
if length!=64: #最后一組如果不滿64位進行填充
add=8-length/8
text[time]+=str(bin(ord(str(add)))).replace('0b','').zfill(8)*add
else:
text.append(str(bin(ord('8'))).replace('0b','').zfill(8)*8)
return text
def base64encode(list): #該部分主要是對二進制串進行base64處理
out=''
string=''.join(list)
a=len(string)%24
if a==8: #補0操作
string+='0000'
if a==16:
string+='00'
m=int(len(string)/6)
for j in range(m):
out+=base[int(string[j*6:j*6+6],2)]
if(a==8): #補=操作
out+='=='
if(a==16):
out+='='
return out
def base64decode(string): #該部分主要進行base64解碼操作
temp1=string.split('=')[0] #去掉多余的=
temp2=''
outlist=[]
for i in temp1: #將字符串轉化為二進制串
temp2+=str(bin(base.index(i))).replace('0b','').zfill(6)
temp3=len(temp2)
if (temp3-2)%64==0: #去掉多余的0
temp2=temp2[0:len(temp2)-2]
if (temp3-4)%64==0:
temp2=temp2[0:len(temp2)-4]
time=len(temp2)/64
for i in range(time): #將二進制串每64位進行分組
outlist.append(temp2[64*i:64*(i+1)])
return outlist
def decode(list1): #該部分主要是將64位明文轉化為原字符串
string=''
more=int(chr(int(list1[len(list1)-1][56:64],2))) #得到補充位數目
strtemp1=''.join(list1)
strtemp2=strtemp1[0:(len(strtemp1)-8*more)] #去掉補充位
for i in range(0,len(strtemp2)/8,2):
if int(strtemp2[i*8:(i+1)*8],2)==0: #如果此八位為0,則說明后面的一個字節為ascii編碼
string+=chr(int(strtemp2[(i+1)*8:(i+2)*8],2))
else: #如果此八位不為0,則說明該字節與后一個為unicode編碼
string+=unichr(int(strtemp2[i*8:(i+2)*8],2))
return string
DES.py
# -*- coding: utf-8 -*-
import time
import base64
import os
m=0
C0=''
D0=''
L0=''
R0=''
cipher=''
outtext=''
k=0
substitute1=[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]
substitute2=[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]
shift=[1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]
KEY=[ dict() for i in range(16)]
sbox= [
[
0xe,0x4,0xd,0x1,0x2,0xf,0xb,0x8,0x3,0xa,0x6,0xc,0x5,0x9,0x0,0x7,
0x0,0xf,0x7,0x4,0xe,0x2,0xd,0x1,0xa,0x6,0xc,0xb,0x9,0x5,0x3,0x8,
0x4,0x1,0xe,0x8,0xd,0x6,0x2,0xb,0xf,0xc,0x9,0x7,0x3,0xa,0x5,0x0,
0xf,0xc,0x8,0x2,0x4,0x9,0x1,0x7,0x5,0xb,0x3,0xe,0xa,0x0,0x6,0xd,
],
[
0xf,0x1,0x8,0xe,0x6,0xb,0x3,0x4,0x9,0x7,0x2,0xd,0xc,0x0,0x5,0xa,
0x3,0xd,0x4,0x7,0xf,0x2,0x8,0xe,0xc,0x0,0x1,0xa,0x6,0x9,0xb,0x5,
0x0,0xe,0x7,0xb,0xa,0x4,0xd,0x1,0x5,0x8,0xc,0x6,0x9,0x3,0x2,0xf,
0xd,0x8,0xa,0x1,0x3,0xf,0x4,0x2,0xb,0x6,0x7,0xc,0x0,0x5,0xe,0x9,
],
[
0xa,0x0,0x9,0xe,0x6,0x3,0xf,0x5,0x1,0xd,0xc,0x7,0xb,0x4,0x2,0x8,
0xd,0x7,0x0,0x9,0x3,0x4,0x6,0xa,0x2,0x8,0x5,0xe,0xc,0xb,0xf,0x1,
0xd,0x6,0x4,0x9,0x8,0xf,0x3,0x0,0xb,0x1,0x2,0xc,0x5,0xa,0xe,0x7,
0x1,0xa,0xd,0x0,0x6,0x9,0x8,0x7,0x4,0xf,0xe,0x3,0xb,0x5,0x2,0xc,
],
[
0x7,0xd,0xe,0x3,0x0,0x6,0x9,0xa,0x1,0x2,0x8,0x5,0xb,0xc,0x4,0xf,
0xd,0x8,0xb,0x5,0x6,0xf,0x0,0x3,0x4,0x7,0x2,0xc,0x1,0xa,0xe,0x9,
0xa,0x6,0x9,0x0,0xc,0xb,0x7,0xd,0xf,0x1,0x3,0xe,0x5,0x2,0x8,0x4,
0x3,0xf,0x0,0x6,0xa,0x1,0xd,0x8,0x9,0x4,0x5,0xb,0xc,0x7,0x2,0xe,
],
[
0x2,0xc,0x4,0x1,0x7,0xa,0xb,0x6,0x8,0x5,0x3,0xf,0xd,0x0,0xe,0x9,
0xe,0xb,0x2,0xc,0x4,0x7,0xd,0x1,0x5,0x0,0xf,0xa,0x3,0x9,0x8,0x6,
0x4,0x2,0x1,0xb,0xa,0xd,0x7,0x8,0xf,0x9,0xc,0x5,0x6,0x3,0x0,0xe,
0xb,0x8,0xc,0x7,0x1,0xe,0x2,0xd,0x6,0xf,0x0,0x9,0xa,0x4,0x5,0x3,
],
[
0xc,0x1,0xa,0xf,0x9,0x2,0x6,0x8,0x0,0xd,0x3,0x4,0xe,0x7,0x5,0xb,
0xa,0xf,0x4,0x2,0x7,0xc,0x9,0x5,0x6,0x1,0xd,0xe,0x0,0xb,0x3,0x8,
0x9,0xe,0xf,0x5,0x2,0x8,0xc,0x3,0x7,0x0,0x4,0xa,0x1,0xd,0xb,0x6,
0x4,0x3,0x2,0xc,0x9,0x5,0xf,0xa,0xb,0xe,0x1,0x7,0x6,0x0,0x8,0xd,
],
[
0x4,0xb,0x2,0xe,0xf,0x0,0x8,0xd,0x3,0xc,0x9,0x7,0x5,0xa,0x6,0x1,
0xd,0x0,0xb,0x7,0x4,0x9,0x1,0xa,0xe,0x3,0x5,0xc,0x2,0xf,0x8,0x6,
0x1,0x4,0xb,0xd,0xc,0x3,0x7,0xe,0xa,0xf,0x6,0x8,0x0,0x5,0x9,0x2,
0x6,0xb,0xd,0x8,0x1,0x4,0xa,0x7,0x9,0x5,0x0,0xf,0xe,0x2,0x3,0xc,
],
[
0xd,0x2,0x8,0x4,0x6,0xf,0xb,0x1,0xa,0x9,0x3,0xe,0x5,0x0,0xc,0x7,
0x1,0xf,0xd,0x8,0xa,0x3,0x7,0x4,0xc,0x5,0x6,0xb,0x0,0xe,0x9,0x2,
0x7,0xb,0x4,0x1,0x9,0xc,0xe,0x2,0x0,0x6,0xa,0xd,0xf,0x3,0x5,0x8,
0x2,0x1,0xe,0x7,0x4,0xa,0x8,0xd,0xf,0xc,0x9,0x0,0x3,0x5,0x6,0xb,
]
]
substituteip= [
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]
selectoperate=[
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]
substituteP=[
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]
resubstituteip=[
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]
def before():
global KEY,m,C0,D0,L0,R0,cipher,outtext,k
KEY=[ dict() for i in range(16)]
m=0
C0=''
D0=''
L0=''
R0=''
cipher=''
outtext=''
k=0
def handleraw(string):
a=''
for i in string:
a+=bin(ord(i)).replace('0b','').zfill(8)
return a
def shiftleft(string,x): #循環左移
return string[-(len(string)-x):]+string[:x]
def encodepassword1(x): #秘鑰置換選擇
global C0
global D0
for i in range(0,28):
C0+=x[substitute1[i]-1]
for j in range(28,56):
D0+=x[substitute1[j]-1]
def encodepassword2(): #秘鑰處理主流程
global k,C0,D0
t=''
if(k!=16):
C0=shiftleft(C0,shift[k])
D0=shiftleft(D0,shift[k])
s=C0+D0
for i in substitute2:
t+=s[i-1]
KEY[k]=t
k+=1
encodepassword2()
def substituteIP(string): #初始置換IP
global L0,R0
a=''
for i in substituteip:
a+=string[i-1]
L0=a[:32]
R0=a[-32:]
def sboxoperate(): #S盒操作
mid=''
for i in selectoperate:
mid+=R0[i-1]
mid=str(bin(int(mid,2)^int(KEY[m-1],2)).replace('0b','').zfill(48))
outraw=''
for n in range(8):
a=int(mid[6*n]+mid[6*n+5],2)
b=int(mid[(6*n+1):(6*n+5)],2)
outraw+=str(bin(int(str(sbox[n][a*16+b]),10)).replace('0b','').zfill(4))
out=''
for i in substituteP:
out+=outraw[i-1]
return out
def encodemain(): #加密主流程
global m,L0,R0,cipher
m+=1
a=L0
L0=R0
R0=str(bin(int(sboxoperate(),2)^int(a,2)).replace('0b','').zfill(32))
if(m!=16):
encodemain()
else:
b=R0+L0
for i in resubstituteip:
cipher+=b[i-1]
def decodecircle(): #解密主流程
global L0,R0,outtext,m
a=R0
R0=L0
L0=str(bin(int(sboxoperate(),2)^int(a,2)).replace('0b','').zfill(32))
m-=1
if(m!=0):
decodecircle()
else:
d=L0+R0
decodetext=[0 for i in range(64)]
for i in range(64):
decodetext[substituteip[i]-1]=d[i]
outtext=''.join(decodetext)
def decoderesubstituteip(string): #逆置換IP
global R0,L0,m
m=16
a=[0 for i in range(64)]
for i in range(64):
a[resubstituteip[i]-1]=string[i]
a=''.join(a)
R0=a[:32]
L0=a[-32:]
def desencode(password,text): #加密函數
before()
encodepassword1(password)
encodepassword2()
substituteIP(text)
encodemain()
return cipher
def desdecode(password,encodetext): #解密函數
before()
encodepassword1(password)
encodepassword2()
decoderesubstituteip(encodetext)
decodecircle()
return outtext
if __name__=='__main__':
e=raw_input('This is a DES encrypt and decrypt function\n press 1 to encrypt, 2 to decrypt:')
password=raw_input('please input the key:')
encodepassword1(password)
encodepassword2()
print 'the KEY is:\n',KEY
if(e=='1'):
text=raw_input('please input the text:')
substituteIP(text)
encodemain()
print 'the cipher is:',cipher
if(e=='2'):
ciphertext=raw_input('please input the cipher:')
decoderesubstituteip(ciphertext)
decodecircle()
print 'the decodetext is:',outtext
os.system("pause")
setup.py
import py2exe
from distutils.core import setup
'''setup(windows=["mainfunc.py"])'''
setup(
windows = [{"script":"mainfunc.py", "icon_resources": [(1, "lock.ico")]} ]
)
