Wolf从零学编程-用Python打造简单加密程序(八)

来源:互联网 发布:蓝桥杯c语言历年试题 编辑:程序博客网 时间:2024/06/03 18:31
 分类:

目录(?)[+]

本篇是最后一篇,加密小程序已经做完了,也可以打包带走。

这篇列出了几个改进,我的目的是: 
- 尽量改善用户体验 
- DEBUG


一、Fix the Bugs

函数参数顺序不同导致BUG

之前写完太激动,昨天耐着性子把所有功能走了一遍(原谅我,还不会写测试),结果是这样的:

  • 生成密钥正常
  • DES加解密正常
  • RSA加解密正常
  • 混合模式读不出密钥,报错信息如下:
  File "E:\crypto\crypto\base.py", line 44, in getPubKey    pub_key = rsa.PublicKey.load_pkcs1(keydata)  File "C:\Python34\lib\site-packages\rsa\key.py", line 75, in load_pkcs1    return method(keyfile)  File "C:\Python34\lib\site-packages\rsa\key.py", line 243, in _load_pkcs1_pem    der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY')  File "C:\Python34\lib\site-packages\rsa\pem.py", line 91, in load_pem    raise ValueError('No PEM start marker "%s" found' % pem_start)ValueError: No PEM start marker "b'-----BEGIN RSA PUBLIC KEY-----'" found
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 数字签名签名、正反验证均正常

为此我同时把混合模式、RSA,以及被调用的base都打开,一行一行的比对,结论是混合模式和RSA对应的调用部分完全相同,不可能出错。我又想到具体的方法调用发生在crypto.py里,一并打开重新看代码,发现以下不同:

# crypto.pymymix.encMix(rawfilename,key_filename,mode,operation)# mymix.pydef encMix(key_filename,rawfilename,mode,operation):# myrsa.pydef encFile(rawfilename,key_filename,mode,operation):
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

唯一的区别就是:encMix()的参数名位置和其他两个不同,当crypto中调用时,会把源文件的路径传给密钥文件,造成无法读取。我自己编写时,都是每个函数单独测试,文件路径是input的,单个模块内使用参数顺序都是一样的,所以没发现问题。

果然,修改参数顺序后,运行正常。到这里整个程序就可以完全运行了。

操作成功后焦点停在DES初始值

测试时常用DES加密,发现操作成功后虽然输入框都清空了(本篇后面的一处改进),但鼠标焦点却在DES初始值处,这时除非用户输入8字节,否则必然会出现一次弹窗。

查找发现,在DES模式中,DES初始值是最后一个使用焦点输入的内容,步骤最后的源文件通常都是通过浏览文件选择的。

之前有想过让每个输入框默认为’disabled’,待选择模式后再判断激活,这样也好看,刚巧也可以解决这个BUG。

# ginterface.py# 组件默认禁用状态des_key_entry = Entry(key_frame,**state='disabled'**,textvariable=des_key)#执行按钮调用方法def cryption():    ...    #清空输入框    if textVar == '操作完成':        mode_choice.set('')        operation_choice.set('')        des_key_entry.delete(0,END)        des_key_entry['state'] = 'disabled'  #清空后恢复禁用状态
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

二、Improvement

DES密钥有效性验证

DES密钥和初始值要求必须是8个字节,entry组件的验证功能就可以完成,没必要使用事件绑定。

对于entry组件的内容验证,可以看看鱼C的讲解,很详细

我希望当用户把焦点离开输入框时触发验证,如果不足8字节则清空输入框,并弹出提示框;为了清空输入框,就必须调用delete()方法,所以没办法让DES密钥和初始值验证使用同一个方法;弹出提示框可以用tkinter的标准对话框messagebox

# ginterface.py# 验证DES密钥和初始值合法性def valiDeskey():    if len(des_key.get()) == 8:        return True    else:        des_key_entry.delete(0,END)  # 不是8字节就直接清空        messagebox.showerror('输入错误','请输入8字节DES密钥',default='ok',icon='warning')        return False   # 验证函数的返回必须是True或False# DES密钥...des_key_entry = Entry(key_frame,textvariable=des_key,validate='focusout',validatecommand=valiDeskey,width=10,show='*')...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

DES初始值的验证完全一样,只是把相应的函数名和变量名更改。

目前这种写法要求用户一旦选择输入DES密钥,就要确保输入8个字节,中途做任何其他的事情都会使输入框失去焦点,即弹出提示。

改进模式选择

目前的逻辑是:用户选择模式和操作,当焦点离开时,会根据已选模式和操作,判断密钥区哪一个输入框可用,但是我设置了默认值是DES和加密,用户有可能压根就不会把焦点放在模式选择框,因此不会对输入框状态进行更改,这种情况我是不允许的!

把模式和操作设置默认值的代码删掉,妥妥的逼用户选择。

操作成功后清空输入

用户很可能在操作一次DES后紧接着开始一次RSA操作,这时应该让软件界面恢复到刚打开的状态,也就是把所有的输入框都清空。我把清空操作添加在了’执行操作’的方法里,且只有当用户操作成功后才会清空。

# ginterface.pydef cryption():    ...    #清空输入框    if textVar == '操作完成':        mode_choice.set('')        operation_choice.set('')        des_key_entry.delete(0,END)  # Entry组件没有set方法        des_IV_entry.delete(0,END)        key_filename_entry.delete(0,END)        sig_filename_entry.delete(0,END)        rawfilename_entry.delete(0,END)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

添加对话框清空功能

当用户觉得对话框内容过多时,可以一键清空。同时为了避免用户在对话框随意输入内容,我把对话框的默认state设为disabled,只有当打印操作进度或清空时短暂恢复normal

# ginterface.pytext = Text(height=10,width=60,bd=3,relief=SUNKEN,wrap=WORD,state='disabled') #高度、宽度、边框宽度和样式、按单词换行text.pack(padx=1,pady=5)def empty():    text['state'] = 'normal'    text.delete(1.0,END)  #1.0是起始位置    text['state'] = 'disabled'empty_button = Button(text='清空对话框',command=empty)empty_button.pack(padx=20,pady=5,side=RIGHT)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

捕获错误信息

为了让用户随心输入随时可以点击’执行操作’按钮,需要把代码运行中的错误信息捕获,并且对于用户选择的错误模式给出提示。

将原先的

# ginterface.pydef cryption():    ...    textVar = crypto.doCrypto(mode,operation,des_key,des_IV,key_filename,sig_filename,rawfilename)    text['state'] = 'normal'    text.insert(END,textVar)    text.insert(END,'\n')    text['state'] = 'disabled'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

改为

def cryption():    ...    try:        textVar = crypto.doCrypto(mode,operation,des_key,des_IV,key_filename,sig_filename,rawfilename)    except:        textVar = '请正确输入各项参数'    text['state'] = 'normal'    text.insert(END,textVar)    text.insert(END,'\n')    text['state'] = 'disabled'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

然后在’crypto.py’中,根据用户的选择给返回值赋值,例如用户选择了DES-签名,就返回’请选择正确的操作’,测试结果如图:

mark

给进度对话框安装垂直滚动条

tkinter的Scrollbar组件可以给Text组件安装垂直和水平滚动条,我需要做的事情有: 
- 新建一个Frame组件,作为对话框和滚动条的父组件 
- 设置Text组件的yscrollcommand选项为Scrollbar组件的set() 
- 设置Scrollbar组件的command选项为Text组件的yview()

#ginterface.py#对话框框架,此框架作用是方便排版text_frame = Frame(root)text_frame.pack()#滚动条和对话框textbar = Scrollbar(text_frame,takefocus=False)  #滚动条不需要焦点textbar.pack(side=RIGHT,fill=Y)text = Text(text_frame,height=10,width=60,bd=3,yscrollcommand=textbar.set,relief=SUNKEN,wrap=WORD,state='disabled')#高度、宽度、边框宽度和样式、按单词换行text.pack(side=RIGHT,fill=BOTH)textbar['command'] = text.yview  #yview是Text组件自带方法
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

清空无效输入框

用户可能会先选择DES模式,输入密钥后发现选错了,应该是RSA模式,这时候肯定是直接更改模式,已经输入的DES密钥需要在禁用前自动清空。

只需要在模式判断里加一行清空就可以,不过只有需要禁用的输入框添加这一行。

# ginterface.pydef judgMode(event):    if mode.get() == 'DES':        des_key_entry['state'] = 'normal'        des_IV_entry['state'] = 'normal'        **key_filename_entry.delete(0,END)**        **sig_filename_entry.delete(0,END)**        key_filename_entry['state'] = 'disabled'        sig_filename_entry['state'] = 'disabled'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

目前为止这个小软件就算完工了,还有一些考虑添加的功能暂时想不到办法,比如:

  • 只允许通过浏览文件选择文件,避免用户输入的错误
  • 进度对话框实时打印代码执行进度和操作耗时

丑陋的代码也需要不断优化,总之我会边学习边进行,github仓库会即时更新。

阅读全文
0 0