Qt5使用openssl实现RSA数字签名

1、环境安装

win7 64

安装qt-opensource-windows-x86-5.9.0.exe或更高版本,下载地址

安装Win32OpenSSL-1_0_2L.exe 下载地址,最新版本可能因为pro配置问题,总不成功,希望大家提醒

2、在Qt5工程的pro中 填写

LIBS += -LC:/OpenSSL-Win32/lib/MinGW -llibeay32
LIBS += -LC:/OpenSSL-Win32/lib/MinGW -lssleay32
INCLUDEPATH += $$quote(C:/OpenSSL-Win32/include)


添加头文件

#include 
#include 
#include 
#include 
#include 

3、添加代码

void MainWindow::createRSAKey()
{
    //创建目录
    QString strPath = "./key";
    QDir dir;
    if(dir.exists(strPath) == false)
    {
        dir.mkpath(strPath);//创建目录
    }
    BIGNUM *bne = BN_new();
    int ret = BN_set_word(bne,RSA_F4);/* 设置随机数长度 */
    RSA *rsa = RSA_new();
    ret = RSA_generate_key_ex(rsa,1024,bne,NULL);/* 密钥长度1024 生成RSA密钥对 */
    if(ret != 1)
    {
        QMessageBox::information(this,"错误提示","生成RSA密钥错误!无法实现后续数字签名!",QMessageBox::Yes);
        return;
    }
    /* 提取私钥 */
    FILE *filename = NULL;
    filename = fopen("./key/privateKey.pem", "wb");
    PEM_write_RSAPrivateKey(filename, rsa, NULL, NULL, 0, NULL, NULL);
    fclose(filename);
    filename = NULL;
    /* 提取公钥 */
    unsigned char *n_b = (unsigned char *)calloc(RSA_size(rsa), sizeof(unsigned char));
    unsigned char *e_b = (unsigned char *)calloc(RSA_size(rsa), sizeof(unsigned char));
    int n_size = BN_bn2bin(rsa->n, n_b);
    int b_size = BN_bn2bin(rsa->e, e_b);
    RSA *pubrsa = RSA_new();
    pubrsa->n = BN_bin2bn(n_b, n_size, NULL);
    pubrsa->e = BN_bin2bn(e_b, b_size, NULL);

//    //另一种格式的公钥输出
//    filename = fopen("./key/publicKeyRSA.pem", "wb");
//    PEM_write_RSAPublicKey(filename, pubrsa);
//    fclose(filename);
//    filename = NULL;

    filename = fopen("./key/publicKey.pem", "wb");
    PEM_write_RSA_PUBKEY(filename, pubrsa);
    fclose(filename);
    filename = NULL;

    RSA_free(pubrsa);
    RSA_free(rsa);
}


编译链接没有问题,运行发现当执行到PEM_write_RSAPrivateKey时报错:OPENSSL_Uplink(67C97000,08): no OPENSSL_Applink

按照网络上的方法尝试

在main文件中的包含头文件的下方加入OpenSSL的链接头文件(经测试放在在调用的mainwidow.cpp中也可以)

extern "C"{

#include "openssl/applink.c"

};

报错

C:\OpenSSL-Win32\include\openssl\applink.c:-1: In function 'void** OPENSSL_Applink()':
C:\OpenSSL-Win32\include\openssl\applink.c:95: error: invalid conversion from 'void* (*)()' to 'void*' [-fpermissive]
         OPENSSL_ApplinkTable[APPLINK_STDIN] = app_stdin;

……

大概是说指针转换出错,全部加上强转,比如

将OPENSSL_ApplinkTable[APPLINK_STDIN] = app_stdin;改为OPENSSL_ApplinkTable[APPLINK_STDIN] =(void*)app_stdin;

编译通过,运行不闪退了

要注意生成公钥和密钥的PEM格式,因为要对应相应的导入函数

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfbQTubOxaSqao97+AaS9Esc6F
dzZ716bqFUTyhTAKU78yUfaG3GSmPH+HyIZIiZnqlU9Z0MEXhFY6hMgI20ZcuZAA
yz6G1hQeaJt1xLSdUblaB5fV6mMPcCuKTgctjq9HJhw47e/iMY+lj+7+30H4Vo43
+xLA4RBmUv4M0AXUnQIDAQAB
-----END PUBLIC KEY-----

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCfbQTubOxaSqao97+AaS9Esc6FdzZ716bqFUTyhTAKU78yUfaG
3GSmPH+HyIZIiZnqlU9Z0MEXhFY6hMgI20ZcuZAAyz6G1hQeaJt1xLSdUblaB5fV
6mMPcCuKTgctjq9HJhw47e/iMY+lj+7+30H4Vo43+xLA4RBmUv4M0AXUnQIDAQAB
AoGBAIHzL03ZY17F8stQBrz5ABqShLCt169ivR+ZbrXwcpQ4Z2TxAm4zP6dxMNLR
VQPTha59Pk0LqBkvOcpBaXwuoE6zaILz9xbyWyZzC/zecq4P4NJRGesdo2yTnnhb
0dJSOAVydCGuTCbbjS/F4Z854NJ8392+h0XCjwJsV+17apVRAkEAy1A7rG0AyYp2
n7b3R0RbDGMbo3Zaxpx2kLHCUOGM6+HLmMuQmff4Y37bsvK27X4IGomptl1+iAJo
GGLeM/+7EwJBAMi9S6Uk2xgf9FqQa4BL/SyOkgjntH69LLUstA+69jSb4A/FTKG6
R6g09qCARb4MLx6LQwnRA6guE7hma68/948CQGpkbwW4+Nt+iLrlbRsvKxIdXt44
ViJuyCDJ1Kysiyj4vKkVhXL8709pmCBZoN5AwI7akSPsYwVbdQul2S+O2F8CQBN8
nM1JSKOM5pGsF2N6/PbIWFDY/WKYRrDHyCsGwUPWJegiBRBmHvKrQY3PJfYPBLv4
VOetDKfU4UEzYBzBHu0CQDaoJbKyumkQXcZXT5cQ0n8Tu5islB8XeItUqAI3Y9uK
ZVLTsoTLVAqMyJsEDDIK8AO580NEF++6nzig/LpOvuU=
-----END RSA PRIVATE KEY-----

真正使用的时候公钥密钥只需要生成一次,使用密钥生成的签名里面含有不可显示字符,所以如果输出显示要么转为16进制,要么进行base64编码;

提供上面的密钥的鲁123456789的数字签名(十六进制输出),也方便大家对照RSA签名

Qt5使用openssl实现RSA数字签名_第1张图片

openssl的RSA数字签名函数RSA_sign没有执行摘要算法,所以要对明文先进行摘要算法SHA1,否则和C# JAVA生成的RSA签名是不一致的!

代码:

void MainWindow::CreateSignature(QByteArray const &strxml,unsigned char *bSign,size_t *iSignlen)
{
    unsigned char *bData = NULL;//报文
    bData = (unsigned char*)(strxml.data());
    size_t iDatalen = strxml.size();
    LoadRSA();//这里可以放在构造函数执行一次加载进来就可以了
    unsigned char szTmp[20]={0};
    SHA1(bData, iDatalen, szTmp);//一定先生成摘要
    int ret = RSA_sign(NID_sha1,szTmp,20,bSign,iSignlen,p_rsa);
    if(ret!=1)
    {
        QMessageBox::information(this,"错误提示","生成签名失败!",QMessageBox::Yes);
    }
}
完整的 Qt5工程,以及 Win32OpenSSL-1_0_2L.exe都 上传到CSDN,方便大家参考,欢迎下载评论

参考文献

Windows下openssl的下载安装和使用

openssl之RSA编程

C# RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密

保存openssl中RSA密钥对

SHA1WithRSA签名使用openssl 实现

Qt之OpenSSL

QT添加openssl的方法 

openssl编程出现no OPENSSL_Applink

Qt openssl配置,OPENSSL_Applink错误  

How to Include OpenSSL in a Qt project

你可能感兴趣的:(C++,Qt)