diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dd8b00c..b48bf9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,8 +26,17 @@ jobs: run: | clang-format-15 --Werror --dry-run *.cpp *.h - build-on-linux: - runs-on: ubuntu-latest + unix: + strategy: + fail-fast: false + matrix: + os: [ + macos-12, + macos-13, + ubuntu-20.04, + ubuntu-22.04, + ] + runs-on: ${{ matrix.os }} steps: - name: checkout tongsuo uses: actions/checkout@v3 @@ -37,15 +46,15 @@ jobs: - name: build Tongsuo working-directory: ./Tongsuo run: | - ./config --banner=Configured --prefix=${RUNNER_TEMP}/tongsuo enable-ntls + ./config --banner=Configured --prefix=${RUNNER_TEMP}/tongsuo --libdir=${RUNNER_TEMP}/tongsuo/lib enable-ntls make -s -j4 make install - uses: actions/checkout@v3 - name: install QT - uses: jurplel/install-qt-action@v3 + uses: jurplel/install-qt-action@v4 with: - version: 6.2.4 + version: 6.5.3 - name: build tsapp run: | @@ -53,8 +62,14 @@ jobs: make -s -j4 make install - build-on-windows: - runs-on: windows-latest + windows: + strategy: + fail-fast: false + matrix: + os: + - windows-2019 + - windows-2022 + runs-on: ${{ matrix.os }} steps: - uses: ilammy/msvc-dev-cmd@v1 with: @@ -82,9 +97,9 @@ jobs: - uses: actions/checkout@v3 - name: install QT - uses: jurplel/install-qt-action@v3 + uses: jurplel/install-qt-action@v4 with: - version: 6.2.4 + version: 6.5.3 - name: build tsapp shell: cmd diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8524160 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,169 @@ +name: release + +on: + workflow_dispatch: + tags: + - '*' +env: + TONGSUO_VERSION: 8.4.0 + +permissions: + contents: write + +jobs: + new_release: + runs-on: ubuntu-latest + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + steps: + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body: | + Changes in this Release + - First Change + - Second Change + draft: true + prerelease: true + + build_linux_macos: + runs-on: ${{ matrix.os}} + needs: [new_release] + strategy: + matrix: + os: [macos-latest, ubuntu-20.04] + name: "build-${{ matrix.os }}" + steps: + - name: build Tongsuo + run: | + wget "https://github.com/Tongsuo-Project/Tongsuo/archive/refs/tags/${TONGSUO_VERSION}.tar.gz" + tar zxf "${TONGSUO_VERSION}.tar.gz" + pushd "Tongsuo-${TONGSUO_VERSION}" + ./config --prefix=${RUNNER_TEMP}/tongsuo --libdir=${RUNNER_TEMP}/tongsuo/lib no-shared no-dso enable-ntls --release + make -s -j4 + make install + popd + - uses: actions/checkout@v3 + - name: install QT + uses: jurplel/install-qt-action@v4 + with: + version: 6.5.3 + + - name: build tsapp + run: | + TONGSUO_HOME=${RUNNER_TEMP}/tongsuo PREFIX=${RUNNER_TEMP}/tsapp qmake + make -s -j4 + make install + find ${RUNNER_TEMP}/tsapp + + - name: package for macos + run: | + macdeployqt tsapp.app -qmldir=. -verbose=1 -dmg + if: ${{ matrix.os == 'macos-latest' }} + + - name: upload artifact for macos + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ needs.new_release.outputs.upload_url }} + asset_path: tsapp.dmg + asset_name: tsapp-${{ runner.os }}.dmg + asset_content_type: application/octet-stream + if: ${{ matrix.os == 'macos-latest' }} + + - name: install linuxdeployqt and package for linux + run: | + wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage + chmod +x linuxdeployqt-continuous-x86_64.AppImage + cp linuxdeployqt-continuous-x86_64.AppImage /usr/local/bin/linuxdeployqt + mkdir -p ${RUNNER_TEMP}/Install/tsapp/ + cp ${RUNNER_TEMP}/tsapp/tsapp ${RUNNER_TEMP}/Install/tsapp/ + cd ${RUNNER_TEMP}/Install/tsapp/ + linuxdeployqt tsapp -appimage -no-copy-copyright-files -no-plugins -no-translations || echo + cd .. + tar czf tsapp.tgz tsapp + if: ${{ matrix.os == 'ubuntu-20.04' }} + + - name: upload artifact for linux + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ needs.new_release.outputs.upload_url }} + asset_path: ${{ runner.temp }}/Install/tsapp.tgz + asset_name: tsapp-${{ runner.os }}.tgz + asset_content_type: application/x-compressed-tar + if: ${{ matrix.os == 'ubuntu-20.04' }} + + build_windows: + runs-on: windows-latest + needs: [new_release] + steps: + - run: choco install -y winrar + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: win64 + - uses: ilammy/setup-nasm@v1 + with: + platform: win64 + - uses: shogo82148/actions-setup-perl@v1 + - name: Download Tongsuo source + run: | + wget "https://github.com/Tongsuo-Project/Tongsuo/archive/refs/tags/${env:TONGSUO_VERSION}.tar.gz" -OutFile "${env:TONGSUO_VERSION}.tar.gz" + shell: powershell + - run: | + "C:\Program Files\WinRAR\WinRAR.exe" -INUL x %TONGSUO_VERSION%.tar.gz + shell: cmd + - name: build Tongsuo + shell: cmd + run: | + pushd "Tongsuo-%TONGSUO_VERSION%" + mkdir _build + pushd _build + perl ..\Configure no-makedepend no-shared enable-ntls VC-WIN64A --prefix=%RUNNER_TEMP%\tongsuo + nmake /S + nmake install_sw + popd + popd + - uses: actions/checkout@v3 + - name: install QT + uses: jurplel/install-qt-action@v4 + with: + version: 6.5.3 + + - name: build tsapp + shell: cmd + run: | + set TONGSUO_HOME=%RUNNER_TEMP%\tongsuo + set PREFIX=%RUNNER_TEMP%\tsapp + qmake + nmake /S + nmake install + + - name: package + shell: cmd + run: | + set PKG_DIR=tsapp-WIN64 + mkdir %PKG_DIR% + cp %RUNNER_TEMP%\tsapp\tsapp.exe %PKG_DIR%\ + windeployqt --qmldir . %PKG_DIR%\tsapp.exe + "C:\Program Files\WinRAR\WinRAR.exe" a tsapp.zip %PKG_DIR%\ + cd + dir + + - name: upload artifact + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + upload_url: ${{ needs.new_release.outputs.upload_url }} + asset_path: ${{ github.workspace }}\tsapp.zip + asset_name: tsapp-${{ runner.os }}.zip + asset_content_type: application/zip + diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..03d2119 --- /dev/null +++ b/CHANGES @@ -0,0 +1,21 @@ + + tsapp CHANGES + ------------- + + Changes with 1.0.0 [xx XXX xxxx] + + *) 支持随机数生成器 + + *) 支持SM2密钥对生成 + + *) 支持SM2签名和验签 + + *) 支持SM2加密和解密 + + *) 支持SM3杂凑 + + *) 支持SM4加解密,模式包括CBC、ECB、CFB、OFB、CTR + + *) 支持双证书签发 + + *) 支持TLCP客户端 diff --git a/TongsuoToolbox_v01.pro b/TongsuoToolbox_v01.pro index 689694a..a135067 100644 --- a/TongsuoToolbox_v01.pro +++ b/TongsuoToolbox_v01.pro @@ -10,11 +10,14 @@ CONFIG += c++17 # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +TARGET=tsapp + SOURCES += \ - home.cpp \ + about.cpp \ main.cpp \ mainwindow.cpp \ randnum.cpp \ + sm2.cpp \ sm2cert.cpp \ sm2encrypt.cpp \ sm2key.cpp \ @@ -25,9 +28,10 @@ SOURCES += \ tserror.cpp HEADERS += \ - home.h \ + about.h \ mainwindow.h \ randnum.h \ + sm2.h \ sm2cert.h \ sm2encrypt.h \ sm2key.h \ @@ -35,27 +39,26 @@ HEADERS += \ sm3hash.h \ sm4encrypt.h \ tlcpclient.h \ - tserror.h + tserror.h \ + version.h # Default rules for deployment. target.path = $$(PREFIX) !isEmpty(target.path): INSTALLS += target -win32: LIBS += -ladvapi32 -lcrypt32 -lgdi32 -luser32 -lws2_32 -L$$(TONGSUO_HOME)/lib -llibcrypto -else:unix: LIBS += -L$$(TONGSUO_HOME)/lib64 -lcrypto - -win32: LIBS += -ladvapi32 -lcrypt32 -lgdi32 -luser32 -lws2_32 -L$$(TONGSUO_HOME)/lib -llibssl -else:unix: LIBS += -L$$(TONGSUO_HOME)/lib64 -lssl +win32: LIBS += -ladvapi32 -lcrypt32 -lgdi32 -luser32 -lws2_32 -L$$(TONGSUO_HOME)/lib -llibssl -llibcrypto +else:unix: LIBS += -L$$(TONGSUO_HOME)/lib -lssl -lcrypto INCLUDEPATH += $$(TONGSUO_HOME)/include DEPENDPATH += $$(TONGSUO_HOME)/include -win32-g++: PRE_TARGETDEPS += $$(TONGSUO_HOME)/lib/libcrypto.lib.a -else:win32:!win32-g++: PRE_TARGETDEPS += $$(TONGSUO_HOME)/lib/libcrypto.lib -else:unix: PRE_TARGETDEPS += $$(TONGSUO_HOME)/lib64/libcrypto.a +win32-g++: PRE_TARGETDEPS += $$(TONGSUO_HOME)/lib/libcrypto.lib.a $$(TONGSUO_HOME)/lib/libssl.lib.a +else:win32:!win32-g++: PRE_TARGETDEPS += $$(TONGSUO_HOME)/lib/libcrypto.lib $$(TONGSUO_HOME)/lib/libssl.lib +else:unix: PRE_TARGETDEPS += $$(TONGSUO_HOME)/lib/libssl.a $$(TONGSUO_HOME)/lib/libcrypto.a FORMS += \ - home.ui \ + about.ui \ + mainwindow.ui \ randnum.ui \ sm2cert.ui \ sm2encrypt.ui \ @@ -66,7 +69,6 @@ FORMS += \ tlcpclient.ui RESOURCES += \ - certs.qrc \ - images.qrc + certs.qrc DISTFILES += diff --git a/about.cpp b/about.cpp new file mode 100644 index 0000000..795f940 --- /dev/null +++ b/about.cpp @@ -0,0 +1,26 @@ +#include "about.h" +#include "ui_about.h" +#include "version.h" + +About::About(QWidget *parent) + : QDialog(parent) + , ui(new Ui::About) +{ + ui->setupUi(this); + + QString text = ui->textBrowser->toHtml(); + + text.replace("|version|", version); + + ui->textBrowser->setHtml(text); +} + +About::~About() +{ + delete ui; +} + +void About::on_pushButton_clicked() +{ + this->close(); +} diff --git a/about.h b/about.h new file mode 100644 index 0000000..64f8213 --- /dev/null +++ b/about.h @@ -0,0 +1,25 @@ +#ifndef ABOUT_H +#define ABOUT_H + +#include + +namespace Ui { +class About; +} + +class About : public QDialog +{ + Q_OBJECT + +public: + explicit About(QWidget *parent = nullptr); + ~About(); + +private slots: + void on_pushButton_clicked(); + +private: + Ui::About *ui; +}; + +#endif // ABOUT_H diff --git a/about.ui b/about.ui new file mode 100644 index 0000000..32cfb49 --- /dev/null +++ b/about.ui @@ -0,0 +1,67 @@ + + + About + + + + 0 + 0 + 400 + 300 + + + + About tsapp + + + + + + 关闭 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + About tsapp + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><title>About tsapp</title><style type="text/css"> +p, li { white-space: pre-wrap; } +hr { height: 1px; border-width: 0; } +li.unchecked::marker { content: "\2610"; } +li.checked::marker { content: "\2612"; } +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:18pt; font-weight:700;">铜锁密码工具箱(tsapp)|version|</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">铜锁密码工具箱(tsapp)基于铜锁密码库(<a href="https://github.com/Tongsuo-Project/Tongsuo"><span style=" text-decoration: underline; color:#094fd1;">https://github.com/Tongsuo-Project/Tongsuo</span></a>)提供的密码学能力开发的商用密码工具箱桌面应用程序。</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">图形用户界面基于Qt框架开发。</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">本项目地址<a href="https://github.com/Tongsuo-Project/tsapp"><span style=" text-decoration: underline; color:#094fd1;">https://github.com/Tongsuo-Project/tsapp</span></a>,欢迎提交issue和PR。</p></body></html> + + + true + + + + + + + + diff --git a/certs.qrc b/certs.qrc index f997abc..9b68185 100644 --- a/certs.qrc +++ b/certs.qrc @@ -1,6 +1,6 @@ certs/subca.pem - certs/subca_pkey.pem + certs/subca.key diff --git a/certs/ca.key b/certs/ca.key new file mode 100644 index 0000000..69e7e59 --- /dev/null +++ b/certs/ca.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgTSHZtff0A3YHhojG +HKIu0odvPip6+39lsguxDH3m+TmhRANCAARC7ZCfZAaqCbMEh1K3pEj2S6/ty2yN +C6x0zIbyxq+mib7qTssQcLrsPMe1EGb2FZQpGk4L9mOzBNlijoi1ocb5 +-----END PRIVATE KEY----- diff --git a/certs/ca.pem b/certs/ca.pem index d16953b..bc6f8cc 100644 --- a/certs/ca.pem +++ b/certs/ca.pem @@ -1,12 +1,13 @@ -----BEGIN CERTIFICATE----- -MIIB2zCCAYKgAwIBAgIBADAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQjELMAkG +MIIB3jCCAYSgAwIBAgIBAjAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQjELMAkG A1UECAwCQ0QxCzAJBgNVBAoMAkdIMQswCQYDVQQLDAJJSjEPMA0GA1UEAwwGQ0Eg -U00yMB4XDTIzMTAyMjA4MTYzNVoXDTI0MTAyMTA4MTYzNVowRTELMAkGA1UEBhMC -QUIxCzAJBgNVBAgMAkNEMQswCQYDVQQKDAJHSDELMAkGA1UECwwCSUoxDzANBgNV -BAMMBkNBIFNNMjBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABGDEBzKqxehinDE1 -yVmhtBg4RZl3yMdYbSQ1YCS4Oq39UpYnIPBQZJtFVcp/mzYkEatAFH3bULzZN9i2 -tYKVG9OjYzBhMB0GA1UdDgQWBBSGjjM6h6hZvgui1qC/aWzcwA8DxTAfBgNVHSME -GDAWgBSGjjM6h6hZvgui1qC/aWzcwA8DxTAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud -DwEB/wQEAwIBhjAKBggqgRzPVQGDdQNHADBEAiAG1lSJPjiucZM7Ono6Ym4cZRJ6 -FkYkRCbmUsA7KGUurAIgPB75xE9nBCvjOA5mX0w6qTIxyca9ZZQW/fXKiD7rc9w= ------END CERTIFICATE----- \ No newline at end of file +U00yMCAXDTI0MDcwNzA0Mjc0NVoYDzIxMjQwNjEzMDQyNzQ1WjBFMQswCQYDVQQG +EwJBQjELMAkGA1UECAwCQ0QxCzAJBgNVBAoMAkdIMQswCQYDVQQLDAJJSjEPMA0G +A1UEAwwGQ0EgU00yMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEQu2Qn2QGqgmz +BIdSt6RI9kuv7ctsjQusdMyG8savpom+6k7LEHC67DzHtRBm9hWUKRpOC/ZjswTZ +Yo6ItaHG+aNjMGEwHQYDVR0OBBYEFGPkDCglafjEeeT2wufS/PqKqSP+MB8GA1Ud +IwQYMBaAFGPkDCglafjEeeT2wufS/PqKqSP+MA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgGGMAoGCCqBHM9VAYN1A0gAMEUCIQDOKNIcpCOnL/qFC9nYHSY0 +fHWiGgZLLVFkamCN0meRNgIgUfW1xK+7rZddJSHqJKIeHJp28PlKBXY8oIuGhhEz +EqQ= +-----END CERTIFICATE----- diff --git a/certs/ca_pkey.pem b/certs/ca_pkey.pem deleted file mode 100644 index 6946edd..0000000 --- a/certs/ca_pkey.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgvQZKYXBs2tJ75OiC -Heno6Hy2hOgF40spgGXQjq9wM22hRANCAARgxAcyqsXoYpwxNclZobQYOEWZd8jH -WG0kNWAkuDqt/VKWJyDwUGSbRVXKf5s2JBGrQBR921C82TfYtrWClRvT ------END PRIVATE KEY----- \ No newline at end of file diff --git a/certs/subca.key b/certs/subca.key new file mode 100644 index 0000000..b625382 --- /dev/null +++ b/certs/subca.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgC2yI3oPT4cnM8fGf +J/emyP9/Qr87/x1RO5sNMnm5ioqhRANCAAR73c9xN7bdOrqUQhe/77qxwerRbzZe +wZ65DXOMgIztuCiCEQLh0CfjPLV98LxHbUhTc1EJWhDGofTqh8VFQNYj +-----END PRIVATE KEY----- diff --git a/certs/subca.pem b/certs/subca.pem index 50735f9..24144c7 100644 --- a/certs/subca.pem +++ b/certs/subca.pem @@ -1,13 +1,13 @@ -----BEGIN CERTIFICATE----- -MIIB4jCCAYigAwIBAgIBADAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQjELMAkG +MIIB4zCCAYqgAwIBAgIBAjAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQjELMAkG A1UECAwCQ0QxCzAJBgNVBAoMAkdIMQswCQYDVQQLDAJJSjEPMA0GA1UEAwwGQ0Eg -U00yMB4XDTIzMTAyMjA4MTY1MFoXDTI0MTAyMTA4MTY1MFowSDELMAkGA1UEBhMC -QUIxCzAJBgNVBAgMAkNEMQswCQYDVQQKDAJHSDELMAkGA1UECwwCSUoxEjAQBgNV -BAMMCVNVQkNBIFNNMjBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABIWmHv6geS35 -44DbP2u7YJwqswfnHEYrWflC9f2KKFDysQREA92amnPCExdQkM/ei7gQp4KjLI6q -bb6pOuge9qujZjBkMB0GA1UdDgQWBBTrKs5sc0eO1wXiY3pVVctAALwRxjAfBgNV -HSMEGDAWgBSGjjM6h6hZvgui1qC/aWzcwA8DxTASBgNVHRMBAf8ECDAGAQH/AgEA -MA4GA1UdDwEB/wQEAwIBhjAKBggqgRzPVQGDdQNIADBFAiBpzPyJFkWFw7x33wod -1yGoFzj2tspPc58vhnJoxACngwIhAIusYCpxvLmvHkegG1MZwSCr48GthBrfGkR4 -eQIgVj4P ------END CERTIFICATE----- \ No newline at end of file +U00yMCAXDTI0MDcwNzA0Mjc0NloYDzIxMjQwNjEzMDQyNzQ2WjBIMQswCQYDVQQG +EwJBQjELMAkGA1UECAwCQ0QxCzAJBgNVBAoMAkdIMQswCQYDVQQLDAJJSjESMBAG +A1UEAwwJU1VCQ0EgU00yMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEe93PcTe2 +3Tq6lEIXv++6scHq0W82XsGeuQ1zjICM7bgoghEC4dAn4zy1ffC8R21IU3NRCVoQ +xqH06ofFRUDWI6NmMGQwHQYDVR0OBBYEFCi8tdpCMx+yoWdWdO3IZ6xxDhljMB8G +A1UdIwQYMBaAFGPkDCglafjEeeT2wufS/PqKqSP+MBIGA1UdEwEB/wQIMAYBAf8C +AQAwDgYDVR0PAQH/BAQDAgGGMAoGCCqBHM9VAYN1A0cAMEQCIH6UJaA1ppUtSbHn +3JRGdRHpVKgGaxRkqIVIrfgLnG8IAiBrcRv26xSHRe1eFT9BoJkIiFNTb/gbPdjS +0kQ4AdEHkQ== +-----END CERTIFICATE----- diff --git a/certs/subca_pkey.pem b/certs/subca_pkey.pem deleted file mode 100644 index 809d283..0000000 --- a/certs/subca_pkey.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgthXQl7N8urUeP84X -1Zc7+0o1QLlfXdOcBc+zLuyYsnWhRANCAASFph7+oHkt+eOA2z9ru2CcKrMH5xxG -K1n5QvX9iihQ8rEERAPdmppzwhMXUJDP3ou4EKeCoyyOqm2+qTroHvar ------END PRIVATE KEY----- \ No newline at end of file diff --git a/home.cpp b/home.cpp deleted file mode 100644 index 3fed5e8..0000000 --- a/home.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "home.h" -#include "ui_home.h" -#include - -Home::Home(QWidget *parent) - : QWidget(parent) - , ui(new Ui::Home) -{ - ui->setupUi(this); -} - -Home::~Home() -{ - delete ui; -} - -void Home::paintEvent(QPaintEvent *event) -{ - //重写自动执行 - QPixmap pixmap = QPixmap("://images/HomeBackground.png") - .scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - QPainter painter(this); - painter.drawPixmap(this->rect(), pixmap); -} diff --git a/home.h b/home.h deleted file mode 100644 index 57816c4..0000000 --- a/home.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef HOME_H -#define HOME_H - -#include - -namespace Ui { -class Home; -} - -class Home : public QWidget -{ - Q_OBJECT - -public: - explicit Home(QWidget *parent = nullptr); - ~Home(); - -private: - Ui::Home *ui; - -protected: - virtual void paintEvent(QPaintEvent *event) override; -}; -#endif // HOME_H diff --git a/home.ui b/home.ui deleted file mode 100644 index 0c777d8..0000000 --- a/home.ui +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Home - - - - 0 - 0 - 400 - 300 - - - - Form - - - - - diff --git a/images.qrc b/images.qrc deleted file mode 100644 index 38e3ca4..0000000 --- a/images.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - images/HomeBackground.png - images/TongSuoIcon.png - - diff --git a/images/HomeBackground.png b/images/HomeBackground.png deleted file mode 100644 index 3fe6e53..0000000 Binary files a/images/HomeBackground.png and /dev/null differ diff --git a/images/TongSuoIcon.png b/images/TongSuoIcon.png deleted file mode 100644 index fee2724..0000000 Binary files a/images/TongSuoIcon.png and /dev/null differ diff --git a/main.cpp b/main.cpp index 115a22b..26c0c73 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,16 @@ #include "mainwindow.h" +#include #include +BIO *bio_err = NULL; + int main(int argc, char *argv[]) { + if (!OPENSSL_init_ssl(OPENSSL_INIT_NO_LOAD_CONFIG, NULL)) + return 1; + + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT); + QApplication a(argc, argv); MainWindow w; w.show(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 66e7298..ac2a7fb 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,74 +1,30 @@ #include "mainwindow.h" +#include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) + , ui(new Ui::MainWindow) { - /* 主界面设置 */ - this->setGeometry(480, 200, 800, 480); - this->setWindowIcon(QIcon(":/images/TongSuoIcon.png")); - this->setWindowTitle(QString("TongSuo")); - /* widget 小部件实例化 */ - widget = new QWidget(this); - /* 设置居中 */ - this->setCentralWidget(widget); - /* 垂直布局实例化 */ - hBoxLayout = new QHBoxLayout(); - /* 堆栈部件实例化 */ - stackedWidget = new QStackedWidget(); - /* 列表实例化 */ - listWidget = new QListWidget(); - /* 首页实例化 */ - tsHome = new Home(); - /* 随机数生成实例化 */ - rdNum = new RandNum(); - /* SM2密钥生成实例化 */ - sm2Key = new Sm2Key(); - /* SM2加解密实例化 */ - sm2Encry = new Sm2Encrypt(); - /* SM3哈希实例化 */ - sm3Hash = new Sm3Hash(); - /* SM2签名验签实例化 */ - sm2SignVerify = new Sm2SignVerify(); - /* SM4加解密实例化 */ - sm4Encry = new Sm4encrypt(); - /* SM2签发证书实例化 */ - sm2Cer = new Sm2Cert(); - /* TLCP客户端实例化 */ - tlcpClient = new TLCPclient(); - /* 左侧功能导航 */ - QList strListWidgetList; - strListWidgetList << "首页" - << "随机数生成" - << "SM2密钥生成" - << "SM2加解密" - << "SM3哈希" - << "SM2签名验签" - << "SM4加解密" - << "SM2签发证书" - << "TLCP客户端"; - for (int i = 0; i < 9; i++) { - /* listWidget 插入项 */ - listWidget->insertItem(i, strListWidgetList[i]); - } - /* 子页面插入 */ - stackedWidget->addWidget(tsHome); - stackedWidget->addWidget(rdNum); - stackedWidget->addWidget(sm2Key); - stackedWidget->addWidget(sm2Encry); - stackedWidget->addWidget(sm3Hash); - stackedWidget->addWidget(sm2SignVerify); - stackedWidget->addWidget(sm4Encry); - stackedWidget->addWidget(sm2Cer); - stackedWidget->addWidget(tlcpClient); - /* 设置列表的最大宽度 */ - listWidget->setMaximumWidth(200); - /* 添加到水平布局 */ - hBoxLayout->addWidget(listWidget); - hBoxLayout->addWidget(stackedWidget); - /* 将 widget 的布局设置成 hboxLayout */ - widget->setLayout(hBoxLayout); - /* 利用 listWidget 的信号函数 currentRowChanged()与槽函数 setCurrentIndex()进行信号与槽连接*/ - connect(listWidget, SIGNAL(currentRowChanged(int)), stackedWidget, SLOT(setCurrentIndex(int))); + ui->setupUi(this); + about = new About(); } -MainWindow::~MainWindow() {} +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::on_action_about_triggered() +{ + about->show(); +} + +void MainWindow::on_action_exit_triggered() +{ + this->close(); +} + +void MainWindow::on_listWidget_currentRowChanged(int currentRow) +{ + this->ui->stackedWidget->setCurrentIndex(currentRow); +} diff --git a/mainwindow.h b/mainwindow.h index 4ed7ac6..d8ac0ba 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -1,54 +1,32 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include "home.h" -#include "randnum.h" -#include "sm2cert.h" -#include "sm2encrypt.h" -#include "sm2key.h" -#include "sm2signverify.h" -#include "sm3hash.h" -#include "sm4encrypt.h" -#include "tlcpclient.h" -#include -#include +#include "about.h" #include -#include + +namespace Ui { +class MainWindow; +} class MainWindow : public QMainWindow { Q_OBJECT public: - MainWindow(QWidget *parent = nullptr); + explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); +private slots: + void on_action_about_triggered(); + + void on_action_exit_triggered(); + + void on_listWidget_currentRowChanged(int currentRow); + private: - /* widget 小部件 */ - QWidget *widget; - /* 水平布局 */ - QHBoxLayout *hBoxLayout; - /* 列表视图 */ - QListWidget *listWidget; - /* 堆栈窗口部件 */ - QStackedWidget *stackedWidget; - /* 首页界面 */ - Home *tsHome; - /* 随机数生成界面 */ - RandNum *rdNum; - /* sm2密钥生成*/ - Sm2Key *sm2Key; - /* sm2加密界面*/ - Sm2Encrypt *sm2Encry; - /* sm3哈希界面 */ - Sm3Hash *sm3Hash; - /* sm2签名验签界面 */ - Sm2SignVerify *sm2SignVerify; - /* sm4加解密界面 */ - Sm4encrypt *sm4Encry; - /* sm2签发证书 */ - Sm2Cert *sm2Cer; - /* TLCP客户端界面 */ - TLCPclient *tlcpClient; + Ui::MainWindow *ui; + + About *about; }; + #endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..2974c20 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,172 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + 铜锁密码工具箱(tsapp) + + + + + + + + + + 200 + 16777215 + + + + + 随机数生成 + + + + + SM2密钥生成 + + + + + SM2签名验签 + + + + + SM2加解密 + + + + + SM3杂凑 + + + + + SM4加解密 + + + + + 双证书签发 + + + + + TLCP客户端 + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + 0 + 0 + 800 + 24 + + + + + tsapp + + + + + + + + + + + 关于tsapp + + + + + 退出tsapp + + + + + + RandNum + QWidget +
randnum.h
+ 1 +
+ + Sm2Key + QWidget +
sm2key.h
+ 1 +
+ + Sm2SignVerify + QWidget +
sm2signverify.h
+ 1 +
+ + Sm2Encrypt + QWidget +
sm2encrypt.h
+ 1 +
+ + Sm3Hash + QWidget +
sm3hash.h
+ 1 +
+ + Sm4encrypt + QWidget +
sm4encrypt.h
+ 1 +
+ + Sm2Cert + QWidget +
sm2cert.h
+ 1 +
+ + TLCPclient + QWidget +
tlcpclient.h
+ 1 +
+
+ + +
diff --git a/randnum.cpp b/randnum.cpp index 64bc7d6..2fe70c0 100644 --- a/randnum.cpp +++ b/randnum.cpp @@ -6,9 +6,9 @@ RandNum::RandNum(QWidget *parent) , ui(new Ui::RandNum) { ui->setupUi(this); - /* 限制只能输入整数且范围为[1,256]*/ + /* 限制只能输入整数且范围为[1,128 * 1024]*/ QIntValidator *aIntValidator = new QIntValidator; - aIntValidator->setRange(1, 256); + aIntValidator->setRange(1, 131072); ui->lineEditInput->setValidator(aIntValidator); } @@ -19,22 +19,32 @@ RandNum::~RandNum() void RandNum::on_pushButtonGen_clicked() { - /* 获取用户输入 */ QString inputByte = this->ui->lineEditInput->text(); int randNumByte = inputByte.toInt(); - std::unique_ptr buf(new unsigned char[randNumByte]); - /* 获取随机数输出栏 */ - QTextBrowser *outputNum = this->ui->textBrowserOutput; - /* 调用随机数生成函数 */ - int ret = RAND_bytes(buf.get(), randNumByte); + size_t len = randNumByte * 2 + 1; + std::vector buf; + std::vector str; + + buf.reserve(randNumByte); + + int ret = RAND_bytes((unsigned char *) buf.data(), randNumByte); + if (ret == 0) { - /* 生成失败弹窗 */ - getError(); - return; + printTSError(); } else { - /* 生成成功将结果写到输出框 */ - std::shared_ptr outBuf(OPENSSL_buf2hexstr(buf.get(), randNumByte), - [](char *outbuf) { OPENSSL_free(outbuf); }); - outputNum->setText(QString(outBuf.get())); + str.reserve(len); + + if (OPENSSL_buf2hexstr_ex(str.data(), + len, + NULL, + (unsigned char *) buf.data(), + randNumByte, + '\0') + != 1) + return; + + this->ui->textBrowserOutput->setText(QString::fromStdString(std::string(str.data(), len))); } + + return; } diff --git a/randnum.h b/randnum.h index e7a68b8..fde77d8 100644 --- a/randnum.h +++ b/randnum.h @@ -3,6 +3,7 @@ #include "tserror.h" #include +#include #include #include #include diff --git a/randnum.ui b/randnum.ui index 578d4da..88e51ce 100644 --- a/randnum.ui +++ b/randnum.ui @@ -6,123 +6,103 @@ 0 0 - 463 - 312 + 740 + 531 Form - - - - Qt::Vertical - - - - 20 - 40 - - - - - - + + + + 生成随机数 + + + + + - + 0 0 - - - 12 - + + + 10 + 10 + + + + 128 + + + + + + + 字节 - + - Qt::Vertical + Qt::Horizontal - 20 - 40 + 40 + 20 - - + + - Qt::Vertical + Qt::Horizontal - 20 - 40 + 40 + 20 - - - - 生成的十六进制随机数: - - - - - - - 输入您希望获取的随机数的字节数(1~256): - - - - - - - - 12 - + + + + Qt::Vertical - - 生成 + + + 20 + 40 + - + - - - - - 12 - + + + + + 0 + 0 + - - 1 + + hex格式 - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/sm2.cpp b/sm2.cpp new file mode 100644 index 0000000..17418ef --- /dev/null +++ b/sm2.cpp @@ -0,0 +1,197 @@ +#include +#include + +EVP_PKEY *sm2_key_new_from_raw_pub(const std::string &pub) +{ + std::string hex; + std::vector buf; + OSSL_PARAM_BLD *keybld = NULL; + OSSL_PARAM *keyparams = NULL; + EVP_PKEY_CTX *keyctx = NULL; + EVP_PKEY *pkey = NULL; + + hex = std::string("04") + pub; + + keybld = OSSL_PARAM_BLD_new(); + if (keybld == NULL) + goto end; + + buf.reserve(hex.length() / 2); + + if (OPENSSL_hexstr2buf_ex(buf.data(), buf.capacity(), NULL, hex.c_str(), '\0') != 1) + goto end; + + if (!OSSL_PARAM_BLD_push_utf8_string(keybld, OSSL_PKEY_PARAM_GROUP_NAME, "SM2", 3)) + goto end; + + if (!OSSL_PARAM_BLD_push_octet_string(keybld, + OSSL_PKEY_PARAM_PUB_KEY, + buf.data(), + buf.capacity())) + goto end; + + keyparams = OSSL_PARAM_BLD_to_param(keybld); + keyctx = EVP_PKEY_CTX_new_from_name(NULL, "SM2", NULL); + + if (keyctx == NULL || keyparams == NULL) + goto end; + + if (EVP_PKEY_fromdata_init(keyctx) <= 0 + || EVP_PKEY_fromdata(keyctx, &pkey, EVP_PKEY_PUBLIC_KEY, keyparams) <= 0) + goto end; +end: + EVP_PKEY_CTX_free(keyctx); + OSSL_PARAM_free(keyparams); + OSSL_PARAM_BLD_free(keybld); + return pkey; +} + +EVP_PKEY *sm2_key_new_from_raw_pub_and_priv(const std::string &pub, const std::string &priv) +{ + std::string hex; + std::vector buf; + OSSL_PARAM_BLD *keybld = NULL; + OSSL_PARAM *keyparams = NULL; + EVP_PKEY_CTX *keyctx = NULL; + EVP_PKEY *pkey = NULL; + BIGNUM *bn = NULL; + + keybld = OSSL_PARAM_BLD_new(); + if (keybld == NULL) + goto end; + + if (!OSSL_PARAM_BLD_push_utf8_string(keybld, OSSL_PKEY_PARAM_GROUP_NAME, "SM2", 3)) + goto end; + + buf.clear(); + buf.reserve(priv.length() / 2); + + if (OPENSSL_hexstr2buf_ex(buf.data(), buf.capacity(), NULL, priv.c_str(), '\0') != 1) + goto end; + + bn = BN_new(); + if (bn == NULL) + goto end; + + if (BN_bin2bn(buf.data(), buf.capacity(), bn) == NULL + || !OSSL_PARAM_BLD_push_BN(keybld, OSSL_PKEY_PARAM_PRIV_KEY, bn)) + goto end; + + hex = std::string("04") + pub; + + buf.clear(); + buf.reserve(hex.length() / 2); + + if (OPENSSL_hexstr2buf_ex(buf.data(), buf.capacity(), NULL, hex.c_str(), '\0') != 1) + goto end; + + if (!OSSL_PARAM_BLD_push_octet_string(keybld, + OSSL_PKEY_PARAM_PUB_KEY, + buf.data(), + buf.capacity())) + goto end; + + keyparams = OSSL_PARAM_BLD_to_param(keybld); + keyctx = EVP_PKEY_CTX_new_from_name(NULL, "SM2", NULL); + + if (keyctx == NULL || keyparams == NULL) + goto end; + + if (EVP_PKEY_fromdata_init(keyctx) <= 0 + || EVP_PKEY_fromdata(keyctx, &pkey, EVP_PKEY_KEYPAIR, keyparams) <= 0) + goto end; +end: + BN_free(bn); + EVP_PKEY_CTX_free(keyctx); + OSSL_PARAM_free(keyparams); + OSSL_PARAM_BLD_free(keybld); + return pkey; +} + +int sm2_key_get_priv_pem(const EVP_PKEY *pkey, std::string &pem) +{ + int ret = 0; + BIO *out = NULL; + long len; + char *buf = NULL; + + out = BIO_new(BIO_s_mem()); + if (out == NULL) + goto end; + + if (!PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, NULL)) + goto end; + + len = BIO_get_mem_data(out, &buf); + + pem = std::string(buf, len); + + ret = 1; +end: + BIO_free(out); + return ret; +} + +int sm2_key_get_pub_pem(const EVP_PKEY *pkey, std::string &pem) +{ + int ret = 0; + BIO *out = NULL; + long len; + char *buf = NULL; + + out = BIO_new(BIO_s_mem()); + if (out == NULL) + goto end; + + if (!PEM_write_bio_PUBKEY(out, pkey)) + goto end; + + len = BIO_get_mem_data(out, &buf); + + pem = std::string(buf, len); + + ret = 1; +end: + BIO_free(out); + return ret; +} + +int sm2_key_get_pub_hex(const EVP_PKEY *pkey, std::string &hex) +{ + BIGNUM *qx = NULL, *qy = NULL; + char *pubx = NULL, *puby = NULL; + + if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &qx) + || !EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &qy)) + return 0; + + pubx = BN_bn2hex(qx); + puby = BN_bn2hex(qy); + + hex = std::string(pubx) + std::string(puby); + + BN_clear_free(qx); + BN_clear_free(qy); + OPENSSL_free(pubx); + OPENSSL_free(puby); + + return 1; +} + +int sm2_key_get_priv_hex(const EVP_PKEY *pkey, std::string &hex) +{ + BIGNUM *priv = NULL; + char *buf = NULL; + + if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv)) + return 0; + + buf = BN_bn2hex(priv); + + hex = std::string(buf); + + OPENSSL_free(buf); + BN_clear_free(priv); + + return 1; +} diff --git a/sm2.h b/sm2.h new file mode 100644 index 0000000..ad532a6 --- /dev/null +++ b/sm2.h @@ -0,0 +1,20 @@ +#ifndef SM2_H +#define SM2_H + +#include +#include +#include +#include +#include +#include +#include +#include + +int sm2_key_get_pub_pem(const EVP_PKEY *pkey, std::string &pem); +int sm2_key_get_priv_pem(const EVP_PKEY *pkey, std::string &pem); +int sm2_key_get_pub_hex(const EVP_PKEY *pkey, std::string &hex); +int sm2_key_get_priv_hex(const EVP_PKEY *pkey, std::string &hex); +EVP_PKEY *sm2_key_new_from_raw_pub(const std::string &pub); +EVP_PKEY *sm2_key_new_from_raw_pub_and_priv(const std::string &pub, const std::string &priv); + +#endif // SM2_H diff --git a/sm2cert.cpp b/sm2cert.cpp index 2fbaaa2..92f2ae3 100644 --- a/sm2cert.cpp +++ b/sm2cert.cpp @@ -1,5 +1,6 @@ #include "sm2cert.h" #include "ui_sm2cert.h" +#include Sm2Cert::Sm2Cert(QWidget *parent) : QWidget(parent) @@ -12,101 +13,280 @@ Sm2Cert::~Sm2Cert() { delete ui; } -std::shared_ptr Sm2Cert::genCert(int type, - std::shared_ptr midCA, - std::shared_ptr midcaPkey, - QString CNname, - QString days) + +static char *opt_getprog(void) { - /* 生成用户密钥 */ - 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); - /* 证书相关设置 */ + return (char *) ""; +} + +/* + * name is expected to be in the format /type0=value0/type1=value1/type2=... + * where + can be used instead of / to form multi-valued RDNs if canmulti + * and characters may be escaped by \ + */ +static X509_NAME *parse_name(const char *cp, int chtype, int canmulti, const char *desc) +{ + int nextismulti = 0; + char *work; + X509_NAME *n; + + if (*cp++ != '/') { + BIO_printf(bio_err, + "%s: %s name is expected to be in the format " + "/type0=value0/type1=value1/type2=... where characters may " + "be escaped by \\. This name is not in that format: '%s'\n", + opt_getprog(), + desc, + --cp); + return NULL; + } + + n = X509_NAME_new(); + if (n == NULL) { + BIO_printf(bio_err, "%s: Out of memory\n", opt_getprog()); + return NULL; + } + work = OPENSSL_strdup(cp); + if (work == NULL) { + BIO_printf(bio_err, "%s: Error copying %s name input\n", opt_getprog(), desc); + goto err; + } + + while (*cp != '\0') { + char *bp = work; + char *typestr = bp; + unsigned char *valstr; + int nid; + int ismulti = nextismulti; + nextismulti = 0; + + /* Collect the type */ + while (*cp != '\0' && *cp != '=') + *bp++ = *cp++; + *bp++ = '\0'; + if (*cp == '\0') { + BIO_printf(bio_err, + "%s: Missing '=' after RDN type string '%s' in %s name string\n", + opt_getprog(), + typestr, + desc); + goto err; + } + ++cp; + + /* Collect the value. */ + valstr = (unsigned char *) bp; + for (; *cp != '\0' && *cp != '/'; *bp++ = *cp++) { + /* unescaped '+' symbol string signals further member of multiRDN */ + if (canmulti && *cp == '+') { + nextismulti = 1; + break; + } + if (*cp == '\\' && *++cp == '\0') { + BIO_printf(bio_err, + "%s: Escape character at end of %s name string\n", + opt_getprog(), + desc); + goto err; + } + } + *bp++ = '\0'; + + /* If not at EOS (must be + or /), move forward. */ + if (*cp != '\0') + ++cp; + + /* Parse */ + nid = OBJ_txt2nid(typestr); + if (nid == NID_undef) { + BIO_printf(bio_err, + "%s: Skipping unknown %s name attribute \"%s\"\n", + opt_getprog(), + desc, + typestr); + if (ismulti) + BIO_printf(bio_err, + "Hint: a '+' in a value string needs be escaped using '\\' else a new " + "member of a multi-valued RDN is expected\n"); + continue; + } + if (*valstr == '\0') { + BIO_printf(bio_err, + "%s: No value provided for %s name attribute \"%s\", skipped\n", + opt_getprog(), + desc, + typestr); + continue; + } + if (!X509_NAME_add_entry_by_NID( + n, nid, chtype, valstr, strlen((char *) valstr), -1, ismulti ? -1 : 0)) { + ERR_print_errors(bio_err); + BIO_printf(bio_err, + "%s: Error adding %s name attribute \"/%s=%s\"\n", + opt_getprog(), + desc, + typestr, + valstr); + goto err; + } + } + + OPENSSL_free(work); + return n; + +err: + X509_NAME_free(n); + OPENSSL_free(work); + return NULL; +} + +static X509 *genCert(int type, + X509 *midCA, + EVP_PKEY *midcaPkey, + QString subj, + QString days, + char **key, + size_t *keylen) +{ + X509_NAME *name = NULL; + X509 *userCer = NULL; std::string str; + long len; + BIO *out = NULL; + X509_EXTENSION *cert_ex = NULL; + X509_REQ *userReq = NULL; + ASN1_INTEGER *aserial = NULL; + const X509_NAME *rootCAname; + time_t curTime; + ASN1_TIME *rootBeforeTime = NULL; + ASN1_TIME *rootAfterTime = NULL; + EVP_PKEY *userKey = EVP_PKEY_Q_keygen(NULL, NULL, "SM2"); + + if (userKey == NULL) { + printTSError(); + return NULL; + } + + out = BIO_new(BIO_s_mem()); + if (out == NULL) + goto end; + + if (!PEM_write_bio_PrivateKey(out, userKey, NULL, NULL, 0, NULL, NULL)) { + printTSError(); + goto end; + } + + len = BIO_get_mem_data(out, NULL); + if (len <= 0) + goto end; + + *key = (char *) malloc(len); + if (*key == NULL) + goto end; + + if (BIO_read(out, *key, len) != len) + goto end; + + *keylen = len; + + userReq = X509_REQ_new(); + if (userReq == NULL) + goto end; + + X509_REQ_set_pubkey(userReq, userKey); + + if (!subj.isEmpty()) { + name = parse_name(subj.toStdString().c_str(), MBSTRING_ASC, 1, "subject"); + + if (!name) { + return NULL; + } + + X509_REQ_set_subject_name(userReq, name); + } + + if (!X509_REQ_set_version(userReq, X509_VERSION_3) + || !X509_REQ_sign(userReq, userKey, EVP_sm3()) || !X509_REQ_verify(userReq, userKey)) + goto end; + 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()); + userCer = X509_new(); + if (userCer == NULL) + goto end; + + cert_ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, str.c_str()); + if (cert_ex == NULL) + goto end; + + if (!X509_add_ext(userCer, cert_ex, -1) || !X509_set_version(userCer, X509_VERSION_3) + || !X509_set_pubkey(userCer, userKey)) + goto end; - std::shared_ptr aserial(ASN1_INTEGER_new(), ASN1_INTEGER_free); - ASN1_INTEGER_set(aserial.get(), 0); - X509_set_serialNumber(userCer.get(), aserial.get()); + aserial = ASN1_INTEGER_new(); - X509_set_subject_name(userCer.get(), userCAname.get()); + if (!ASN1_INTEGER_set(aserial, 0)) + goto end; - const X509_NAME *rootCAname = X509_get_subject_name(midCA.get()); - X509_set_issuer_name(userCer.get(), rootCAname); + if (!X509_set_serialNumber(userCer, aserial) || !X509_set_subject_name(userCer, name)) + goto end; - 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()); + rootCAname = X509_get_subject_name(midCA); + if (!X509_set_issuer_name(userCer, rootCAname)) + goto end; + + curTime = time(NULL); + rootBeforeTime = ASN1_TIME_new(); + rootAfterTime = ASN1_TIME_adj(NULL, curTime, 0, days.toInt() * 60 * 60 * 24); + + if (!ASN1_TIME_set(rootBeforeTime, curTime) || !X509_set_notBefore(userCer, rootBeforeTime) + || !X509_set_notAfter(userCer, rootAfterTime)) + goto end; + + if (!X509_sign(userCer, midcaPkey, EVP_sm3())) + goto end; + +end: + ASN1_TIME_free(rootAfterTime); + ASN1_TIME_free(rootBeforeTime); + ASN1_INTEGER_free(aserial); + X509_EXTENSION_free(cert_ex); + X509_REQ_free(userReq); + BIO_free(out); + EVP_PKEY_free(userKey); return userCer; } void Sm2Cert::on_pushButtonGen_clicked() { - /* 获取用户输入的通用名称 */ - QString CN = this->ui->lineEditCN->text(); - if (CN.isEmpty()) { + QString subj = this->ui->lineEditSubj->text(); + QString days = this->ui->lineEditDays->text(); + QFile fsubca(":/certs/subca.pem"); + QFile fpkey(":/certs/subca.key"); + X509 *userSignCer = NULL, *userEncryptCer = NULL; + char *signKey = NULL, *encKey = NULL; + size_t signKeyLen, encKeyLen; + QString subcaQstr, pkeyQstr; + X509 *subca = NULL; + EVP_PKEY *pkey = NULL; + long len; + char *buf = NULL; + BIO *out = NULL; + + if (subj.isEmpty()) { QMessageBox::warning(NULL, "warning", - QString("请输入通用名称!"), + QString("请输入主体名称!"), QMessageBox::Close, QMessageBox::Close); return; } - /* 获取用户输入的有效期 */ - QString days = this->ui->lineEditDays->text(); + if (days.isEmpty()) { QMessageBox::warning(NULL, "warning", @@ -115,8 +295,7 @@ void Sm2Cert::on_pushButtonGen_clicked() QMessageBox::Close); return; } - /* 读取中间CA证书 */ - QFile fsubca(":/certs/subca.pem"); + if (!fsubca.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::warning(NULL, "warning", @@ -125,45 +304,96 @@ void Sm2Cert::on_pushButtonGen_clicked() 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打开失败!"), + QString("subca.key打开失败!"), QMessageBox::Close, QMessageBox::Close); return; } + QTextStream subcaInput(&fsubca); 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); + + subcaQstr = subcaInput.readAll(); + pkeyQstr = pkeyInput.readAll(); + + out = BIO_new(BIO_s_mem()); + if (out == NULL) + goto end; + + if (BIO_write(out, subcaQstr.toStdString().c_str(), subcaQstr.size()) != subcaQstr.size()) + goto end; + + subca = PEM_read_bio_X509(out, NULL, NULL, NULL); + if (subca == NULL) { + this->ui->textBrowserSignKey->setText(subcaQstr); + printTSError(); + goto end; + } + + fsubca.close(); + BIO_reset(out); + + if (BIO_write(out, pkeyQstr.toStdString().c_str(), pkeyQstr.size()) != pkeyQstr.size()) + goto end; + + pkey = PEM_read_bio_PrivateKey(out, NULL, NULL, NULL); + if (pkey == NULL) { + printTSError(); + goto end; + } + 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)); + userSignCer = genCert(1, subca, pkey, subj, days, &signKey, &signKeyLen); + if (userSignCer == NULL) { + printTSError(); + goto end; + } + + userEncryptCer = genCert(0, subca, pkey, subj, days, &encKey, &encKeyLen); + if (userEncryptCer == NULL) { + printTSError(); + goto end; + } + + this->ui->textBrowserSignKey->setText(QString::fromStdString(std::string(signKey, signKeyLen))); + this->ui->textBrowserEncryKey->setText(QString::fromStdString(std::string(encKey, encKeyLen))); + + BIO_reset(out); + + if (!PEM_write_bio_X509(out, userSignCer)) { + printTSError(); + goto end; + } + + len = BIO_get_mem_data(out, &buf); + if (len <= 0) + goto end; + + this->ui->textBrowserSignOutput->setPlainText(QString::fromStdString(std::string(buf, len))); + + BIO_reset(out); + + if (!PEM_write_bio_X509(out, userEncryptCer)) { + printTSError(); + goto end; + } + + len = BIO_get_mem_data(out, &buf); + if (len <= 0) + goto end; + + this->ui->textBrowserEncryptOutput->setPlainText(QString::fromStdString(std::string(buf, len))); + +end: + EVP_PKEY_free(pkey); + X509_free(subca); + BIO_free(out); + free(signKey); + free(encKey); + X509_free(userSignCer); + X509_free(userEncryptCer); } diff --git a/sm2cert.h b/sm2cert.h index 1628fd5..7391376 100644 --- a/sm2cert.h +++ b/sm2cert.h @@ -31,12 +31,6 @@ private slots: 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 index b943e6f..45f537d 100644 --- a/sm2cert.ui +++ b/sm2cert.ui @@ -7,73 +7,58 @@ 0 0 400 - 300 + 314 Form - - + + - 12 + 10 - - 签名证书&密钥: - - - + + - 12 + 10 - - 365 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 12 - - - - - - - tongsuo - - - 一般为域名 + + + + 0 - + + + + + 12 + + + + + + + /C=AB/ST=CD/L=EF/O=GH/OU=IJ/CN=test + + + 一般为域名 + + + + - - + + 10 @@ -81,32 +66,29 @@ - - + + 12 - 生成证书 + 加密证书&私钥: - - + + - 12 + 10 - - 通用名称: - - - + + Qt::Vertical @@ -118,111 +100,80 @@ - - + + 12 - 私钥/请求: + 有效天数: - - + + 12 - 有效天数: + 签名证书&私钥: - - - - 0 + + + + Qt::Vertical - - - - - 12 - - - - 自动生成 - - - - - - - - 12 - - - - 手动生成 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 10 - + + + 20 + 40 + - + - - + + 12 - 加密证书&密钥: + 365 + + + - - + + - 10 + 12 + + 主体名称: + - - + + - 10 + 12 + + 生成证书 + diff --git a/sm2encrypt.cpp b/sm2encrypt.cpp index 3881bfd..2caa4cb 100644 --- a/sm2encrypt.cpp +++ b/sm2encrypt.cpp @@ -1,4 +1,5 @@ #include "sm2encrypt.h" +#include "sm2.h" #include "ui_sm2encrypt.h" Sm2Encrypt::Sm2Encrypt(QWidget *parent) @@ -15,94 +16,166 @@ Sm2Encrypt::~Sm2Encrypt() void Sm2Encrypt::on_pushButtonEncrypt_clicked() { - /* 选定椭圆曲线组 */ - std::shared_ptr group(EC_GROUP_new_by_curve_name(NID_sm2), EC_GROUP_free); - /* 密钥上下文生成 */ - std::shared_ptr eckey(EC_KEY_new(), EC_KEY_free); - /* 设定密钥的曲线组 */ - EC_KEY_set_group(eckey.get(), group.get()); - /* 获取用户输入的公钥 */ - QString pubQstrInput = this->ui->lineEditPub->text(); - /* 将16进制字符串公钥转为EC_POINT,并设置到EC_KEY */ - const EC_POINT *pubPoint - = EC_POINT_hex2point(group.get(), pubQstrInput.toStdString().c_str(), NULL, NULL); - EC_KEY_set_public_key(eckey.get(), pubPoint); - /* 将EC_KEY设置到EVP_PKEY */ - std::shared_ptr pKey(EVP_PKEY_new(), EVP_PKEY_free); - EVP_PKEY_set1_EC_KEY(pKey.get(), eckey.get()); - /* 生成加密上下文 */ - std::shared_ptr pkCtx(EVP_PKEY_CTX_new(pKey.get(), NULL), EVP_PKEY_CTX_free); - /* 加密初始化 */ - if (EVP_PKEY_encrypt_init(pkCtx.get()) <= 0) { - getError(); + QString input = this->ui->textEditPlain->toPlainText(); + QString pubQstrInput = this->ui->plainTextEditPub->toPlainText(); + EVP_PKEY_CTX *encctx = NULL; + EVP_PKEY *pkey = NULL; + size_t outlen; + std::vector buf; + std::vector str; + + if (pubQstrInput.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入公钥!"), + QMessageBox::Close, + QMessageBox::Close); return; } - /* 获取输入明文 */ - QString plainTextQstr = this->ui->plainTextEditInput->toPlainText(); - /* 获取加密密文长度 */ - size_t cipherTextLen = 0; - int res = EVP_PKEY_encrypt(pkCtx.get(), - NULL, - &cipherTextLen, - (const unsigned char *) plainTextQstr.toStdString().c_str(), - plainTextQstr.size()); - if (res != 1) { - getError(); + + if (input.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入明文!"), + QMessageBox::Close, + QMessageBox::Close); return; } - /* 加密生成密文 */ - std::shared_ptr cipherText(new unsigned char[cipherTextLen]); - res = EVP_PKEY_encrypt(pkCtx.get(), - cipherText.get(), - &cipherTextLen, - (const unsigned char *) plainTextQstr.toStdString().c_str(), - plainTextQstr.size()); - if (res != 1) { - getError(); - return; + + pkey = sm2_key_new_from_raw_pub(pubQstrInput.toStdString()); + if (pkey == NULL) { + printTSError(); + goto end; + } + + encctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + if (encctx == NULL) + goto end; + + if (EVP_PKEY_encrypt_init(encctx) <= 0 + || EVP_PKEY_encrypt(encctx, + NULL, + &outlen, + (const unsigned char *) input.toStdString().c_str(), + input.toStdString().length()) + <= 0) + goto end; + + buf.clear(); + buf.reserve(outlen); + + if (EVP_PKEY_encrypt(encctx, + buf.data(), + &outlen, + (const unsigned char *) input.toStdString().c_str(), + input.toStdString().length()) + <= 0) + goto end; + + str.reserve(outlen * 2 + 1); + if (OPENSSL_buf2hexstr_ex(str.data(), str.capacity(), NULL, buf.data(), outlen, '\0') != 1) { + printTSError(); + goto end; } - /* 以16进制字符串的形式显示在输出框 */ - std::shared_ptr outBuf(OPENSSL_buf2hexstr(cipherText.get(), cipherTextLen), - [](char *outbuf) { OPENSSL_free(outbuf); }); - this->ui->plainTextEditOutput->setPlainText(QString(outBuf.get())); + + this->ui->textEditCipher->setText(QString::fromStdString(std::string(str.data(), outlen * 2))); + +end: + EVP_PKEY_free(pkey); } void Sm2Encrypt::on_pushButtonDecrypt_clicked() { - /* 选定椭圆曲线组 */ - std::shared_ptr group(EC_GROUP_new_by_curve_name(NID_sm2), EC_GROUP_free); - /* 密钥上下文生成 */ - std::shared_ptr ecKey(EC_KEY_new(), EC_KEY_free); - /* 设定密钥的曲线组 */ - EC_KEY_set_group(ecKey.get(), group.get()); - /* 获取用户输入的私钥 */ - QString priQstrInput = this->ui->lineEditPri->text(); - /* 将16进制字符串私钥转为BIGNUM,并设置到EC_KEY */ - BIGNUM *priBn = BN_new(); - BN_hex2bn(&priBn, priQstrInput.toStdString().c_str()); - EC_KEY_set_private_key(ecKey.get(), priBn); - BN_free(priBn); - /* 将EC_KEY设置到EVP_PKEY */ - std::shared_ptr pKey(EVP_PKEY_new(), EVP_PKEY_free); - EVP_PKEY_set1_EC_KEY(pKey.get(), ecKey.get()); - /* 生成解密上下文 */ - std::shared_ptr pkCtx(EVP_PKEY_CTX_new(pKey.get(), NULL), EVP_PKEY_CTX_free); - /* 解密初始化 */ - if (EVP_PKEY_decrypt_init(pkCtx.get()) <= 0) { - getError(); + QString input = this->ui->textEditCipher->toPlainText(); + QString pubQstrInput = this->ui->plainTextEditPub->toPlainText(); + QString privQstrInput = this->ui->plainTextEditPriv->toPlainText(); + EVP_PKEY_CTX *encctx = NULL; + EVP_PKEY *pkey = NULL; + size_t outlen; + std::vector buf; + std::vector str; + + if (pubQstrInput.isEmpty() || privQstrInput.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入公钥和私钥!"), + QMessageBox::Close, + QMessageBox::Close); + return; + } + + if (input.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入密文!"), + QMessageBox::Close, + QMessageBox::Close); return; } - /* 获取输入密文 */ - QString cipherTextQstr = this->ui->plainTextEditInput->toPlainText(); - long inBufLen = 0; - const unsigned char *inBuf = OPENSSL_hexstr2buf(cipherTextQstr.toStdString().c_str(), &inBufLen); - /* 获取解密明文长度 */ - size_t plainTextLen = 0; - EVP_PKEY_decrypt(pkCtx.get(), NULL, &plainTextLen, inBuf, inBufLen); - /* 解密 生成明文 */ - std::shared_ptr plainText(new unsigned char[plainTextLen]); - EVP_PKEY_decrypt(pkCtx.get(), plainText.get(), &plainTextLen, inBuf, inBufLen); - /* 将明文内容显示到输出框 */ - std::string outStr((const char *) plainText.get(), plainTextLen); - this->ui->plainTextEditOutput->setPlainText(QString::fromStdString(outStr)); + + pkey = sm2_key_new_from_raw_pub_and_priv(pubQstrInput.toStdString(), + privQstrInput.toStdString()); + if (pkey == NULL) { + printTSError(); + goto end; + } + + encctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + if (encctx == NULL) + goto end; + + buf.clear(); + buf.reserve(input.length() / 2); + + if (OPENSSL_hexstr2buf_ex(buf.data(), buf.capacity(), NULL, input.toStdString().c_str(), '\0') + != 1) { + printTSError(); + goto end; + } + + if (EVP_PKEY_decrypt_init(encctx) <= 0 + || EVP_PKEY_decrypt(encctx, NULL, &outlen, buf.data(), buf.capacity()) <= 0) + goto end; + + str.clear(); + str.reserve(outlen); + + if (EVP_PKEY_decrypt(encctx, (unsigned char *) str.data(), &outlen, buf.data(), buf.capacity()) + <= 0) + goto end; + + this->ui->textEditPlain->setText(QString::fromStdString(std::string(str.data(), outlen))); + +end: + EVP_PKEY_free(pkey); +} + +void Sm2Encrypt::on_pushButtonGen_clicked() +{ + EVP_PKEY *pkey = NULL; + std::string hex; + + pkey = EVP_PKEY_Q_keygen(NULL, NULL, "SM2"); + if (pkey == NULL) { + printTSError(); + goto end; + } + + if (!sm2_key_get_pub_hex(pkey, hex)) { + printTSError(); + goto end; + } + + this->ui->plainTextEditPub->setPlainText(QString::fromStdString(hex)); + + if (!sm2_key_get_priv_hex(pkey, hex)) { + printTSError(); + goto end; + } + + this->ui->plainTextEditPriv->setPlainText(QString::fromStdString(hex)); + +end: + EVP_PKEY_free(pkey); + return; } diff --git a/sm2encrypt.h b/sm2encrypt.h index c36957b..b0da76a 100644 --- a/sm2encrypt.h +++ b/sm2encrypt.h @@ -3,9 +3,11 @@ #include "tserror.h" #include +#include #include #include #include +#include #include #include #include @@ -28,6 +30,8 @@ private slots: void on_pushButtonDecrypt_clicked(); + void on_pushButtonGen_clicked(); + private: Ui::Sm2Encrypt *ui; }; diff --git a/sm2encrypt.ui b/sm2encrypt.ui index 17dd21a..aa26ae4 100644 --- a/sm2encrypt.ui +++ b/sm2encrypt.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 300 + 436 + 412 @@ -15,148 +15,82 @@ - - - - - - 12 - - - - 公钥 + + + + + hex格式 - - - 12 - - 私钥 - - - - - 12 - - + + + + + - 04C370A09551DCC0321F0927A44B1A4D6ED5C39C06B336AA8FDE3389AAE830CC518C54BE3D1EAAAF45E8A34F41BCEA429EAD6B3271189B967CD248FF566F9F5161 + 密文 - - - - - 12 - - + + - 54519B9E1FD670D429B4D8EDE7A9A0322C5A6D3C3E9446903EFA5FE2C6B49EC2 + 明文 - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical + + + + hex格式 - - - 20 - 40 - - - + - - - - - - - - - 12 - - + + - 加密 + 公钥 - - - - 12 - + + + hex格式 + + + + - 解密 + 公钥加密 - - - - - 12 - - - - QPlainTextEdit::WidgetWidth + + + + 私钥解密 - - - - - 12 - - - - hello Tongsuo + + + + 生成密钥对 - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/sm2key.cpp b/sm2key.cpp index 885fafc..20c8c61 100644 --- a/sm2key.cpp +++ b/sm2key.cpp @@ -1,4 +1,5 @@ #include "sm2key.h" +#include "sm2.h" #include "ui_sm2key.h" Sm2Key::Sm2Key(QWidget *parent) @@ -15,33 +16,44 @@ Sm2Key::~Sm2Key() void Sm2Key::on_pushButtonGen_clicked() { - /* 选定椭圆曲线组 */ - std::shared_ptr group(EC_GROUP_new_by_curve_name(NID_sm2), EC_GROUP_free); - if (!group) { - getError(); - return; + EVP_PKEY *pkey = NULL; + std::string pem, hex; + + pkey = EVP_PKEY_Q_keygen(NULL, NULL, "SM2"); + if (pkey == NULL) { + printTSError(); + goto end; } - /* 密钥上下文生成 */ - std::shared_ptr key(EC_KEY_new(), EC_KEY_free); - /* 设定密钥的曲线组 */ - EC_KEY_set_group(key.get(), group.get()); - /* 生成EC_KEY */ - int res = EC_KEY_generate_key(key.get()); - if (res != 1) { - getError(); - return; + + if (!sm2_key_get_priv_pem(pkey, pem)) { + printTSError(); + goto end; } - /* 取公钥并转换为十六进制字符串 */ - const EC_POINT *pubPoint = EC_KEY_get0_public_key(key.get()); - std::shared_ptr pubHexStr(EC_POINT_point2hex(group.get(), - pubPoint, - POINT_CONVERSION_UNCOMPRESSED, - NULL), - [](char *pub) { OPENSSL_free(pub); }); - /* 取私钥并转换为十六进制字符串 */ - const BIGNUM *priBn = EC_KEY_get0_private_key(key.get()); - std::shared_ptr priHexStr(BN_bn2hex(priBn), [](char *pri) { OPENSSL_free(pri); }); - /* 在浏览框中显示公钥和私钥 */ - this->ui->textBrowserPrikey->setText(QString(priHexStr.get())); - this->ui->textBrowserPubkey->setText(QString(pubHexStr.get())); + + this->ui->textBrowserPrivPem->setText(QString::fromStdString(pem)); + + if (!sm2_key_get_pub_pem(pkey, pem)) { + printTSError(); + goto end; + } + + this->ui->textBrowserPubPem->setText(QString::fromStdString(pem)); + + if (!sm2_key_get_pub_hex(pkey, hex)) { + printTSError(); + goto end; + } + + this->ui->textBrowserPubkey->setText(QString::fromStdString(hex)); + + if (!sm2_key_get_priv_hex(pkey, hex)) { + printTSError(); + goto end; + } + + this->ui->textBrowserPrivkey->setText(QString::fromStdString(hex)); + +end: + EVP_PKEY_free(pkey); + return; } diff --git a/sm2key.h b/sm2key.h index c7d4509..35ec84e 100644 --- a/sm2key.h +++ b/sm2key.h @@ -1,11 +1,14 @@ #ifndef SM2KEY_H #define SM2KEY_H -#include "openssl/ec.h" #include "tserror.h" #include +#include +#include #include #include +#include +#include #include #include #include diff --git a/sm2key.ui b/sm2key.ui index 468a21a..968d6e0 100644 --- a/sm2key.ui +++ b/sm2key.ui @@ -6,8 +6,8 @@ 0 0 - 414 - 312 + 573 + 503 @@ -15,203 +15,56 @@ - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - + + + - - - - - 微软雅黑 - 14 - - - - 生成 - - + + - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - + - - - 16 - - - 私钥: + SM2私钥(PEM) - - - - true - - - - 0 - 0 - - - - - 0 - 4 - - - - - 200 - 200 - - - - - 12 - + + + + SM2私钥 - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - + - - - 16 - - - 公钥: + SM2公钥(x||y) - - - - - 0 - 0 - + + + + 生成密钥对 - - - 12 - + + + + + + + + + SM2公钥(PEM) + + + - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/sm2signverify.cpp b/sm2signverify.cpp index 03f31ea..e637a7d 100644 --- a/sm2signverify.cpp +++ b/sm2signverify.cpp @@ -1,4 +1,5 @@ #include "sm2signverify.h" +#include "sm2.h" #include "ui_sm2signverify.h" Sm2SignVerify::Sm2SignVerify(QWidget *parent) @@ -15,155 +16,176 @@ Sm2SignVerify::~Sm2SignVerify() void Sm2SignVerify::on_pushButtonGenKey_clicked() { - /* 选定椭圆曲线组 */ - std::shared_ptr group(EC_GROUP_new_by_curve_name(NID_sm2), EC_GROUP_free); - if (!group) { - getError(); - return; + EVP_PKEY *pkey = NULL; + std::string hex; + + pkey = EVP_PKEY_Q_keygen(NULL, NULL, "SM2"); + if (pkey == NULL) { + printTSError(); + goto end; } - /* 密钥上下文生成 */ - std::shared_ptr key(EC_KEY_new(), EC_KEY_free); - /* 设定密钥的曲线组 */ - EC_KEY_set_group(key.get(), group.get()); - /* 生成EC_KEY */ - int res = EC_KEY_generate_key(key.get()); - if (res != 1) { - getError(); - return; + + if (!sm2_key_get_pub_hex(pkey, hex)) { + printTSError(); + goto end; + } + + this->ui->plainTextEditPubKey->setPlainText(QString::fromStdString(hex)); + + if (!sm2_key_get_priv_hex(pkey, hex)) { + printTSError(); + goto end; } - /* 取公钥并转换为十六进制字符串 */ - const EC_POINT *pubPoint = EC_KEY_get0_public_key(key.get()); - std::shared_ptr pubHexStr(EC_POINT_point2hex(group.get(), - pubPoint, - POINT_CONVERSION_UNCOMPRESSED, - NULL), - [](char *pub) { OPENSSL_free(pub); }); - /* 取私钥并转换为十六进制字符串 */ - const BIGNUM *priBn = EC_KEY_get0_private_key(key.get()); - std::shared_ptr priHexStr(BN_bn2hex(priBn), [](char *pri) { OPENSSL_free(pri); }); - /* 在浏览框中显示公钥和私钥 */ - this->ui->lineEditPriKey->setText(QString(priHexStr.get())); - this->ui->plainTextEditPubKey->setPlainText(QString(pubHexStr.get())); + + this->ui->lineEditPriKey->setText(QString::fromStdString(hex)); + +end: + EVP_PKEY_free(pkey); + return; } void Sm2SignVerify::on_pushButtonSign_clicked() { /* 获取私钥 */ + QString pubQstr = this->ui->plainTextEditPubKey->toPlainText(); QString priQstr = this->ui->lineEditPriKey->text(); + QString inputQstr = this->ui->textEditData->toPlainText(); + EVP_PKEY *pkey = NULL; + EVP_MD_CTX *mctx = NULL; + size_t siglen = 0; + std::vector sig; + std::vector str; + if (priQstr.isEmpty()) { QMessageBox::warning(NULL, "warning", - QString("请输入或者生成私钥!"), + QString("请输入或生成私钥!"), QMessageBox::Close, QMessageBox::Close); return; } - /* 获取待签名数据 */ - QString inputQstr = this->ui->lineEditInput->text(); + if (inputQstr.isEmpty()) { QMessageBox::warning(NULL, "warning", - QString("请输入待签数据!"), + QString("请输入待签名数据!"), QMessageBox::Close, QMessageBox::Close); return; } - /* 选定椭圆曲线组 */ - std::shared_ptr group(EC_GROUP_new_by_curve_name(NID_sm2), EC_GROUP_free); - /* EC密钥生成 */ - std::shared_ptr ecKey(EC_KEY_new(), EC_KEY_free); - /* 设定密钥的曲线组 */ - EC_KEY_set_group(ecKey.get(), group.get()); - /* 将16进制字符串私钥转为BIGNUM,并设置到EC_KEY */ - BIGNUM *priBn = BN_new(); - BN_hex2bn(&priBn, priQstr.toStdString().c_str()); - EC_KEY_set_private_key(ecKey.get(), priBn); - BN_free(priBn); - /* 将16进制字符串公钥转为ECPOINT,并设置到EC_KEY */ - QString pubQstrInput = this->ui->plainTextEditPubKey->toPlainText(); - const EC_POINT *pubPoint - = EC_POINT_hex2point(group.get(), pubQstrInput.toStdString().c_str(), NULL, NULL); - EC_KEY_set_public_key(ecKey.get(), pubPoint); - /* 将EC_KEY设置到EVP_PKEY */ - std::shared_ptr pKey(EVP_PKEY_new(), EVP_PKEY_free); - EVP_PKEY_set1_EC_KEY(pKey.get(), ecKey.get()); - /* 签名上下文及初始化 */ - size_t siglen = 0; - std::shared_ptr mctx(EVP_MD_CTX_new(), EVP_MD_CTX_free); - if (!EVP_DigestSignInit(mctx.get(), NULL, EVP_sm3(), NULL, pKey.get()) - || !EVP_DigestSign(mctx.get(), + pkey = sm2_key_new_from_raw_pub_and_priv(pubQstr.toStdString(), priQstr.toStdString()); + if (pkey == NULL) { + printTSError(); + return; + } + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto end; + + if (!EVP_DigestSignInit(mctx, NULL, EVP_sm3(), NULL, pkey) + || !EVP_DigestSign(mctx, NULL, &siglen, (unsigned char *) inputQstr.toStdString().c_str(), inputQstr.size())) { - getError(); - return; + printTSError(); + goto end; } - /* 签名 */ - std::shared_ptr sig((unsigned char *) OPENSSL_malloc(siglen), - [](unsigned char *buf) { OPENSSL_free(buf); }); - int ret = EVP_DigestSign(mctx.get(), - sig.get(), - &siglen, - (unsigned char *) inputQstr.toStdString().c_str(), - inputQstr.size()); - if (ret != 1) { - getError(); - return; + + sig.reserve(siglen); + + if (EVP_DigestSign(mctx, + sig.data(), + &siglen, + (unsigned char *) inputQstr.toStdString().c_str(), + inputQstr.size()) + != 1) { + printTSError(); + goto end; } - /* 显示十六进制字符串到输出框 */ - std::shared_ptr out(OPENSSL_buf2hexstr(sig.get(), siglen), - [](char *buf) { OPENSSL_free(buf); }); - this->ui->plainTextEditOutput->setPlainText(QString(out.get())); + + str.reserve(siglen * 2 + 1); + + if (OPENSSL_buf2hexstr_ex(str.data(), str.capacity(), NULL, sig.data(), siglen, '\0') != 1) { + printTSError(); + goto end; + } + + this->ui->plainTextEditSign->setPlainText( + QString::fromStdString(std::string(str.data(), str.capacity()))); +end: + EVP_MD_CTX_free(mctx); + EVP_PKEY_free(pkey); + return; } void Sm2SignVerify::on_pushButtonVerify_clicked() { - /* 获取原文 */ - QString inputQstr = this->ui->lineEditInput->text(); - /* 获取签名 */ - QString signQstr = this->ui->plainTextEditOutput->toPlainText(); - long siglen = signQstr.size(); - const unsigned char *sig = OPENSSL_hexstr2buf(signQstr.toStdString().c_str(), &siglen); - /* 选定椭圆曲线组 */ - std::shared_ptr group(EC_GROUP_new_by_curve_name(NID_sm2), EC_GROUP_free); - /* 密钥上下文生成 */ - std::shared_ptr eckey(EC_KEY_new(), EC_KEY_free); - /* 设定密钥的曲线组 */ - EC_KEY_set_group(eckey.get(), group.get()); - /* 获取用户输入的公钥 */ QString pubQstrInput = this->ui->plainTextEditPubKey->toPlainText(); - /* 将16进制字符串公钥转为EC_POINT,并设置到EC_KEY */ - const EC_POINT *pubPoint - = EC_POINT_hex2point(group.get(), pubQstrInput.toStdString().c_str(), NULL, NULL); - EC_KEY_set_public_key(eckey.get(), pubPoint); - /* 将EC_KEY设置到EVP_PKEY */ - std::shared_ptr pKey(EVP_PKEY_new(), EVP_PKEY_free); - EVP_PKEY_set1_EC_KEY(pKey.get(), eckey.get()); - /* 验签上下文及初始化 */ - std::shared_ptr mctx(EVP_MD_CTX_new(), EVP_MD_CTX_free); - if (!EVP_DigestVerifyInit(mctx.get(), NULL, EVP_sm3(), NULL, pKey.get())) { - getError(); + QString inputQstr = this->ui->textEditData->toPlainText(); + QString signQstr = this->ui->plainTextEditSign->toPlainText(); + std::vector sig; + EVP_PKEY *pkey = NULL; + EVP_MD_CTX *mctx = NULL; + int ret; + + if (pubQstrInput.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入公钥!"), + QMessageBox::Close, + QMessageBox::Close); return; } - /* 验签 */ - int ret = EVP_DigestVerify(mctx.get(), - sig, - siglen, - (unsigned char *) inputQstr.toStdString().c_str(), - inputQstr.size()); - if (ret == 1) { - /* 验签成功 */ + + if (signQstr.isEmpty()) { QMessageBox::warning(NULL, "warning", - QString("验签成功!"), + QString("请输入签名!"), QMessageBox::Close, QMessageBox::Close); + return; + } + + sig.reserve(signQstr.size() / 2); + + if (OPENSSL_hexstr2buf_ex(sig.data(), sig.capacity(), NULL, signQstr.toStdString().c_str(), '\0') + != 1) { + printTSError(); + goto end; + } + + pkey = sm2_key_new_from_raw_pub(pubQstrInput.toStdString()); + if (pkey == NULL) { + printTSError(); + goto end; + } + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto end; + + if (!EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey)) { + printTSError(); + goto end; + } + /* 验签 */ + ret = EVP_DigestVerify(mctx, + sig.data(), + sig.capacity(), + (unsigned char *) inputQstr.toStdString().c_str(), + inputQstr.size()); + if (ret == 1) { + QMessageBox::information(NULL, + "success", + QString("验签成功!"), + QMessageBox::Close, + QMessageBox::Close); } else if (ret == 0) { - /* 验签失败 */ QMessageBox::warning(NULL, - "warning", + "failed", QString("验签失败!"), QMessageBox::Close, QMessageBox::Close); @@ -171,4 +193,8 @@ void Sm2SignVerify::on_pushButtonVerify_clicked() getError(); return; } +end: + EVP_MD_CTX_free(mctx); + EVP_PKEY_free(pkey); + return; } diff --git a/sm2signverify.ui b/sm2signverify.ui index 0f711f8..1f812e4 100644 --- a/sm2signverify.ui +++ b/sm2signverify.ui @@ -7,148 +7,134 @@ 0 0 390 - 302 + 318 Form - - - - - - 12 - - - - 公钥: - - - - - - - - 12 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 12 - - - - 验证签名 - - - - - - - - 12 - - - - 私钥: - - - - - - - - 12 - - - - 生成签名 - - - - - - - - 12 - - - - 签名: - - - - - - - - 12 - - - - hello Tongsuo - - - - - - - - 12 - - - - - - - - - 12 - - - - 待签/待验数据: - - - - - - - - 12 - - - - - - - - - 12 - - - - 生成密钥对 - - + + + + + + + + 12 + + + + 待签名/验签数据: + + + + + + + + 12 + + + + 生成密钥对 + + + + + + + + 12 + + + + 私钥: + + + + + + + + 12 + + + + hex格式 + + + + + + + + 12 + + + + 公钥: + + + + + + + + 12 + + + + hex格式 + + + + + + + + 12 + + + + 签名: + + + + + + + + 12 + + + + 生成签名 + + + + + + + + 12 + + + + 验证签名 + + + + + + + + + + hex格式 + + + + diff --git a/sm3hash.cpp b/sm3hash.cpp index 9f9255e..cef2f7b 100644 --- a/sm3hash.cpp +++ b/sm3hash.cpp @@ -15,18 +15,32 @@ Sm3Hash::~Sm3Hash() void Sm3Hash::on_pushButtonGen_clicked() { - /* 获取用户输入 */ QString input = this->ui->plainTextEditInput->toPlainText(); - /* 进行哈希生成摘要 */ unsigned char md[32] = {}; + unsigned char hex[65]; size_t mdlen = 0; + + if (input.isEmpty()) { + if (input.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入数据!"), + QMessageBox::Close, + QMessageBox::Close); + return; + } + } + if (!EVP_Q_digest(NULL, "SM3", NULL, input.toStdString().c_str(), input.size(), md, &mdlen)) { - /* 错误处理 */ - getError(); + printTSError(); return; } - /* 转为16进制字符串并输出 */ - std::shared_ptr output(OPENSSL_buf2hexstr(md, mdlen), - [](char *buf) { OPENSSL_free(buf); }); - this->ui->textBrowserOutput->setText(QString(output.get())); + + if (OPENSSL_buf2hexstr_ex((char *) hex, sizeof(hex), NULL, md, mdlen, '\0') != 1) { + printTSError(); + return; + } + + this->ui->textBrowserOutput->setText( + QString::fromStdString(std::string((char *) hex, sizeof(hex)))); } diff --git a/sm3hash.ui b/sm3hash.ui index a308cd1..2c538bc 100644 --- a/sm3hash.ui +++ b/sm3hash.ui @@ -14,19 +14,6 @@ Form - - - - Qt::Vertical - - - - 40 - 160 - - - - @@ -37,7 +24,7 @@ - 哈希内容: + 输入内容: @@ -48,6 +35,9 @@ 12 + + hex格式 + @@ -70,7 +60,7 @@ - 哈希结果: + 杂凑结果: @@ -88,19 +78,6 @@ - - - - Qt::Vertical - - - - 40 - 200 - - - - diff --git a/sm4encrypt.cpp b/sm4encrypt.cpp index 71eb9e8..52da545 100644 --- a/sm4encrypt.cpp +++ b/sm4encrypt.cpp @@ -1,5 +1,6 @@ #include "sm4encrypt.h" #include "ui_sm4encrypt.h" +#include Sm4encrypt::Sm4encrypt(QWidget *parent) : QWidget(parent) @@ -13,129 +14,235 @@ Sm4encrypt::~Sm4encrypt() delete ui; } -void Sm4encrypt::on_pushButtonGen_clicked() +static int do_sm4_crypt(const char *algo, + int enc, + const unsigned char *key, + const unsigned char *iv, + const unsigned char *input, + size_t inlen, + unsigned char *output, + size_t *outlen) { - /* 获取密钥 */ + int ret = 0; + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *cipher = NULL; + int len, lenf; + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) + goto end; + + cipher = EVP_CIPHER_fetch(NULL, algo, NULL); + if (cipher == NULL) + goto end; + + if (!EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc)) + goto end; + + if (!EVP_CipherUpdate(ctx, output, &len, input, inlen)) + goto end; + + if (!EVP_CipherFinal_ex(ctx, output + len, &lenf)) + goto end; + + *outlen = len + lenf; + ret = 1; +end: + EVP_CIPHER_CTX_free(ctx); + return ret; +} + +void Sm4encrypt::on_pushButtonEncrypt_clicked() +{ + QString algo = this->ui->comboBoxMode->currentText(); QString keyQstr = this->ui->lineEditKey->text(); - long keyLen = keyQstr.size(); - std::shared_ptr key(OPENSSL_hexstr2buf(keyQstr.toStdString().c_str(), &keyLen), - [](unsigned char *buf) { OPENSSL_free(buf); }); - /* 获取加密内容 */ - QString inputQstr = this->ui->plainTextEditInput->toPlainText(); - /* 生成加密上下文 */ - std::shared_ptr sm4Ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); - if (sm4Ctx == NULL) { - /* 错误处理 */ - getError(); - return; - } - /* 选定模式初始化加密 */ - int modeIndex = this->ui->comboBoxMode->currentIndex(); - if (modeIndex == 0) { - /* CBC模式 */ - QString ivQstr = this->ui->lineEditCBCIV->text(); - long ivlen = ivQstr.size(); - std::shared_ptr iv(OPENSSL_hexstr2buf(ivQstr.toStdString().c_str(), &ivlen), - [](unsigned char *buf) { OPENSSL_free(buf); }); - if (!EVP_EncryptInit(sm4Ctx.get(), EVP_sm4_cbc(), key.get(), iv.get())) { - /* 错误处理 */ - getError(); - return; - } - } else if (modeIndex == 1) { - /* ECB模式 */ - if (!EVP_EncryptInit(sm4Ctx.get(), EVP_sm4_ecb(), key.get(), NULL)) { - /* 错误处理 */ - getError(); - return; - } - } else { - getError(); + QString ivQstr = this->ui->lineEditIV->text(); + QString inputQstr = this->ui->plainTextEditPlain->toPlainText(); + std::vector key, iv, outbuf; + std::vector outhex; + size_t outlen; + + if (keyQstr.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入密钥!"), + QMessageBox::Close, + QMessageBox::Close); return; } - /* 加密 */ - int outputLen = 0, tmpLen = 0; - std::shared_ptr output( - new unsigned char[inputQstr.size() + EVP_MAX_BLOCK_LENGTH]); - if (!EVP_EncryptUpdate(sm4Ctx.get(), - output.get(), - &outputLen, - (unsigned char *) inputQstr.toStdString().c_str(), - inputQstr.size())) { - /* 错误处理 */ - getError(); + if (algo != "SM4-ECB" && ivQstr.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入初始化向量IV!"), + QMessageBox::Close, + QMessageBox::Close); return; } - if (!EVP_EncryptFinal(sm4Ctx.get(), output.get() + outputLen, &tmpLen)) { - /* 错误处理 */ - getError(); + + key.reserve(keyQstr.size() / 2); + + if (OPENSSL_hexstr2buf_ex(key.data(), key.capacity(), NULL, keyQstr.toStdString().c_str(), '\0') + != 1) { + printTSError(); return; } - /* 将加密结果以16进制显示到输出栏 */ - std::shared_ptr outHex(OPENSSL_buf2hexstr(output.get(), outputLen + tmpLen), - [](char *buf) { OPENSSL_free(buf); }); - this->ui->textBrowserOutput->setText(QString(outHex.get())); + + iv.reserve(ivQstr.size() / 2); + + if (OPENSSL_hexstr2buf_ex(iv.data(), iv.capacity(), NULL, ivQstr.toStdString().c_str(), '\0') + != 1) { + printTSError(); + return; + } + + outbuf.reserve(inputQstr.size() + 16); + + if (do_sm4_crypt(algo.toStdString().c_str(), + 1, + key.data(), + iv.data(), + (const unsigned char *) inputQstr.toStdString().c_str(), + inputQstr.size(), + outbuf.data(), + &outlen) + != 1) { + printTSError(); + return; + } + + outhex.reserve(outlen * 2 + 1); + + if (OPENSSL_buf2hexstr_ex(outhex.data(), outhex.capacity(), NULL, outbuf.data(), outlen, '\0') + != 1) { + printTSError(); + return; + } + + this->ui->plainTextEditCipher->setPlainText(QString(outhex.data())); } void Sm4encrypt::on_pushButtonDecrypt_clicked() { - /* 获取密钥 */ + QString algo = this->ui->comboBoxMode->currentText(); QString keyQstr = this->ui->lineEditKey->text(); - long keyLen = keyQstr.size(); - std::shared_ptr key(OPENSSL_hexstr2buf(keyQstr.toStdString().c_str(), &keyLen), - [](unsigned char *buf) { OPENSSL_free(buf); }); - /* 获取解密内容 */ - QString inputQstr = this->ui->plainTextEditInput->toPlainText(); - long inputlen = inputQstr.size(); - std::shared_ptr input(OPENSSL_hexstr2buf(inputQstr.toStdString().c_str(), - &inputlen), - [](unsigned char *buf) { OPENSSL_free(buf); }); - /* 生成解密上下文 */ - std::shared_ptr sm4Ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); - if (sm4Ctx == NULL) { - /* 错误处理 */ - getError(); - return; - } - /* 选定模式初始化解密 */ - int modeIndex = this->ui->comboBoxMode->currentIndex(); - if (modeIndex == 0) { - /* CBC模式 */ - QString ivQstr = this->ui->lineEditCBCIV->text(); - long ivlen = ivQstr.size(); - std::shared_ptr iv(OPENSSL_hexstr2buf(ivQstr.toStdString().c_str(), &ivlen), - [](unsigned char *buf) { OPENSSL_free(buf); }); - if (!EVP_DecryptInit(sm4Ctx.get(), EVP_sm4_cbc(), key.get(), iv.get())) { - /* 错误处理 */ - getError(); - return; - } - } else if (modeIndex == 1) { - /* ECB模式 */ - if (!EVP_DecryptInit(sm4Ctx.get(), EVP_sm4_ecb(), key.get(), NULL)) { - /* 错误处理 */ - getError(); - return; - } - } else { - getError(); + QString ivQstr = this->ui->lineEditIV->text(); + QString inputQstr = this->ui->plainTextEditCipher->toPlainText(); + std::vector key, iv, input; + std::vector outbuf; + size_t outlen; + + if (keyQstr.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入密钥!"), + QMessageBox::Close, + QMessageBox::Close); + return; + } + + if (algo != "SM4-ECB" && ivQstr.isEmpty()) { + QMessageBox::warning(NULL, + "warning", + QString("请输入初始化向量IV!"), + QMessageBox::Close, + QMessageBox::Close); + return; + } + + key.reserve(keyQstr.size() / 2); + + if (OPENSSL_hexstr2buf_ex(key.data(), key.capacity(), NULL, keyQstr.toStdString().c_str(), '\0') + != 1) { + printTSError(); return; } - /* 解密 */ - int outputLen = 0, tmpLen = 0; - std::shared_ptr output(new unsigned char[inputlen]); - if (!EVP_DecryptUpdate(sm4Ctx.get(), output.get(), &outputLen, input.get(), inputlen)) { - /* 错误处理 */ - getError(); + + iv.reserve(ivQstr.size() / 2); + + if (OPENSSL_hexstr2buf_ex(iv.data(), iv.capacity(), NULL, ivQstr.toStdString().c_str(), '\0') + != 1) { + printTSError(); + return; + } + + input.reserve(inputQstr.size() / 2); + if (OPENSSL_hexstr2buf_ex(input.data(), + input.capacity(), + NULL, + inputQstr.toStdString().c_str(), + '\0') + != 1) { + printTSError(); + return; + } + + outbuf.reserve(input.capacity()); + + if (do_sm4_crypt(algo.toStdString().c_str(), + 0, + key.data(), + iv.data(), + input.data(), + input.capacity(), + (unsigned char *) outbuf.data(), + &outlen) + != 1) { + printTSError(); return; } - if (!EVP_DecryptFinal(sm4Ctx.get(), output.get() + outputLen, &tmpLen)) { - /* 错误处理 */ - getError(); + + this->ui->plainTextEditPlain->setPlainText( + QString::fromStdString(std::string(outbuf.data(), outlen))); +} + +void Sm4encrypt::on_pushButtonRandomIV_clicked() +{ + unsigned char buf[16]; + std::vector hex; + + if (RAND_bytes(buf, sizeof(buf)) != 1) { + printTSError(); + return; + } + + hex.reserve(sizeof(buf) * 2 + 1); + + if (OPENSSL_buf2hexstr_ex(hex.data(), hex.capacity(), NULL, buf, sizeof(buf), '\0') != 1) { + printTSError(); return; } - /* 将解密结果显示到输出栏 */ - this->ui->textBrowserOutput->setText( - QString::asprintf("%.*s", outputLen + tmpLen, output.get())); + + this->ui->lineEditIV->setText(hex.data()); +} + +void Sm4encrypt::on_pushButtonRandomKey_clicked() +{ + unsigned char buf[16]; + std::vector hex; + + if (RAND_bytes(buf, sizeof(buf)) != 1) { + printTSError(); + return; + } + + hex.reserve(sizeof(buf) * 2 + 1); + + if (OPENSSL_buf2hexstr_ex(hex.data(), hex.capacity(), NULL, buf, sizeof(buf), '\0') != 1) { + printTSError(); + return; + } + + this->ui->lineEditKey->setText(hex.data()); +} + +void Sm4encrypt::on_comboBoxMode_currentTextChanged(const QString &arg1) +{ + if (arg1 == "SM4-ECB") { + this->ui->lineEditIV->setEnabled(false); + this->ui->lineEditIV->hide(); + } else { + this->ui->lineEditIV->setEnabled(true); + this->ui->lineEditIV->show(); + } } diff --git a/sm4encrypt.h b/sm4encrypt.h index 1faa441..bfd6777 100644 --- a/sm4encrypt.h +++ b/sm4encrypt.h @@ -18,10 +18,16 @@ class Sm4encrypt : public QWidget ~Sm4encrypt(); private slots: - void on_pushButtonGen_clicked(); + void on_pushButtonEncrypt_clicked(); void on_pushButtonDecrypt_clicked(); + void on_pushButtonRandomIV_clicked(); + + void on_pushButtonRandomKey_clicked(); + + void on_comboBoxMode_currentTextChanged(const QString &arg1); + private: Ui::Sm4encrypt *ui; }; diff --git a/sm4encrypt.ui b/sm4encrypt.ui index 198bd79..d5e7724 100644 --- a/sm4encrypt.ui +++ b/sm4encrypt.ui @@ -14,91 +14,41 @@ Form - - - - - - - 12 - - - - - CBC - - - - - EBC - - - - - - - - 0 - - - - - - - - 12 - - - - 初始IV: - - - - - - - - 12 - - - - 1F:B2:D4:2F:B3:6E:2E:88:A2:20:B0:4F:2E:49:AA:13 - - - - - - - - - - - - + + 12 - - 加密/解密结果: - + + + SM4-CBC + + + + + SM4-ECB + + + + + SM4-CFB + + + + + SM4-OFB + + + + + SM4-CTR + + - - - - Qt::Vertical - - - - 20 - 40 - - - - - + @@ -106,12 +56,12 @@ - 加密/解密内容: + 明文: - - + + 12 @@ -122,66 +72,59 @@ - - - - Qt::Vertical + + + + + 12 + - - - 20 - 40 - + + 加密模式: - + - - + + 12 - 3F:34:2E:9D:67:D6:CE:7B:E7:01:75:6A:F7:BA:C8:F2 + + + + hex格式 - - + + 12 + + 初始化向量: + - - + + 12 - 密钥: + 密文: - + - - - - - 12 - - - - 加密 - - - @@ -196,37 +139,84 @@ - - + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + 12 - 加密模式: + 密钥: + + + + + + + + 12 + + + + + + + hex格式 + + + + + + + + 12 + + + + 加密 + + + + + + + hex格式 + + + + + + + 随机 + + + + + + + 随机 - - - comboBoxMode - currentIndexChanged(int) - stackedWidget - setCurrentIndex(int) - - - 112 - 178 - - - 169 - 189 - - - - + diff --git a/tlcpclient.cpp b/tlcpclient.cpp index 0636e91..a127aed 100644 --- a/tlcpclient.cpp +++ b/tlcpclient.cpp @@ -1,6 +1,6 @@ #include "tlcpclient.h" #include "ui_tlcpclient.h" -static SSL *ssl; + TLCPclient::TLCPclient(QWidget *parent) : QWidget(parent) , ui(new Ui::TLCPclient) @@ -12,53 +12,84 @@ TLCPclient::TLCPclient(QWidget *parent) TLCPclient::~TLCPclient() { delete ui; + SSL_free(ssl); + ssl = NULL; + SSL_CTX_free(ctx); + ctx = NULL; + socket.close(); } void TLCPclient::on_pushButtonConnect_clicked() { + int ret, err; + if (ui->pushButtonConnect->text() == "连接服务器") { - //载入SSL相关信息 - SSL_library_init(); - SSL_load_error_strings(); - OpenSSL_add_all_algorithms(); //获取域名端口 QString addrQstr = this->ui->lineEditAddr->text(); QString portQstr = this->ui->lineEditPort->text(); + QString cipherList = this->ui->lineEditCiphers->text(); // 创建一个 QSslSocket对象设置地址并连接 - QTcpSocket socket; - socket.connectToHost(addrQstr, portQstr.toInt()); - if (!socket.waitForConnected()) { + + this->socket.reset(); + this->socket.connectToHost(addrQstr, portQstr.toInt()); + if (!this->socket.waitForConnected()) { QMessageBox::warning(NULL, "connect failed", - QString("TCP connection to server failed"), + QString("TCP连接失败,请确认服务器地址&端口号是否正确"), QMessageBox::Ok, QMessageBox::Ok); + return; } //TCP已连接,准备SSL连接 - const SSL_METHOD *method = NTLS_client_method(); - std::shared_ptr ssl_ctx(SSL_CTX_new(method), SSL_CTX_free); - SSL_CTX_enable_ntls(ssl_ctx.get()); - SSL_CTX_set_verify(ssl_ctx.get(), SSL_VERIFY_NONE, NULL); - ssl = SSL_new(ssl_ctx.get()); - SSL_set_fd(ssl, socket.socketDescriptor()); - if (SSL_connect(ssl) == 1) { + if (this->ctx == NULL) { + this->ctx = SSL_CTX_new(NTLS_client_method()); + if (this->ctx == NULL) { + return; + } + + SSL_CTX_enable_ntls(this->ctx); + SSL_CTX_set_verify(this->ctx, SSL_VERIFY_NONE, NULL); + } + + if (SSL_CTX_set_cipher_list(this->ctx, cipherList.toStdString().c_str()) != 1) { + QMessageBox::warning(NULL, + "set cipher list failed", + QString("设置密码套件失败,请确认套件格式是否正确"), + QMessageBox::Ok, + QMessageBox::Ok); + return; + } + + SSL_free(this->ssl); + this->ssl = SSL_new(this->ctx); + SSL_set_fd(ssl, this->socket.socketDescriptor()); + + if (BIO_socket_nbio(this->socket.socketDescriptor(), 0) != 1) { + QMessageBox::warning(NULL, + "set blocking failed", + QString("设置阻塞模式失败"), + QMessageBox::Ok, + QMessageBox::Ok); + return; + } + + ret = SSL_connect(this->ssl); + if (ret == 1) { //SSL连接成功 ui->pushButtonConnect->setText("断开服务器"); - QMessageBox::information(NULL, - "connect success", - QString("TLCP connection to server successful"), - QMessageBox::Ok, - QMessageBox::Ok); + + this->ui->textBrowserDebug->append(QString("TLCP握手成功\n")); ui->pushButtonSend->setEnabled(true); } else { + err = SSL_get_error(this->ssl, ret); + //SSL连接失败 - SSL_shutdown(ssl); - SSL_free(ssl); + SSL_shutdown(this->ssl); QMessageBox::warning(NULL, "connect failed", - QString("SSL connection to server failed"), + QString("TLCP连接失败,err:%1").arg(err), QMessageBox::Ok, QMessageBox::Ok); return; @@ -66,42 +97,61 @@ void TLCPclient::on_pushButtonConnect_clicked() } else { ui->pushButtonConnect->setText("连接服务器"); ui->pushButtonSend->setEnabled(false); - if (ssl != NULL) { - SSL_shutdown(ssl); - SSL_free(ssl); + if (this->ssl != NULL) { + SSL_shutdown(this->ssl); } - QMessageBox::information(NULL, - "connect closed", - QString("client closed connection"), - QMessageBox::Ok, - QMessageBox::Ok); + + this->ui->textBrowserDebug->append(QString("客户端关闭连接\n")); } } void TLCPclient::on_pushButtonSend_clicked() { - SSL_set_msg_callback(ssl, trace_cb); + // SSL_set_msg_callback(ssl, trace_cb); //获取发送内容 QString inputQstr = this->ui->plainTextEditInput->toPlainText(); - int ret = SSL_write(ssl, inputQstr.toStdString().c_str(), inputQstr.size()); + int ret = SSL_write(this->ssl, inputQstr.toStdString().c_str(), inputQstr.size()); if (ret < 0) { - //发送失败 - getError(); - return; - } - SSL_set_connect_state(ssl); - char rxbuf[256] = {0}; - int rxlen = SSL_read(ssl, rxbuf, 256); - if (rxlen < 0) { - int err = SSL_get_error(ssl, rxlen); - while (err == 2) { - rxlen = SSL_read(ssl, rxbuf, 256); - err = SSL_get_error(ssl, rxlen); + int err = SSL_get_error(this->ssl, ret); + + if (err == SSL_ERROR_SYSCALL && !socket.isOpen()) { + QMessageBox::warning(NULL, + "write failed", + QString("TLCP发送数据失败,服务端已经关闭连接"), + QMessageBox::Ok, + QMessageBox::Ok); + return; + } else { + QMessageBox::warning(NULL, + "write failed", + QString("TLCP发送数据失败,err:%1").arg(err), + QMessageBox::Ok, + QMessageBox::Ok); + //发送失败 + // getError(); + return; } - getError(); } else { - //输出到反馈栏 + this->ui->textBrowserDebug->append(QString(">>>:\n") + inputQstr + QString("\n")); + } + + char rxbuf[16384] = {0}; + ret = SSL_read(this->ssl, rxbuf, sizeof(rxbuf)); + if (ret < 0) { + int err = SSL_get_error(this->ssl, ret); + + QMessageBox::warning(NULL, + "read failed", + QString("读失败,err:%1").arg(err), + QMessageBox::Ok, + QMessageBox::Ok); + return; + } else { + // 输出到接收 this->ui->textBrowserOutput->setText(QString::asprintf("%s", rxbuf)); + + this->ui->textBrowserDebug->append(QString("<<<:\n") + QString::asprintf("%s", rxbuf) + + QString("\n")); } } diff --git a/tlcpclient.h b/tlcpclient.h index 8840bd7..f359b03 100644 --- a/tlcpclient.h +++ b/tlcpclient.h @@ -2,11 +2,11 @@ #define TLCPCLIENT_H #include +#include #include #include #include #include -#pragma comment(lib, "ws2_32.lib") namespace Ui { class TLCPclient; @@ -33,6 +33,9 @@ private slots: private: Ui::TLCPclient *ui; + QTcpSocket socket; + SSL_CTX *ctx; + SSL *ssl; }; #endif // TLCPCLIENT_H diff --git a/tlcpclient.ui b/tlcpclient.ui index 88ab966..1c23db4 100644 --- a/tlcpclient.ui +++ b/tlcpclient.ui @@ -6,43 +6,42 @@ 0 0 - 427 - 300 + 434 + 426 Form - + QLayout::SetMinimumSize - - + + 12 - 发送内容: + 接收数据: - - + + 12 - - hello Tongsuo - + + 发送数据: - + @@ -50,11 +49,58 @@ - 112.64.122.183 + 127.0.0.1 + + + IP地址 + + + + + + + 调试信息输出 + + + + + + + + + + + Academy Engraved LET + 13 + + + + 服务器地址: + + + + + + + + 0 + 0 + + + + + 12 + + + + 443 + + + 端口号 - + @@ -66,31 +112,33 @@ - - + + 12 - 内容反馈: + 发送 - - + + 12 - - 服务器地址: + + GET / HTTP/1.0 + + - + @@ -104,38 +152,22 @@ p, li { white-space: pre-wrap; } hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } -</style></head><body style=" font-family:'Microsoft YaHei UI'; font-size:12pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Microsoft YaHei UI';"><br /></p></body></html> - - - - - 12 - - + + - 发送 + ECC-SM2-SM4-CBC-SM3 - - - - - 0 - 0 - - - - - 12 - - + + - 443 + 密码套件: diff --git a/tserror.cpp b/tserror.cpp index 1fff4bf..7b6a6c4 100644 --- a/tserror.cpp +++ b/tserror.cpp @@ -17,3 +17,18 @@ void getError() QMessageBox::Close); return; } + +void printTSError() +{ + char buf[512]; + + ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); + + QMessageBox::warning(NULL, + "Error", + QString::asprintf("%s", buf), + QMessageBox::Close, + QMessageBox::Close); + + return; +} diff --git a/tserror.h b/tserror.h index d515bf1..3cc44f8 100644 --- a/tserror.h +++ b/tserror.h @@ -5,5 +5,8 @@ /* 错误处理函数 */ void getError(); +void printTSError(); + +extern BIO *bio_err; #endif // TSERROR_H diff --git a/version.h b/version.h new file mode 100644 index 0000000..12ad02a --- /dev/null +++ b/version.h @@ -0,0 +1,6 @@ +#ifndef VERSION_H +#define VERSION_H + +static const char *version = "1.0.0"; + +#endif // VERSION_H