用tkinter做数字证书的时候老是报错:pyasn1.error.PyAsn1Error: NamedTypes undefined component type
下边是我的代码
import base64
import tkinter as tk
from tkinter import messagebox
import rsa
from pyasn1.codec.der import encoder as der_encoder
from pyasn1.type.univ import ObjectIdentifier, OctetString, Sequence
import datetime
import hashlib
from Crypto.PublicKey import RSA
import os
from tkinter import *
import pymysql
from Crypto.Signature import pkcs1_15
from Crypto.Util.asn1 import DerSequence
from pyasn1.codec.der import encoder
from base64 import b64decode
import json
from Crypto.Hash import SHA256
class LoginFrame(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
# 设置窗口标题
self.master.title('数字证书制作与验证登陆')
# 设置窗口大小
self.master.geometry('400x300+500+200')
# 设置用户名标签
self.label_user = tk.Label(self.master, text='用户名:',font=('Arial', 15,'bold'))
self.label_user.place(x=50, y=50)
# 设置用户名输入框
self.entry_user = tk.Entry(self.master, width=20, font=('Arial', 14))
self.entry_user.place(x=130, y=50, height=30)
# 设置密码标签
self.label_pwd = tk.Label(self.master, text='密码:',font=('Arial', 15,'bold'))
self.label_pwd.place(x=70, y=120)
# 设置密码输入框
self.entry_pwd = tk.Entry(self.master, width=20, font=('Arial', 14), show='*')
self.entry_pwd.place(x=130, y=120, height=30)
# 设置登录按钮1
self.btn_login1 = tk.Button(self.master, text='制作数字证书', font=('Arial', 10), command=self.login1, width=15, height=2)
self.btn_login1.place(x=50, y=178)
# 设置登录按钮2
self.btn_login2 = tk.Button(self.master, text='验证数字证书', font=('Arial', 10), command=self.login2, width=15, height=2)
self.btn_login2.place(x=220, y=178)
# 设置注册按钮
self.btn_register = tk.Button(self.master, text='注册', font=('Arial', 10), command=self.register, width=6,
height=2)
self.btn_register.place(x=170, y=240)
def register(self):
reg_window = Toplevel(self) # 创建新的顶级窗口作为注册窗口
reg_window.title("注册") # 设置窗口标题和其他属性
username_label = Label(reg_window, text="用户名:")
username_label.place(x=20, y=20)
username_entry = Entry(reg_window, width=12)
username_entry.place(x=70, y=20)
password_label = Label(reg_window, text="密码:")
password_label.place(x=20, y=80)
password_entry = Entry(reg_window, show="*", width=12)
password_entry.place(x=70, y=80)
def save_to_db():
username = username_entry.get()
password = password_entry.get()
# 连接数据库
db = pymysql.connect(host='localhost', port=3306, user='root', passwd='ZhouYiPu1207', db='anquanzhuce')
cursor = db.cursor()
# 插入数据
sql = "INSERT INTO user (username, password) VALUES (%s, %s)"
cursor.execute(sql, (username, password))
db.commit()
# 关闭数据库连接
cursor.close()
db.close()
# 提示用户已注册成功
messagebox.showinfo("提示", "注册成功!")
btn_register = Button(reg_window, text="确认注册", command=save_to_db)
btn_register.place(x=70, y=130)
def login1(self):
user = self.entry_user.get()
pwd = self.entry_pwd.get()
# 连接数据库
db = pymysql.connect(host='localhost', port=3306, user='root', passwd='ZhouYiPu1207', db='anquanzhuce')
cursor = db.cursor()
# 查询数据是否存在
sql = "SELECT * FROM user WHERE username = %s AND password = %s"
cursor.execute(sql, (user, pwd))
result = cursor.fetchone()
# 关闭数据库连接
cursor.close()
db.close()
if result:
messagebox.showinfo('登陆成功', '欢迎制作数字证书!')
# 如果用户名和密码正确,打开CertWindow窗口
self.master.destroy()
cert_window = CertWindow()
cert_window.mainloop()
else:
messagebox.showerror("错误", "用户名或密码错误!")
def login2(self):
user = self.entry_user.get()
pwd = self.entry_pwd.get()
# 连接数据库
db = pymysql.connect(host='localhost', port=3306, user='root', passwd='ZhouYiPu1207', db='anquanzhuce')
cursor = db.cursor()
# 查询数据是否存在
sql = "SELECT * FROM user WHERE username = %s AND password = %s"
cursor.execute(sql, (user, pwd))
result = cursor.fetchone()
# 关闭数据库连接
cursor.close()
db.close()
if result:
messagebox.showinfo('登陆成功', '欢迎验证数字证书!')
# 如果用户名和密码正确,打开VerifyWindow窗口
self.master.destroy()
verify_window = VerifyWindow()
verify_window.mainloop()
else:
# 提示用户名或密码错误
messagebox.showerror('登陆失败', '用户名或密码错误!')
class CertWindow(tk.Tk):
def __init__(self):
super().__init__()
# 设置窗口大小和位置
self.geometry('400x700+550+50')
self.title('数字证书制作')
# 输入姓名
self.label_user_name = tk.Label(self.master, text='姓名:', font=('微软雅黑', 15))
self.label_user_name.place(x=70, y=50)
self.entry_user_name = tk.Entry(self.master, width=20, font=('微软雅黑', 14))
self.entry_user_name.place(x=130, y=50, height=30)
# 输入身份证
self.label_user_id = tk.Label(self.master, text='身份证:', font=('微软雅黑', 15))
self.label_user_id.place(x=50, y=120)
self.entry_user_id = tk.Entry(self.master, width=20, font=('微软雅黑', 14), show='*')
self.entry_user_id.place(x=130, y=120, height=30)
# 定制公钥
self.btn_dzgy = tk.Button(self.master, text='定制公钥', font=('微软雅黑', 12), command=self.dzgy, width=15, height=2)
self.btn_dzgy.place(x=127, y=180)
self.textbox_dzgy = tk.Text(self.master, font=('微软雅黑', 10), width=30, height=3)
self.textbox_dzgy.place(x=85, y=220)
# 一键生成数字证书
self.btn_scszzs = tk.Button(self.master, text='生成数字证书', font=('微软雅黑', 12), command=self.scszzs,width=15, height=2)
self.btn_scszzs.place(x=40, y=300)
# 导出数字证书
self.btn_dcszzs = tk.Button(self.master, text='导出数字证书', font=('微软雅黑', 12), command=self.dcszzs, width=15,height=2)
self.btn_dcszzs.place(x=220, y=300)
# 显示CA公钥
self.btn_CAgy = tk.Button(self.master, text='CA公钥', font=('微软雅黑', 12), command=self.CAgy, width=15,
height=2)
self.btn_CAgy.place(x=10, y=380)
# 文本框显示CA公钥
self.textbox_CAgy = tk.Text(self.master, font=('微软雅黑', 10), width=30, height=5)
self.textbox_CAgy.place(x=10, y=420)
# 复制
self.btn_fzCAgy = tk.Button(self.master, text='复制', font=('微软雅黑', 12), command=self.fzCAgy, width=10,
height=1)
self.btn_fzCAgy.place(x=260, y=445)
# 显示签名
self.btn_qm = tk.Button(self.master, text='数字签名', font=('微软雅黑', 12), command=self.qm, width=15,
height=2)
self.btn_qm.place(x=10, y=530)
# 签名文本框
self.textbox_qm = tk.Text(self.master, font=('微软雅黑', 10), width=30, height=5)
self.textbox_qm.place(x=10, y=570)
# 复制
self.btn_fzqm = tk.Button(self.master, text='复制', font=('微软雅黑', 12), command=self.fzqm, width=10,
height=1)
self.btn_fzqm.place(x=260, y=595)
# 定制公钥
def dzgy(self):
# 创建弹窗
top = tk.Toplevel(self.master)
top.title('定制公钥')
top.geometry('200x120+500+200')
lbl = tk.Label(top, text='请输入密钥长度:')
lbl.pack(pady=10)
# 创建输入框
self.entry_keylen = tk.Entry(top)
self.entry_keylen.pack(pady=10)
# 创建确认按钮
btn_confirm = tk.Button(top, text='确认', command=self.generate_keypair)
btn_confirm.pack()
def generate_keypair(self):
# 获取用户输入的密钥长度
keylen = int(self.entry_keylen.get())
# 生成密钥对
key_pair = RSA.generate(keylen)
# 获取公钥并按要求转换为 PEM 格式
pem_public_key = key_pair.publickey().export_key(format='PEM', pkcs=1).decode()
# # 去掉 PEM 格式公钥中的 -----BEGIN PUBLIC KEY----- 和 -----END PUBLIC KEY----- 行
# pem_public_key = pem_public_key.replace('-----BEGIN PUBLIC KEY-----', '-----BEGIN RSA PUBLIC KEY-----', 1)
# pem_public_key = pem_public_key.replace('-----END PUBLIC KEY-----', '-----END RSA PUBLIC KEY-----', 1)
# 将公钥展示在 textbox_dzgy 中
self.textbox_dzgy.delete('1.0', 'end')
self.textbox_dzgy.insert('end', pem_public_key)
# 创建保存文件夹
folder_path = 'C:/Users/35152/Desktop/PycharmProjects/ShuZiZhengShu'
if not os.path.exists(folder_path):
os.makedirs(folder_path)
# 保存公钥文件
with open(folder_path + '/public_user.pem', 'w') as f:
f.write(pem_public_key)
# 弹出保存成功的提示框
tk.messagebox.showinfo('保存成功', '公钥已保存在本文件夹中')
# 生成数字证书并保存到文件夹
def scszzs(self):
# 定义哈希算法 OID 值
HASH_ALGO_OID = "2.16.840.1.101.3.4.2.1"
# 获取用户姓名、身份证号码和公钥
user_name = self.entry_user_name.get()
user_id = self.entry_user_id.get()
with open('C:/Users/35152/Desktop/PycharmProjects/ShuZiZhengShu/public_user.pem', 'r') as f:
pem_public_key = f.read()
# 将 PEM 格式公钥转换为 Crypto.PublicKey.RSA.RsaKey 对象
public_key_obj = RSA.import_key(pem_public_key)
# 组装数字证书的原始数据
certificate_raw_data = {
"user_name": user_name,
"user_id": user_id,
"public_key": pem_public_key,
}
json_data = json.dumps(certificate_raw_data)
# 计算数字证书原始数据的哈希值并添加 OID 属性
hash_obj = hashlib.new('sha256WithRSAEncryption', json_data.encode('utf-8'))
hash_obj.update(json_data.encode('utf-8'))
certificate_hash = hash_obj.digest()
# 将哈希值按 ASN.1 DER 编码形式添加 OID 属性
hash_info = Sequence()
hash_info.setComponentByPosition(0, HASH_ALGO_OID)
hash_info.setComponentByPosition(1, OctetString(cert_hash))
hashed_data = der_encoder.encode(hash_info)
# 基于私钥对数字证书原始数据进行签名
with open('private_CA.pem', 'r') as f:
pem_private_key = f.read()
private_key_obj = RSA.import_key(pem_private_key)
signature = pkcs1_15.new(private_key_obj).sign(hashed_data)
# 将签名进行Base64编码
base64_signature = base64.b64encode(signature).decode()
# 组装数字证书并写入文件
certificate = {
"user_name": user_name,
"user_id": user_id,
"public_key": pem_public_key,
"signature": base64_signature,
}
# 计算证书哈希值
cert_hash = hashlib.sha256(certificate).digest()
folder_path = 'C:/Users/35152/Desktop/PycharmProjects/ShuZiZhengShu'
if not os.path.exists(folder_path):
os.makedirs(folder_path)
with open(folder_path + '/certificate.json', 'w') as f:
json.dump(certificate, f)
# 更新提示信息
messagebox.showinfo('提示', '数字证书生成成功!')
# 导出数字证书
def dcszzs(self):
pass
# 显示CA公钥
def CAgy(self):
pass
# 复制CA公钥
def fzCAgy(self):
pass
# 显示签名
def qm(self):
pass
# 复制签名
def fzqm(self):
pass
class VerifyWindow(tk.Tk):
def __init__(self):
super().__init__()
# 设置窗口大小和位置
self.geometry('400x400+550+200')
self.title('数字证书验证')
# 设置CA公钥标签
self.label_CAgy = tk.Label(self.master, text='CA公钥:', font=('微软雅黑', 15, 'bold'))
self.label_CAgy.place(x=45, y=50)
# 设置CA公钥输入框
self.entry_CAgy = tk.Entry(self.master, width=20, font=('微软雅黑', 14))
self.entry_CAgy.place(x=130, y=50, height=30)
# 设置签名标签
self.label_qm = tk.Label(self.master, text='数字签名:', font=('微软雅黑', 15, 'bold'))
self.label_qm.place(x=33, y=120)
# 设置签名输入框
self.entry_qm = tk.Entry(self.master, width=20, font=('微软雅黑', 14), show='*')
self.entry_qm.place(x=130, y=120, height=30)
# 导入数字证书
self.btn_drszzs = tk.Button(self.master, text='导入数字证书', font=('微软雅黑', 15, 'bold'), command=self.drszzs, width=17,
height=2)
self.btn_drszzs.place(x=90, y=180)
# 验证数字证书
self.btn_yzszzs = tk.Button(self.master, text='验证数字证书', font=('微软雅黑', 15, 'bold'),command=self.yzszzs, width=17,
height=2)
self.btn_yzszzs.place(x=90, y=280)
# 导入数字证书
def drszzs(self):
pass
#验证数字证书
def yzszzs(self):
pass
# 创建登陆界面
root = tk.Tk()
login_frame = LoginFrame(root)
login_frame.pack()
root.mainloop()