基于RSA加密和Tkinter可视化的密码存储程序(可用于期末作业设计、Python练习、实用应用;抗错误输入、抗密码盗取)三:主函数界面

此篇接上篇,有兴趣的可以去主页或专栏看看,没有的话咱直接开始:

基于RSA加密和Tkinter可视化的密码存储程序(可用于期末作业设计、Python练习、实用应用;抗错误输入、抗密码盗取)二:登录、注册界面_山河之书Liu_Zixin的博客-CSDN博客这个就算了吧)但是,密码是8位以上的无限位,同时需要包含大小写字母和数字,让暴力破解当场崩溃,接下来就是代码段(注释明确),我会在最后放上程序截图。注册界面(为保证安全,仅支持一次性注册),密码修改界面,密保问题修改界面,忘记密码登录界面;密码信息(平台,账号,密码三个属性)插入,基于平台名称的密码信息模糊查询,密码信息定位修改(仅能修改密码,其他两项不能),密码信息定位删除,用户密码登录,忘记密码登录,登录密码修改,密保问题修改,密钥(公钥私钥)加密存储,密码信息、登录检查信息加密存储;https://blog.csdn.net/weixin_61864411/article/details/127177297?spm=1001.2014.3001.5501        本文主要包括数据操纵主界面(增删改查功能一个不少),还有修改密码,修改密保问题及答案的辅助界面,主要逻辑就是读出加密存储的信息列表,然后私钥解密,进行基于关键字的查询或者执行基于关键字删除,修改;或者是一次性插入。完成后对写入的新信息进行加密,写入列表,重新写入文件;如果仅查询,则仅读取而不写入。

        修改密码和密保问题、答案的地方也是同一道理,读取出登录信息列表,然后再将替换的信息加密写回,将列表写回原文件即可。

话不多说上代码,代码包含详细注释,希望能帮到任何看到的人,有些注释在文章二中反复注释过了,就可能不再注释了。程序截图将放在代码段之后。

# 别问模块调用去哪里了,问就是,在上一篇文章里,按理说,这段是插在上一篇文章的代码的设置最后几个log_in等按键之前的,就是那里,嗯,对的,这一段代码是无法单独直接运行的。

def main():
    window_main = tk.Tk()  # 数据操纵主界面
    window_main.title("TOP SECRET")
    window_main.geometry("600x500")
    tree = ttk.Treeview(window_main)  # 这就是展示表啦

    tree["column"] = ("platform", "user_name", "user_password")  # 展示表的展示属性
    tree.column("platform", width=132)  # 设置platform属性框宽度
    tree.heading("platform", text="PLATFORM")  #设置platform属性框名
    tree.column("user_name", width=132)  # 同上之理
    tree.heading("user_name", text="USERNAME")
    tree.column("user_password", width=132)
    tree.heading("user_password", text="PASSWORD")
    tree.place(x=0, y=100)  # 设置属性框位置

    platform = tk.Label(window_main, text="PLATFORM-KEYWORD")  # 设置关键字“平台”的输入框,详细注释见上一篇文章
    platform.grid(row=1, column=0)
    platform_str = tk.StringVar()
    platform_input = tk.Entry(window_main, width=20, textvariable=platform_str)
    platform_input.grid(row=1, column=1)

    user_name = tk.Label(window_main, text="USERNAME")  # 设置要存储的用户名输入框
    user_name.grid(row=2, column=0)
    user_name_str = tk.StringVar()
    user_name_input = tk.Entry(window_main, width=20, textvariable=user_name_str)
    user_name_input.grid(row=2, column=1)

    user_password = tk.Label(window_main, text="PASSWORD")  # 设置要存储的密码输入框
    user_password.grid(row=3, column=0)
    user_password_str = tk.StringVar()
    user_password_input = tk.Entry(window_main, width=20, textvariable=user_password_str)
    user_password_input.grid(row=3, column=1)

    def select():  # 查找密码
        try:
            with open("file_password.pickle", "rb+") as file_password:  # 读取密码存储文件,注意此处是rb+模式打开,因此在遇到没有文件的时候就会报错,配合后面的故障排除,完美
                password_data = pickle.load(file_password)  # 获取密码
            with open("private.pem") as private_file:
                q = private_file.read()  # 获取私钥,毕竟只需要读取不需要写入,公钥就不需要了
            privkey_use = rsa.PrivateKey.load_pkcs1(q.encode())  # 解码出私钥

            platform_info = platform_input.get()  # 获取关键词(平台名称)

            pattern = r"^\w*\s*\w*\s*\w*\s*(%s)\s*\w*\s*\w*\s*\w*$" % platform_info  # 正则表达式,用于模糊匹配检查,这里之所以折腾这一大段,是因为不连续空格无法一次性识别的问题,我设置了最多可以有完全不连续的四个空格(前后各四个),想必可以搞定大部分使用场景吧。
            list_show = []  # 原来的列表里面的数据是加密的,需要先解密,然后写入新的列表
            if len(platform_info) == 0:  # 没有信息的情况下
                for i in range(len(password_data)):
                    list_element = []
                    for j in range(len(password_data[i])):
                        data_j_0 = rsa.decrypt(password_data[i][j], privkey_use)
                        data_j = data_j_0.decode()
                        list_element.append(data_j)
                    list_show.append(list_element)  # 全部解码,写入新的列表,准备输出
            else:  # 如果有输入信息
                for i in range(len(password_data)):
                    list_element = []
                    data_0 = rsa.decrypt(password_data[i][0], privkey_use)  # 此处先解码出关键字平台,先进行匹配,成了再解密其他信息,提高效率的
                    data = data_0.decode()
                    tf = re.match(pattern, data)  # 进行模糊匹配检查,如果符合一并输出
                    if tf:
                        for j in range(len(password_data[i])):
                            data_j_0 = rsa.decrypt(password_data[i][j], privkey_use)  # 解密其他信息
                            data_j = data_j_0.decode()
                            list_element.append(data_j)
                        list_show.append(list_element)
                    else:
                        continue  # 不符合直接跳过,然后最后如果没有列表自动为空,啥也检索不出

            list_show.sort(key=lambda ele: ele[0], reverse=False)  # 排序,这个……就不再自选什么升序降序了,直接默认吧,FALSE是啥我也忘了,可能是升序,大家自己试试就知道了
            x = tree.get_children()  # 获取信息总元组(行)数
            for i in x:
                tree.delete(i)  # 这还原初始化的
            for i in range(len(list_show)):
                tree.insert("", i, text=str(i + 1), values=(list_show[i][0], list_show[i][1], list_show[i][2]))  # 插入信息,那个text之所以要+1,是因为众所周知,列表索引是从0开始的

            file_password.close()
            private_file.close()  # 关文件

        except FileNotFoundError:  # 没有文件就先去插入一条,顺百年间文件
            tk.messagebox.showinfo("", "No data. Please first insert one.")

    def insert():
        try:
            platform_info = platform_input.get()
            user_name_info = user_name_input.get()
            user_password_info = user_password_input.get()

            with open("file_password.pickle", "wb+") as file_password:
                password_data = pickle.load(file_password)  # 这里就是插入的重要意义,wb+可以在没有文件的时候新建
            with open("public.pem") as public_file:
                p = public_file.read()

            pubkey_use = rsa.PublicKey.load_pkcs1(p.encode())  # 这个不需要读取,只需要写入,只需要公钥

            if platform_info != 0 and user_name_info != 0 and user_password_info != 0:  # 数据不能为0
                platform_info_encrypted = rsa.encrypt(platform_info.encode(), pubkey_use)
                user_name_info_encrypted = rsa.encrypt(user_name_info.encode(), pubkey_use)
                user_password_info_encrypted = rsa.encrypt(user_password_info.encode(), pubkey_use)
                list_element = [platform_info_encrypted, user_name_info_encrypted, user_password_info_encrypted]  # 常规操作,详参上一篇注册函数插入登录信息

                password_data.append(list_element)
                pickle.dump(password_data, file_password)
                tk.messagebox.showinfo("CORRECT", "INSERT SUCCESSFULLY")
            else:  # 但凡有一个数据缺失,都不让插入
                tk.messagebox.showinfo("", "Please input all information needed.")

            file_password.close()
            public_file.close()

        except EOFError:  # 这是为了防止有文件,但文件为空的情况,即新建文件时是无法从中读取出列表的,此时报EOFError,自动转到这里,插入一个新的初始列表,就好了,上面那个只能用于第二次插入(就算第一次插入后把数据删除了,但是预设列表在那里,就足够了)
            platform_info = platform_input.get()
            user_name_info = user_name_input.get()
            user_password_info = user_password_input.get()

            with open("public.pem") as public_file:
                q = public_file.read()

            file_password = open("file_password.pickle", "wb+")

            pubkey_use = rsa.PublicKey.load_pkcs1(q.encode())
            password_data = []
            if platform_info != 0 and user_name_info != 0 and user_password_info != 0:
                platform_info_encrypted = rsa.encrypt(platform_info.encode(), pubkey_use)
                user_name_info_encrypted = rsa.encrypt(user_name_info.encode(), pubkey_use)
                user_password_info_encrypted = rsa.encrypt(user_password_info.encode(), pubkey_use)
                list_element = [platform_info_encrypted, user_name_info_encrypted, user_password_info_encrypted]

                password_data.append(list_element)
                pickle.dump(password_data, file_password)
                tk.messagebox.showinfo("CORRECT", "INSERT SUCCESSFULLY")
            else:
                tk.messagebox.showinfo("", "Please input all information needed.")

            file_password.close()
            public_file.close()

    def change():  # 修改数据用的函数
        try:
            with open("file_password.pickle", "rb+") as file_password:
                password_data = pickle.load(file_password)
            with open("private.pem") as private_file:
                q = private_file.read()
            with open("public.pem") as public_file:  # 这次可是得公私钥都读出了,毕竟要写还要根据修改目标进行筛选
                p = public_file.read()

            privkey_use = rsa.PrivateKey.load_pkcs1(q.encode())
            pubkey_use = rsa.PublicKey.load_pkcs1(p.encode())

            platform_info = platform_input.get()
            user_password_info = user_password_input.get()

            list_item = []
            num = len(password_data)
            for i in range(num):
                data_i_0 = rsa.decrypt(password_data[i][0], privkey_use)  #循环读取解密关键词平台
                data_i = data_i_0.decode()
                list_item.append(data_i)
            if platform_info in list_item:  # 如果出现关键词和输入的一样(这个必须完全一样)
                for i in range(num):
                    if list_item[i] == platform_info:
                        user_password_info_encrypted = rsa.encrypt(user_password_info.encode(), pubkey_use)
                        password_data[i][2] = user_password_info_encrypted  # 修改密码
                        with open("file_password.pickle", "rb+") as file_password:
                            pickle.dump(password_data, file_password)  # 重新写入
                        tk.messagebox.showinfo("CORRECT", "CHANGE SUCCESSFULLY")
                        break
                    else:
                        continue
            else:  # 找不到的话就提示
                tk.messagebox.showinfo("", "No such platform. Please confirm before type.")

            file_password.close()
            private_file.close()
            public_file.close()
        except FileNotFoundError:  # 这操作也得有数据才能操作,是吧?
            tk.messagebox.showinfo("", "No data. Please first insert one.")

    def delete():  # 删除函数,使用的和change几乎一样的逻辑,只是不再替换而是直接删掉这一个二维列表中的一个列表项,这段代码作为对上一段代码的理解代码,看懂上一个之后来看这个练练手
        try:
            with open("file_password.pickle", "rb+") as file_password:
                password_data = pickle.load(file_password)
            with open("private.pem") as private_file:
                q = private_file.read()
            privkey_use = rsa.PrivateKey.load_pkcs1(q.encode())

            platform_info = platform_input.get()

            list_item = []
            num = len(password_data)
            for i in range(num):
                data_i_0 = rsa.decrypt(password_data[i][0], privkey_use)
                data_i = data_i_0.decode()
                list_item.append(data_i)
            if platform_info in list_item:
                for i in range(num):
                    if list_item[i] == platform_info:
                        del password_data[i]
                        with open("file_password.pickle", "rb+") as file_password:
                            pickle.dump(password_data, file_password)
                        tk.messagebox.showinfo("CORRECT", "DELETE SUCCESSFULLY")
                        file_password.close()
                        private_file.close()
                        break
                    else:
                        continue
            else:
                tk.messagebox.showinfo("", "No such platform. Please confirm before type.")

        except FileNotFoundError:
            tk.messagebox.showinfo("", "No data. Please first insert one.")

    def quit_window():  # 退出该界面
        window_main.destroy()

    tk.Button(window_main, text="SELECT", command=select).place(x=50, y=350)
    tk.Button(window_main, text="INSERT", command=insert).place(x=150, y=350)
    tk.Button(window_main, text="CHANGE", command=change).place(x=250, y=350)
    tk.Button(window_main, text="DELETE", command=delete).place(x=350, y=350)
    tk.Button(window_main, text="QUIT", command=quit_window).place(x=488, y=350)
    tk.Button(window_main, text="CHANGE PASSWORD", command=change_password).place(x=50, y=390)
    tk.Button(window_main, text="CHANGE QUESTION", command=change_question).place(x=400, y=390)  # 六个按键自然不必多说


def change_password():  # 修改密码函数
    def change_password_use():
        with open("file_log_in.pickle", "rb+") as file_log_in:
            data_log_in = pickle.load(file_log_in)
        with open("public.pem") as public_file:
            p = public_file.read()

        pubkey_use = rsa.PublicKey.load_pkcs1(p.encode())
        password_change_info = password_change_input.get()
        password_change_confirm_info = password_change_confirm_input.get()

        pattern_password = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[0-9a-zA-Z]{8,12}$"
        result_password = re.match(pattern_password, password_change_info)
        if password_change_info == 0 or password_change_confirm_info == 0:
            tk.messagebox.showinfo("", "Information can not be empty")
        elif not result_password:
            tk.messagebox.showinfo("", "Password must contain more than 8 characters, \n"
                                       "including numbers, upper and lower case letters.")
        elif password_change_info != password_change_confirm_info:
            tk.messagebox.showinfo("", "Inconsistent passwords.")
        else:
            password_change_info_encrypted = rsa.encrypt(password_change_info.encode(), pubkey_use)
            password_change_confirm_info_encrypted = rsa.encrypt(password_change_confirm_info.encode(), pubkey_use)

            data_log_in[1] = password_change_info_encrypted
            data_log_in[2] = password_change_confirm_info_encrypted
            with open("file_log_in.pickle", "wb+") as file_log_in:
                pickle.dump(data_log_in, file_log_in)

            file_log_in.close()
            public_file.close()
            tk.messagebox.showinfo("CORRECT", "CHANGE SUCCESSFULLY")
            window_change_password.destroy()

    window_change_password = tk.Tk()
    window_change_password.title("CHANGE PASSWORD")
    window_change_password.geometry("230x150")

    password_change = tk.Label(window_change_password, text="Please input new password.")
    password_change.place(x=10, y=20)
    password_change_str = tk.StringVar()
    password_change_input = tk.Entry(window_change_password, width=30, textvariable=password_change_str, show="*")
    password_change_input.place(x=10, y=40)

    password_change_confirm = tk.Label(window_change_password, text="Please input new password again.")
    password_change_confirm.place(x=10, y=70)
    password_change_confirm_str = tk.StringVar()
    password_change_confirm_input = tk.Entry(window_change_password, width=30, textvariable=password_change_confirm_str,
                                             show="*")
    password_change_confirm_input.place(x=10, y=90)

    change = tk.Button(window_change_password, text="CHANGE", command=change_password_use)
    change.place(x=80, y=120)


def change_question():  # 修改密保问题及答案函数
    def change_question_use():
        with open("file_log_in.pickle", "rb+") as file_log_in:
            data_log_in = pickle.load(file_log_in)
        with open("public.pem") as public_file:
            p = public_file.read()

        pubkey_use = rsa.PublicKey.load_pkcs1(p.encode())
        security_question_change_info = security_question_change_input.get()
        answer_change_info = answer_change_input.get()

        if security_question_change_info == 0 or answer_change_info == 0:
            tk.messagebox.showinfo("", "Information can not be empty")
        else:
            security_question_change_info_encrypted = rsa.encrypt(security_question_change_info.encode(), pubkey_use)
            answer_change_info_encrypted = rsa.encrypt(answer_change_info.encode(), pubkey_use)

            data_log_in[3] = security_question_change_info_encrypted
            data_log_in[4] = answer_change_info_encrypted
            with open("file_log_in.pickle", "wb+") as file_log_in:
                pickle.dump(data_log_in, file_log_in)

            file_log_in.close()
            public_file.close()
            tk.messagebox.showinfo("CORRECT", "CHANGE SUCCESSFULLY")
            window_change_question.destroy()

    window_change_question = tk.Tk()
    window_change_question.title("CHANGE PASSWORD")
    window_change_question.geometry("230x150")

    security_question_change = tk.Label(window_change_question, text="Please input new security question.")
    security_question_change.place(x=10, y=20)
    security_question_change_str = tk.StringVar()
    security_question_change_input = tk.Entry(window_change_question, width=30,
                                              textvariable=security_question_change_str, show="*")
    security_question_change_input.place(x=10, y=40)

    answer_change = tk.Label(window_change_question, text="Please input answer.")
    answer_change.place(x=10, y=70)
    answer_change_str = tk.StringVar()
    answer_change_input = tk.Entry(window_change_question, width=30, textvariable=answer_change_str, show="*")
    answer_change_input.place(x=10, y=90)

    change = tk.Button(window_change_question, text="CHANGE", command=change_question_use)
    change.place(x=80, y=120)

程序静态效果图:

有些晚了,截图草率了点,见谅,我都测试过的,该有的功能一个不少 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河之书Liu_Zixin

不要打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值