python加密解密图形界面_python桌面端开发手记(序列化、压缩包、加密、图形界面GUI)...

本文记录了一个使用Python开发的离线桌面端应用,包括信息序列化、加密、解密和图形化界面GUI的功能。核心模块涉及JSON序列化、AES和RSA加密解密。GUI部分使用Tkinter实现,最后通过pyinstaller将.py文件转换为.exe可执行文件。
摘要由CSDN通过智能技术生成

0x00

前段时间接到一个小项目是给某行业内部开发离线桌面端,业务流实现上总体分信息录入、加密导出。因为是win桌面端,所以老板说依托Access用VBA做,我据理力争了一下。之前就是用Access+VBA给项目组里各个单位做报销平台,二次开发的速度快,但是等到下发部署的时候遇到诸多问题,系统版本、位数的问题和Access版本、位数的问题,十分坎坷。然后这次的小项目单个用户产生的数据量不大,没有必要拖一个数据库在后面。所以跟老板说:直接把用户录入的信息加密后序列化到磁盘就好了,然后做一个加密打包的功能;而且甲方要的急,就想着用python许多函数不用自己再去写,开发快,最后转可执行文件就好了……以上一段freestyle之后,然后老板觉得OK!然后就开始填坑之旅了……

在把需求分析和设计做了一下后,自己决定按照【核心模块】-->【GUI】-->【编译成可执行文件】的流程走下去

0x01 核心模块

这个部分比较简单,涉及到的主要功能有序列化为.json、反序列化、AES和RSA加密解密等。

1 序列化

1.1 从内存中的dict到磁盘上的json

import json

class Detail(object):#用一个类来封装必要的信息

def __init__(self, infodict):

self.serial_num = infodict['序号'] # 序号

self.type_code = infodict['类型'] # 类型

self.corporation = infodict['单位'] # 单位

self.submitter = infodict['姓名'] # 姓名

# ...

def inst2json(inst):#序列化函数

json_stuff = json.dumps(inst, default=lambda obj: obj.__dict__, ensure_ascii=False)

with open('filename.json', 'a') as f:#追加

f.write(json_stuff)

return

if __name__=='__main__':

myinfodict={}

#向infodict添加必要的键值

myinfodict['序号']='XUHAO'

myinfodict['类型']='LEIXING'

myinfodict['单位']='DANWEI'

myinfodict['姓名']='XINGMING'

# ...

myinst=Detail(myinfodict)#实例化

try:

inst2json(myinst)

except:

print('序列化失败')

else:

print('序列化成功')

1.2 从磁盘上的json到内存中的dict

import json

with open('filename.json','r') as f:

dict_stuff=json.load(f)

print(dict_stuff)

KEY WORDS:

将字典序列化为json

将字典保存为json

json反序列化

将json读成字典

2 加解密

填坑:

装pycrypto这个包的时候可能会报错,需要先装winrandom-1.2.1-cp35-cp35m-win32

2.1 AES加密

import struct

from Crypto.Cipher import AES

import hashlib

import os

def encrypt_file(password, in_filename, out_filename=None, chunksize=64 * 1024):

key = hashlib.sha256(password.encode('utf-8')).digest()

if not out_filename:

out_filename = in_filename + '.crypt'

str = ''

chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'

length = len(chars) - 1

from random import Random

random = Random()

for i in range(16):

str += chars[random.randint(0, length)]

iv = str.encode()

encryptor = AES.new(key, AES.MODE_CBC, iv)

filesize = os.path.getsize(in_filename)

with open(in_filename, 'rb') as infile:

with open(out_filename, 'wb') as outfile:

outfile.write(struct.pack('

由于程序直接将用户输入序列化到磁盘,所以应该加密存储,也可以用上面的代码实现。读入到程序中时在解密,保证用户不会绕过程序读到有价值的数据。

为了防止被逆向出password,在这个项目里不讲AES的密钥硬编码到程序中,而是采用让用户输入密钥种子,在用种子生成AES的密钥,并把这个密钥后用RSA公钥加密的方法来保证数据安全。用AES+RSA而不是直接对所有数据进行RSA是因为数据量大时计算耗时比较小

2.2 RSA密钥对生成

from Crypto.PublicKey import RSA

def generate_RSA(bits=2048):

new_key = RSA.generate(bits, e=65537)

public_key = new_key.publickey().exportKey("PEM")

private_key = new_key.exportKey("PEM")

return private_key, public_key

def keygen():

private,public=generate_RSA()

with open('private.pem','wb') as private_key:

private_key.write(private)

with open('public.pem','wb') as public_key:

public_key.write(public)

if __name__=='__main__':

keygen()

2.3 RSA加密

# -*- coding:utf-8 -*-

import base64

from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5

from Crypto.PublicKey import RSA

def encrypt_key(pwd):

with open('public.pem', 'rb') as f:

pubkey = f.read()

rsakey = RSA.importKey(pubkey)

cipher = Cipher_pkcs1_v1_5.new(rsakey)

cipher_text = base64.b64encode(cipher.encrypt(pwd.encode()))# encrypt的参数是变长字节串

with open('key.crypt', 'wb') as k:

k.write(cipher_text)

if __name__=='__main__':

password='d0main'#

try:

encrypt_key(password)

except:

print('失败')

else:

print('密钥加密成功')

至此,就可以将公钥算法加密的对称密钥和对称加密的数据一起打包了

2.4 RSA解密

# -*- coding=utf-8 -*-

from random import Random

import os

import base64

from Crypto import Random

from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5

from Crypto.PublicKey import RSA

def decrypt_key(key_file):

random_generator = Random.new().read

if os.path.exists('private.pem'):

with open('private.pem','rb') as f:

key = f.read()

rsakey = RSA.importKey(key)

cipher = Cipher_pkcs1_v1_5.new(rsakey)

with open(key_file,'rb') as k:

encrypt_text=k.read()

pwd = cipher.decrypt(base64.b64decode(encrypt_text), random_generator)

return pwd.decode()

else:

print('未找到私钥')

if __name__=='__main__':

print('口令是:'+decrypt_key('key.crypt'))

拿到了口令值后,就可以进行AES解密了

2.5 AES解密

import struct

from Crypto.Cipher import AES

import hashlib

import os

def decrypt_file(password, in_filename, out_filename=None, chunksize=24*1024):

key=hashlib.sha256(password.encode('utf-8')).digest()

if not out_filename:

out_filename = os.path.splitext(in_filename)[0]+'.txt'

with open(in_filename, 'rb') as infile:

origsize = struct.unpack('

KEY WORDS:

python加密

RSA加密

AES加密

3 zip文件操作

3.1 打包

import zipfile

import os

def compress(startdir):

z = zipfile.ZipFile('filename.zip', 'w', zipfile.ZIP_DEFLATED)

for dirpath, dirnames, filenames in os.walk(startdir):

for filename in filenames: #可以在这里对要打包的文件做筛选

z.write(os.path.join(dirpath, filename))

z.close()

if __name__=='__main__':

dirpath='需要打包的文件夹路径'

try:

compress(dirpath)

except:

print('打包失败')

else:

print('打包成功')

3.2 解包

import zipfile

def uncompress(zippath):

f = zipfile.ZipFile(zippath,'r')

for file in f.namelist():

f.extract(file,".")

if __name__=='__main__':

zippath='filename.zip'

uncompress(zippath)

KEYWORDS:

python zip压缩文件

python 解压缩zip

0x02 图形化界面-GUI

用python来做GUI的过程是艰难的。虽然有诸如PyQt、PySide、Tkinter、wxPython许多工具包,但是想要像C#、VB那样在IDE中拖拽控件基本做不到,都是要一行一行写,换言之就是“写界面”!所以决定直接用Python3.5自带的Tkinter来写,而且这一个包相比于其他的工具包,学习起来最快,成本最低。最终决定用Tkinter!

项目涉及到的组件(widget)种类很多,要说起来篇幅过长,一些细节可能会日后更新在主页中,而且网上的教学贴不少,所以就不过多赘述。

心得:由于我的这个项目涉及到许多页面跳转,需要来回调用窗口,因此将窗口(组件)对象化是正确的做法,而非过程化的创建。将不同的窗口封装类,调用的时候实例化,从而避免代码重复。

KEYWORDS:

python 图形化界面

python GUI

tkinter

0x03 从 .py 到 .exe

这个过程也是痛苦的(为什么这么坎坷)。就我所知有py2exe和pyinstaller,wiki告诉我还有cx_Freeze。

我的环境是python3.5,直觉告诉我应该找一个不断更新的,否则后面坑更多。py2exe在2014出了支持python3的版本之后也没有再维护,cx_Freeze的官网看起来维护的也没pyinstaller的漂亮(我怎么以貌取人),所以我还是选择使用pyinstaller V3.2.1

8179fb9d1930ebb6813f3b5f0b216d2d.png

a7db7d1a0c95590b381b1565fe317fdb.png

填坑:

装这个pyinstaller也没少报错,如果报错可能是缺少一些开发组件。PyInstaller在win上需要两个模块。一个是PyWin32或者pypiwin32。如果还没装PyWin32并且使用pip安装PyInstaller,那么 pypiwin32会伴随着自动给你装上。出了上述的模块,还需要pefile这个包。我是在装了pywin32-221.win32-py3.5之后才把pyinstaller装上的。

pyinstaller的使用请参阅pyinstaller文档

也可参考友站https://www.crifan.com/use_pyinstaller_to_package_python_to_single_executable_exe/

常用-F来让pyinstaller只生成一个文件而没有一对其余的组件,用-w来让生成的程序只打开窗口而不是控制台,使用--icon 来设置程序的图标(图标文.ico)。如:

pyinstaller --clean --win-private-assemblies -w -F --icon=new.ico demo.py

这样,在demo.py的目录下回生成两个文件夹,编译好的可执行文件在dist文件夹下,尝试打开,如果不能正常运行,可以前往build下查看warn.txt查看是不是有哪些依赖没有被编译而出错。

填坑:

起初,我的加密模块需要用PyCryptodome。PyCryptodome是从PyCrypto fork出来的,对比PyCrypto加了一些特性,被视为PyCrypto的替代品,所以我已开始也没有装PyCrypto而是直接装PyCryptodome,结果就是编译出来的exe无法运行,提示FATAL ERROR:failed to execute script。后来卸载了PyCryptodome,装了PyCrypto,把代码改了(就是本文第一部分提到的代码),在重新编译后方可正常运行可执行文件。

KEYWORDS:

将python文件转换成exe

将python文件转换成可执行文件

将py转换成exe

0x04 参考文献

1.Mark, Lutz. Python编程:第4版[M]. 北京:中国电力出版社, 2015.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值