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)
#插入日期时间快捷键
def btn_cur_time():
    cur_time = time.strftime('%Y-%m-%d %H:%M:%S ',time.localtime(time.time())) 
    text_box.insert('insert',cur_time)
button_save = Button(root,text='插入日期时间', command=btn_cur_time)
button_save.grid(column=1,row=0)
mainloop()
原文地址:https://www.cnblogs.com/pu369/p/15420768.html