python实现aes-256-gcm加密和解密-自已动手写个加解密软件(二) - pu369com

时间:2024-03-11 14:09:15

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()