diff --git a/TongsuoToolbox_v01.pro b/TongsuoToolbox_v01.pro index a6e639c..64312dc 100644 --- a/TongsuoToolbox_v01.pro +++ b/TongsuoToolbox_v01.pro @@ -13,6 +13,7 @@ SOURCES += \ main.cpp \ mainwindow.cpp \ randnum.cpp \ + sm2cert.cpp \ sm2encrypt.cpp \ sm2key.cpp \ sm2signverify.cpp \ @@ -24,6 +25,7 @@ HEADERS += \ home.h \ mainwindow.h \ randnum.h \ + sm2cert.h \ sm2encrypt.h \ sm2key.h \ sm2signverify.h \ @@ -48,6 +50,7 @@ else:unix: PRE_TARGETDEPS += $$(TONGSUO_HOME)/lib64/libcrypto.a FORMS += \ home.ui \ randnum.ui \ + sm2cert.ui \ sm2encrypt.ui \ sm2key.ui \ sm2signverify.ui \ diff --git a/certs.qrc b/certs.qrc new file mode 100644 index 0000000..f997abc --- /dev/null +++ b/certs.qrc @@ -0,0 +1,6 @@ + + + certs/subca.pem + certs/subca_pkey.pem + + diff --git a/certs/ca.pem b/certs/ca.pem new file mode 100644 index 0000000..d16953b --- /dev/null +++ b/certs/ca.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2zCCAYKgAwIBAgIBADAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQjELMAkG +A1UECAwCQ0QxCzAJBgNVBAoMAkdIMQswCQYDVQQLDAJJSjEPMA0GA1UEAwwGQ0Eg +U00yMB4XDTIzMTAyMjA4MTYzNVoXDTI0MTAyMTA4MTYzNVowRTELMAkGA1UEBhMC +QUIxCzAJBgNVBAgMAkNEMQswCQYDVQQKDAJHSDELMAkGA1UECwwCSUoxDzANBgNV +BAMMBkNBIFNNMjBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABGDEBzKqxehinDE1 +yVmhtBg4RZl3yMdYbSQ1YCS4Oq39UpYnIPBQZJtFVcp/mzYkEatAFH3bULzZN9i2 +tYKVG9OjYzBhMB0GA1UdDgQWBBSGjjM6h6hZvgui1qC/aWzcwA8DxTAfBgNVHSME +GDAWgBSGjjM6h6hZvgui1qC/aWzcwA8DxTAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBhjAKBggqgRzPVQGDdQNHADBEAiAG1lSJPjiucZM7Ono6Ym4cZRJ6 +FkYkRCbmUsA7KGUurAIgPB75xE9nBCvjOA5mX0w6qTIxyca9ZZQW/fXKiD7rc9w= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/certs/ca_pkey.pem b/certs/ca_pkey.pem new file mode 100644 index 0000000..6946edd --- /dev/null +++ b/certs/ca_pkey.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgvQZKYXBs2tJ75OiC +Heno6Hy2hOgF40spgGXQjq9wM22hRANCAARgxAcyqsXoYpwxNclZobQYOEWZd8jH +WG0kNWAkuDqt/VKWJyDwUGSbRVXKf5s2JBGrQBR921C82TfYtrWClRvT +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/certs/subca.pem b/certs/subca.pem new file mode 100644 index 0000000..50735f9 --- /dev/null +++ b/certs/subca.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB4jCCAYigAwIBAgIBADAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQjELMAkG +A1UECAwCQ0QxCzAJBgNVBAoMAkdIMQswCQYDVQQLDAJJSjEPMA0GA1UEAwwGQ0Eg +U00yMB4XDTIzMTAyMjA4MTY1MFoXDTI0MTAyMTA4MTY1MFowSDELMAkGA1UEBhMC +QUIxCzAJBgNVBAgMAkNEMQswCQYDVQQKDAJHSDELMAkGA1UECwwCSUoxEjAQBgNV +BAMMCVNVQkNBIFNNMjBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABIWmHv6geS35 +44DbP2u7YJwqswfnHEYrWflC9f2KKFDysQREA92amnPCExdQkM/ei7gQp4KjLI6q +bb6pOuge9qujZjBkMB0GA1UdDgQWBBTrKs5sc0eO1wXiY3pVVctAALwRxjAfBgNV +HSMEGDAWgBSGjjM6h6hZvgui1qC/aWzcwA8DxTASBgNVHRMBAf8ECDAGAQH/AgEA +MA4GA1UdDwEB/wQEAwIBhjAKBggqgRzPVQGDdQNIADBFAiBpzPyJFkWFw7x33wod +1yGoFzj2tspPc58vhnJoxACngwIhAIusYCpxvLmvHkegG1MZwSCr48GthBrfGkR4 +eQIgVj4P +-----END CERTIFICATE----- \ No newline at end of file diff --git a/certs/subca_pkey.pem b/certs/subca_pkey.pem new file mode 100644 index 0000000..809d283 --- /dev/null +++ b/certs/subca_pkey.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgthXQl7N8urUeP84X +1Zc7+0o1QLlfXdOcBc+zLuyYsnWhRANCAASFph7+oHkt+eOA2z9ru2CcKrMH5xxG +K1n5QvX9iihQ8rEERAPdmppzwhMXUJDP3ou4EKeCoyyOqm2+qTroHvar +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/mainwindow.cpp b/mainwindow.cpp index 7595237..39f5f6d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -31,6 +31,8 @@ MainWindow::MainWindow(QWidget *parent) sm2SignVerify = new Sm2SignVerify(); /* SM4加解密实例化 */ sm4Encry = new Sm4encrypt(); + /* SM2签发证书实例化 */ + sm2Cer = new Sm2Cert(); /* 左侧功能导航 */ QList strListWidgetList; strListWidgetList << "首页" @@ -39,8 +41,9 @@ MainWindow::MainWindow(QWidget *parent) << "SM2加解密" << "SM3哈希" << "SM2签名验签" - << "SM4加解密"; - for (int i = 0; i < 7; i++) { + << "SM4加解密" + << "SM2签发证书"; + for (int i = 0; i < 8; i++) { /* listWidget 插入项 */ listWidget->insertItem(i, strListWidgetList[i]); } @@ -52,6 +55,7 @@ MainWindow::MainWindow(QWidget *parent) stackedWidget->addWidget(sm3Hash); stackedWidget->addWidget(sm2SignVerify); stackedWidget->addWidget(sm4Encry); + stackedWidget->addWidget(sm2Cer); /* 设置列表的最大宽度 */ listWidget->setMaximumWidth(200); /* 添加到水平布局 */ diff --git a/mainwindow.h b/mainwindow.h index 932c0b6..c97dc90 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -3,6 +3,7 @@ #include "home.h" #include "randnum.h" +#include "sm2cert.h" #include "sm2encrypt.h" #include "sm2key.h" #include "sm2signverify.h" @@ -44,5 +45,7 @@ class MainWindow : public QMainWindow Sm2SignVerify *sm2SignVerify; /* sm4加解密界面 */ Sm4encrypt *sm4Encry; + /* sm2签发证书 */ + Sm2Cert *sm2Cer; }; #endif // MAINWINDOW_H diff --git a/sm2cert.cpp b/sm2cert.cpp new file mode 100644 index 0000000..2fbaaa2 --- /dev/null +++ b/sm2cert.cpp @@ -0,0 +1,169 @@ +#include "sm2cert.h" +#include "ui_sm2cert.h" + +Sm2Cert::Sm2Cert(QWidget *parent) + : QWidget(parent) + , ui(new Ui::Sm2Cert) +{ + ui->setupUi(this); +} + +Sm2Cert::~Sm2Cert() +{ + delete ui; +} +std::shared_ptr Sm2Cert::genCert(int type, + std::shared_ptr midCA, + std::shared_ptr midcaPkey, + QString CNname, + QString days) +{ + /* 生成用户密钥 */ + std::shared_ptr userKey(EVP_PKEY_Q_keygen(NULL, NULL, "SM2"), EVP_PKEY_free); + if (userKey.get() == NULL) { + /* 错误处理 */ + getError(); + exit(0); + } + /* 输出用户私钥 */ + std::shared_ptr out(BIO_new(BIO_s_mem()), BIO_free); + PEM_write_bio_PrivateKey(out.get(), userKey.get(), NULL, 0, NULL, NULL, NULL); + int len = BIO_pending(out.get()); + char buf[1024] = {}; + BIO_read(out.get(), buf, len); + if (type == 0) { + this->ui->textBrowserEncryKey->setText(QString(buf)); + } else { + this->ui->textBrowserSignKey->setText(QString(buf)); + } + /* 生成CSR */ + std::shared_ptr userReq(X509_REQ_new(), X509_REQ_free); + /* CSR相关设置 */ + X509_REQ_set_pubkey(userReq.get(), userKey.get()); + + std::shared_ptr userCAname(X509_NAME_new(), X509_NAME_free); + X509_NAME_add_entry_by_txt(userCAname.get(), + "CN", + MBSTRING_ASC, + (unsigned char *) CNname.toStdString().c_str(), + -1, + -1, + 0); + X509_REQ_set_subject_name(userReq.get(), userCAname.get()); + + X509_REQ_set_version(userReq.get(), X509_VERSION_3); + X509_REQ_sign(userReq.get(), userKey.get(), EVP_sm3()); + X509_REQ_verify(userReq.get(), userKey.get()); + + /* 签发证书 */ + std::shared_ptr userCer(X509_new(), X509_free); + /* 证书相关设置 */ + std::string str; + if (type == 0) { + str = "Key Encipherment, Data Encipherment"; + } else { + str = "Digital Signature"; + } + std::shared_ptr + cert_ex(X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, str.c_str()), X509_EXTENSION_free); + X509_add_ext(userCer.get(), cert_ex.get(), -1); + + X509_set_version(userCer.get(), X509_VERSION_3); + X509_set_pubkey(userCer.get(), userKey.get()); + + std::shared_ptr aserial(ASN1_INTEGER_new(), ASN1_INTEGER_free); + ASN1_INTEGER_set(aserial.get(), 0); + X509_set_serialNumber(userCer.get(), aserial.get()); + + X509_set_subject_name(userCer.get(), userCAname.get()); + + const X509_NAME *rootCAname = X509_get_subject_name(midCA.get()); + X509_set_issuer_name(userCer.get(), rootCAname); + + time_t curTime = time(NULL); + std::shared_ptr rootBeforeTime(ASN1_TIME_new(), ASN1_TIME_free); + ASN1_TIME_set(rootBeforeTime.get(), curTime); + X509_set_notBefore(userCer.get(), rootBeforeTime.get()); + std::shared_ptr + rootAfterTime(ASN1_TIME_adj(NULL, curTime, 0, days.toInt() * 60 * 60 * 24), ASN1_TIME_free); + X509_set_notAfter(userCer.get(), rootAfterTime.get()); + /* 使用中间CA私钥签发 */ + X509_sign(userCer.get(), midcaPkey.get(), EVP_sm3()); + + return userCer; +} + +void Sm2Cert::on_pushButtonGen_clicked() +{ + /* 获取用户输入的通用名称 */ + QString CN = this->ui->lineEditCN->text(); + if (CN.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入通用名称!"), + QMessageBox::Close, + QMessageBox::Close); + return; + } + /* 获取用户输入的有效期 */ + QString days = this->ui->lineEditDays->text(); + if (days.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入有效期!"), + QMessageBox::Close, + QMessageBox::Close); + return; + } + /* 读取中间CA证书 */ + QFile fsubca(":/certs/subca.pem"); + if (!fsubca.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::warning(NULL, + "warning", + QString("subca.pem打开失败!"), + QMessageBox::Close, + QMessageBox::Close); + return; + } + QTextStream subcaInput(&fsubca); + QString subcaQstr = subcaInput.readAll(); + std::shared_ptr subcaOut(BIO_new(BIO_s_mem()), BIO_free); + BIO_write(subcaOut.get(), subcaQstr.toStdString().c_str(), subcaQstr.size()); + std::shared_ptr subca(PEM_read_bio_X509(subcaOut.get(), NULL, NULL, NULL), X509_free); + fsubca.close(); + + /* 读取中间CA私钥 */ + QFile fpkey(":/certs/subca_pkey.pem"); + if (!fpkey.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::warning(NULL, + "warning", + QString("subca_pkey.pem打开失败!"), + QMessageBox::Close, + QMessageBox::Close); + return; + } + QTextStream pkeyInput(&fpkey); + QString pkeyQstr = pkeyInput.readAll(); + std::shared_ptr pkeyOut(BIO_new(BIO_s_mem()), BIO_free); + BIO_write(pkeyOut.get(), pkeyQstr.toStdString().c_str(), pkeyQstr.size()); + std::shared_ptr pkey(PEM_read_bio_PrivateKey(pkeyOut.get(), NULL, NULL, NULL), + EVP_PKEY_free); + fpkey.close(); + + /* 生成用户签名证书 */ + std::shared_ptr userSignCer = this->genCert(1, subca, pkey, CN, days); + /* 生成用户加密证书 */ + std::shared_ptr userEncryptCer = this->genCert(0, subca, pkey, CN, days); + /* 将用户证书以PEM格式输出到输出栏 */ + std::shared_ptr outSign(BIO_new(BIO_s_mem()), BIO_free); + PEM_write_bio_X509(outSign.get(), userSignCer.get()); + int len = BIO_pending(outSign.get()); + char buf[2048] = {}; + BIO_read(outSign.get(), buf, len); + this->ui->textBrowserSignOutput->setPlainText(QString(buf)); + std::shared_ptr outEncrypt(BIO_new(BIO_s_mem()), BIO_free); + PEM_write_bio_X509(outEncrypt.get(), userEncryptCer.get()); + len = BIO_pending(outEncrypt.get()); + BIO_read(outEncrypt.get(), buf, len); + this->ui->textBrowserEncryptOutput->setPlainText(QString(buf)); +} diff --git a/sm2cert.h b/sm2cert.h new file mode 100644 index 0000000..1628fd5 --- /dev/null +++ b/sm2cert.h @@ -0,0 +1,42 @@ +#ifndef SM2CERT_H +#define SM2CERT_H + +#include "tserror.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ui { +class Sm2Cert; +} + +class Sm2Cert : public QWidget +{ + Q_OBJECT + +public: + explicit Sm2Cert(QWidget *parent = nullptr); + ~Sm2Cert(); + +private slots: + void on_pushButtonGen_clicked(); + +private: + Ui::Sm2Cert *ui; + /* type等于1生成签名证书,等于0生成加密证书 */ + std::shared_ptr genCert(int type, + std::shared_ptr midCA, + std::shared_ptr midcaPkey, + QString CNname, + QString days); +}; + +#endif // SM2CERT_H diff --git a/sm2cert.ui b/sm2cert.ui new file mode 100644 index 0000000..28254fb --- /dev/null +++ b/sm2cert.ui @@ -0,0 +1,158 @@ + + + Sm2Cert + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + 签名证书&密钥: + + + + + + + 365 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + tongsuo + + + 一般为域名 + + + + + + + + + + 生成证书 + + + + + + + 通用名称: + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 私钥/请求: + + + + + + + 有效天数: + + + + + + + 0 + + + + + 自动生成 + + + + + + + 手动生成 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 加密证书&密钥: + + + + + + + + + + + + + +