python实现aes-256-gcm加密和解密-自已动手写个加解密软件(二)
之前用golang写了个练手的加解密https://www.cnblogs.com/pu369/p/12924007.html,但是思路有点问题,于是用python重新写了一个能够实用的
#-*- coding: utf-8 -*-
#文件后缀pyw可隐藏命令行窗口
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from tkinter import Tk,mainloop,StringVar,Frame,Text,Scrollbar,Toplevel,Entry,Button,Label,messagebox #可用*代替
import sys,os,time
import hashlib,binascii,base64,cryptography.exceptions
encryptfile = __file__.split("\\")[-1].split(".")[0] #加密文件名与脚本名相同
if os.path.exists(encryptfile):
if os.path.isdir(encryptfile):
messagebox.showinfo(title='提示', message='当前目录不允许有脚本同名的文件夹')
sys.exit(0)
else:
with open(encryptfile,'w') as f:
pass
#time.sleep(1) #等待创建文件
root = Tk()# 初始化
root.title(encryptfile)
root.geometry('1500x700+100+100') #长x宽+左上角x和y
#双向绑定变量
password0 = StringVar(value="")
password1 = StringVar(value="")
password_login = StringVar(value="")
#全局变量
saved_cipher_base64 =b""
#加密函数
def encrypt_aes256gcm(key, ciphertext, aad):
'''
aes-256-gcm 加密
key: 为str,hex字符串,64字符(32字节)
aad: 为str,hex字符串,32字符(16字节)
ciphertext: 为bytes, 明文
返回: 为bytes, base64 的密文
'''
aes_gcm_ivlen = 12
key_bytes = binascii.unhexlify(key)
aad_bytes = binascii.unhexlify(aad)
data = ciphertext
iv_bytes = os.urandom(aes_gcm_ivlen)
aesgcm = AESGCM(key_bytes) # tag_length=16
crypt_bytes = aesgcm.encrypt(iv_bytes, data, aad_bytes)
return base64.b64encode(iv_bytes + crypt_bytes)
#解密函数
def decrypt_aes256gcm(key, ciphertext, aad):
'''
aes-256-gcm 解密
key: 为str,hex字符串,64字符(32字节)
aad: 为str,hex字符串,32字符(16字节)
ciphertext: 为bytes, base64 的密文
返回: bytes 的明文, 或者解密失败 返回 b''
'''
aes_gcm_ivlen = 12
key_bytes = binascii.unhexlify(key)
aad_bytes = binascii.unhexlify(aad)
try:
data = base64.b64decode(ciphertext)
except binascii.Error as e:
return b''
iv_bytes = data[0:aes_gcm_ivlen]
data = data[aes_gcm_ivlen:]
aesgcm = AESGCM(key_bytes) # tag_length=16
try:
text_bytes = aesgcm.decrypt(iv_bytes, data, aad_bytes)
except cryptography.exceptions.InvalidTag as e:
return b''
return text_bytes
#加密文件,并存盘
def enc_writef():
'''
aes-256-gcm 加密
key: 为str,hex字符串,64字符(32字节)
aad: 为str,hex字符串,32字符(16字节)
ciphertext: 为bytes, 明文
返回: 为bytes, base64 的密文
'''
with open(encryptfile,'wb') as f:
contents = text_box.get('0.0', 'end')#明文str
contents_bytes = base64.b64encode(contents.encode())#转为Base64byes
m = hashlib.md5(password0.get().encode())
aad =m.hexdigest()
m = hashlib.sha3_256(password0.get().encode())
key =m.hexdigest()
ciphertext_bytes = encrypt_aes256gcm(key, contents_bytes, aad)
try:
f.write(ciphertext_bytes)
messagebox.showinfo(title='成功', message='已经加密保存!')
root.destroy()
except:
messagebox.showinfo(title='成功', message='已经加密保存!')
root.destroy()
#两次输入密码确认
def btn_pw():
if password0.get()=="":
messagebox.showinfo(title='错误', message='密码不能为空')
elif password0.get()!=password1.get():
messagebox.showinfo(title='错误', message='两次密码不一致')
else:
enc_writef()
#保存并退出按钮
def btn_save():
if messagebox.askokcancel('提示','确认保存并退出?'):
#动态生成密码输入窗体
top_level = Toplevel()
top_level.geometry('300x100+100+100') #长x宽+左上角x和y
top_level.title("请输入密码")
entry_pw1 = Entry(top_level,textvariable=password0,show='*')
entry_pw1.grid(column=0,row=0)
entry_pw2 = Entry(top_level,textvariable=password1,show='*')
entry_pw2.grid(column=0,row=1)
button_pw = Button(top_level,text='确定', command=btn_pw)
button_pw.grid(column=0,row=2)
top_level.attributes("-toolwindow", 1)
top_level.wm_attributes("-topmost", 1)
button_save = Button(root,text='保存并退出', command=btn_save)
button_save.grid(column=0,row=0)
#文本框控件 width 单行可见字符# height 显示行数#autoseparators撤销操作分隔符
text_box = Text(root, width=100, height=20, undo=True, autoseparators=False)
text_box.grid(column=0,row=2,columnspan=10)
text_box.config(font=("宋体", 20))
#解密文件,并加载至GUI
def btn_login():
m = hashlib.md5(password_login.get().encode())
aad =m.hexdigest()
m = hashlib.sha3_256(password_login.get().encode())
key =m.hexdigest()
try:
plain_text_base64 = decrypt_aes256gcm(key,saved_cipher_base64, aad)
if plain_text_base64 ==b"":
messagebox.showinfo(title='失败', message='解密失败!')
root.destroy()
else:
temp = base64.b64decode(plain_text_base64)
plain_result = temp.decode()
text_box.insert('insert',plain_result)
top_level.withdraw()
messagebox.showinfo(title='成功', message='解密成功!')
except:
messagebox.showinfo(title='失败', message='解密失败!')
root.destroy()
#读取密文,保存为全局变量,并判断是否为空
with open(encryptfile,'rb') as f:
saved_cipher_base64 = f.read()
if saved_cipher_base64 ==b"":#刚刚建立的新密码本
pass
else: #弹出解密密码窗体
top_level = Toplevel()
top_level.geometry('300x100+100+100') #长x宽+左上角x和y
top_level.title("请输入解密密码")
entry_pw = Entry(top_level,textvariable=password_login,show='*')
entry_pw.grid(column=0,row=0)
button_pw = Button(top_level,text='确定', command=btn_login)
button_pw.grid(column=0,row=2)
top_level.attributes("-toolwindow", 1)
top_level.wm_attributes("-topmost", 1)
#文本框加滚动条
scroll=Scrollbar()
scroll.grid(column=10,row=2,sticky="NS")
#文本框与滚动条关联
scroll.config(command=text_box.yview)
text_box.config(yscrollcommand=scroll.set)
mainloop()
补充:后来电脑重装了,双击这个.pyw运行不起来,执行: pip install cryptography ,然后直接双击脚本仍不行。于是打开IDLE加载这个脚本,竟然运行成功了,奇怪。
后来又一次重装电脑及python,并pip 安装相关的库后,又正常了。
浙公网安备 33010602011771号