加密项目开发笔记(2)——PC

1、准备

    PC端由于需要使用Python,虽然都已经粗浅学过,不够还是没有写过相应的GUI程序,除非用Tkinter画几条线也算的话。

    然后就是找寻各种python的GUI框架,Tkinter,pyQT等等,最后决定使用wxPython,一方面它比较适应我们项目的体量,另一方面他的资历最老,开发功能较为完善。wxPython是wxWidgets的跨平台GUI框架,已经适配了新版本的Python3,决定好后首先是寻找wxPython相关的资料,发现网络上并没有什么体系完整的中文资料,除了易百wxPython,里面的内容比较浅,但是实用性还是比较强的,此外还有两份PDF,不过没怎么看,PDF教程都太过于系统化,而我需要的是能够随时查阅的资料所以没怎么看,所以我选择了查找英文官方文档,这还是我第一次采用官方文档做项目,激动得我双手颤抖。

    随后我在电脑上用pip安装好了wxPython,开始正式学习

2、Hello World!

    使用框架前我选择了先用wxPython做几个小东西以便去理解框架的操作逻辑,用到了一些博客的入门教程wxPython入门,首先做的一个比较完善的程序是一个图片查看器, 在这个实现了一个基本的选择图片——>展示图片的功能,就是功能并没有很完善,没有去判断图片的格式,而是默认只能打开png格式的图片,不过实现了自动根据图片分辨率调整窗口。

    从这个小程序中可以看出实现我想wxPython的GUI的步骤为:

  1. 实例化wx.App类,也可以继承此类自己写一个类以实例化
  2. 实现wx.Frame类并调用实例对象的Show()方法,也可以自己先继承此类再实例化
  3. 调用wx.App类或其子类的MainLoop()方法启动APP事件循环

其中wx.App的OnInit方法是在其__init__方法的末尾处调用,一般用来做整个程序的初始化操作,并用来实例化Frame和展示Frame; 然后就是Frame类的初始化函数的编写,Frame类初始化函数主要是用来构建界面元素;在这个程序中,主要用到的类有FileDialog类,StaticBitMap类,Menu类,以及MenuBar,其中MenuBar是位于GUI程序标题栏下方菜单栏的一级菜单,Menu类则是MenuBar的二级菜单,要展示文件选择对话框则先要实例化他的类,然后调用其ShowModal()方法,返回的是是否选择的信息,其值主要是wx.OK, wx.CANCEL这都是wxPython内置的常量;要显示图片则先要用Image类导入图片并将其转化为位图,然后再利用静态图类将其展示出来。

import wx

class MyApp(wx.App):
	def OnInit(self):
		Frame = MyFrame()
		Frame.Show()
		return True
		
		
class MyFrame(wx.Frame):
	def __init__(self):
		super(MyFrame, self).__init__(None, title="图片查看器", size=(400,400))
		self.CreateStatusBar()
		menu = wx.Menu()
		open_m = menu.Append(wx.ID_OPEN, "打开图片")
		self.Bind(wx.EVT_MENU, self.openImag, open_m)
		menuBar = wx.MenuBar()
		menuBar.Append(menu, "打开")
		self.SetMenuBar(menuBar)
		
	def openImag(self, e):
		imagFile = wx.FileDialog(None, "选择你的图片文件", wildcard="*.JPEG;*.png;*.gif;*.jpg", )
		if imagFile.ShowModal() == wx.ID_OK:
			temp = wx.Image(imagFile.GetPath(), wx.BITMAP_TYPE_PNG)
			imag = temp.ConvertToBitmap()
			wx.StaticBitmap(parent=self, bitmap=imag, size=(imag.GetWidth()/3, imag.GetHeight()/3))
			self.SetSize((imag.GetWidth(), imag.GetHeight()))
	
	
if __name__ == '__main__':
	App = MyApp()
	App.MainLoop()

 

3、main.py的编写

    1.界面构建

        

        如图,这个GUI程序的基本元素都在这上面了,并创建了一个panel类作为背板,由BoxSizer排列,采用VERTICAL的方式,共分为5行,需要注意的是后四行。

        第二行由一个TextCtrl和一个Button构成,一直没太搞清这种几个原件排在一行的分布该怎么调整,在这一行采用的是先用固定的长宽来构建编辑框(因为当时是在搞不好他的长度所以出此下策)并将其设置了只读,保证了用户不会误操作路径,其次使用了BoxSizer的AddSpacer()制造空白来控制编辑框与按钮之间的距离,然后就是按钮,按钮没什么问题,将这些控件都加入一个HORIZONTAL的Sizer中并将其Add进总的Vertical Sizer。

        第三行由加密认证级别的RadioBox以及生成二维码Button构成,在实例化RadioBox时直接将一个可选项lable字符串列表赋值给choice便可以实现多选,其中列表的第一项是这个RadioBox的默认选项。然后接一个AddSpacer制造控件距离,再就是生成二维码按钮,这个按钮在初始时是需要设置失效的,只有在选择文件后才enable他,在这里就可以使用Disable()方法,需要注意wxPython的大部分控件都是可以调用这个函数的。

        第四行是二维码显示位,在开始时也是不能让它显示的,不过不能用Disable,而是先创建好StaticBitMap类而不传给他图片对象,后面在显示二维码后再通过绑定的函数来生成二维码并展示。不过之前在这里其实有个卡了我很久的问题,就是显示图片后发现图片不是位于当前HORIZONTAL Sizer的中间,后面发现只要提前自己指定了二维码的尺寸就可以显示正常位置了,这个思想同样可以用在第五行的过期提示中,也属于后续才显示内容的。

        从上面的例子中我猜测是由于当创建一个控件而没有指定其尺寸的时候,此控件就会先化作一个“点”,这个点的位置会按照调用ADD时的位置来定位,若为center则这个点就位于当前Sizer的中心,然后当后续对此控件添加显示对象时,就会以这个点为对象起点(GUI的起点往往指左上角的位置)来放置对象,比如二维码,它显示出来的时候其左上角那个“点”就位于当前Sizer的中心,所以只要事先确定其尺寸,那么他就事先把这个控件作为一个“点”来处理,Add时也就会放置在正确的位置

    2.二维码显示函数

        这个函数属于比较简单的一个函数,首先确定二维码的信息格式,然后利用QRCode函数实例化对象,然后将信息给他,再保存图片,然后利用Image类将其转化为位图最后显示出来,之前有尝试过不保存图片直接将二维码转化位图显示出来但一直失败,算是后面可以优化的项目吧。

    3.倒计时函数

         倒计时函数是作为一个线程函数的,思路很简单,就是设置一个到期时间,在这个时间内每过一秒检索是否重新按了生成二维码按钮,为真则结束当前线程,三十秒后显示到期提醒。

    4.连接服务器函数

        这个函数也很简单,或者换句话说Python的Socket编程非常简便直接,连接上服务器后,发送生成的请求码,然后接收OK,然后就是等待回应,得到的回应密钥作为返回值返回

    5.与生成二维码绑定的函数

        这个函数略复杂,是在其他项目都准备好了后这个函数正式开始执行。首先是判断是先尝试关闭上一个Socket连接,然后读取RadioBox的值,若为单因子认证则不做什么,若为双因子认证则弹出文本编辑对话框让用户输入IV,限定为15位,不足则用一定规律的字符串补足;再然后是生成时间戳和随机请求号,并启动倒计时线程和二维码显示函数和连接服务器函数,最后将从服务器拿到的密钥传给开始加密的函数。

    开始加密的函数则是一些鲁棒性的扩展和准备加密以及加解密完成后的提示等,整个main.py写了将近两百行,多亏了强大的Python

 

4、加密函数的编写

    加密函数算是PC端唯一的难点了,本来以为晚上大把的Python文件加密库,结果真是没有找到,全网的加密教程基本都是加密字符串的,再多一点有加密文本文件的方法,所以加密文件就只能自己进一步摸索了。

    首先我的加密算法选择的是AES的CBC加密,这是一种比较流行的加密方式,采用密钥和初始向量两个来制造密钥生成器,具体算法实现是先将一段字符串分为若干相同长度的段(所以对字符串的长度有要求,必须是指定长度的倍数),然后先使用初始向量处理一下,然后再用密钥处理一下,这是第一段,后面的段是将前一段的加密字符串作为初始向量的。就这样将整个字符串加密好。

    要注意的是初始化时先要将iv和密钥进行编码,算法概述如下:

  1. 首先以二进制方式读取文件内容(不用二进制则只能处理文本)并将读取的内容存下来,关闭文件
  2. 将读取的二进制串补空字符到长度是16的倍数,并储存好增加的空字符的长度
  3. 判断当前文件是源文件还是加密文件,调用对应的函数
  4. 加密的话,首先判断是单因子还是双因子,是单因子的话生成一段15byte的随机字符串然后和之前保存的补空字符串长度的ascii码拼接作为iv,并将iv赋值给tail,随后利用pycryptodome模块的加密算法进行AES的CBC加密。是双因子的话,直接将传来的iv作为iv,不过保留一串由随机字符串和空字符长度拼接的字符串作为tail。加密完成后将之前的tail添加到bytes串结尾以备解密时用。
  5. 解密的话,首先也是判断加密级别,单因子的话直接将末尾16位作为iv,双因子则用传进来的iv和文件byte串最后一位拼接作为iv,对byte串进行解密,解密完成后要记得删掉末尾的空字符,至于删多少个已经很明白了。
  6. 将加密或解密后的bytes串以二进制方法写入文件,需要注意文件名的修改。

    在这个加解密算法中之所以不能用处理文本的方式是因为,文本是用字符串读取文件内容的,普通文件不支持这种方式读取,其次就是许多压缩文件什么的文件文件末尾都由很多的空字符串,导致了单纯地用strip()会删除原本的空字符,所以采用了将一定的加密信息存储在密文之中的方法。加密算法总共也只有70多行,python真香

5、总结

    整个PC端目前也只是个DEMO,需要后续不断地完善,比如在等待服务器发密钥的时候主线程都堵塞在这条语句中,导致整个Panel都会处于无响应状态,这个可以通过将与服务器通信的函数放到另一个线程中运行即可解决,再比如双因子的用户自定义iv在某些情况下解密时即使iv不对也可以解密成功,不过我已经找到一定规律可以想办法解决,再比如批处理,这也是个简单事,还有就是文件的完整性检测,需要用到MD5检测,总而言之程序还不完善,后续的新功能添加也势在必行,最后还是那句话,Python真香

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值