Qt 实现Https ssl认证

Qt 实现Https ssl认证

安装OpenSSL

/index.html (openssl.org)

先了解一下认证原理

HTTPS单向认证

客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息;

服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书;

客户端使用服务端返回的信息验证服务器的合法性,包括:

  • 证书是否过期;
  • 发行服务器证书的CA是否可靠;(通过查询浏览器或本机内的CA证书)
  • 返回的公钥是否能正确解开返回证书中的数字签名;(通过使用本机或浏览器内置的CA公钥进行解密)
  • 服务器证书上的域名是否和服务器的实际域名相匹配;
  • 验证通过后,将继续进行通信,否则,终止通信;

客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择;

服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;

服务器将选择好的加密方案通过明文方式返回给客户端;

客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器;

服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥;
在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全;

image-20210723205933968

HTTPS双向认证

客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息;

服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书;

客户端使用服务端返回的信息验证服务器的合法性,包括:

  • 证书是否过期;
  • 发行服务器证书的CA是否可靠;(通过查询浏览器或本机内的CA证书)
  • 返回的公钥是否能正确解开返回证书中的数字签名;(通过使用本机或浏览器内置的CA公钥进行解密)
  • 服务器证书上的域名是否和服务器的实际域名相匹配;
  • 验证通过后,将继续进行通信,否则,终止通信;

服务端要求客户端发送客户端的证书即客户端证书公钥,客户端会将自己的证书发送至服务端;

验证客户端的证书,通过验证后,会获得客户端的公钥;

客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择

服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;

将加密方案通过使用之前获取到的公钥进行加密,返回给客户端

客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端;

服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全;

image-20210723210116842

Charles抓包原理

image-20210723205852568

数字证书详细认证过程

(1).首先,CA认证中心/数字证书所有人,它在网络上的表现形式只能是一张数字证书!所以我们可以把某张数字证书等价于某个CA认证中心/数字证书所有人。这样的话,验证数字证书的合法性就可以确定CA认证中心/数字证书所有人是否是合法的!!!

(2).数字证书使用数字签名作验证!这里简单说明一下数字签名的过程:你从Firefox/IE导出的数字证书包含3个部分:证书内容(F),加密算法(A),F加密密文(F’) (数字证书结构会在第三部分详细介绍),在这里,A不是一个算法,而是两个,所以密文F’是F两次加密后的结果。

首先,F会被散列算法SHA1计算出hash值h1(称为128bit的摘要),然后h1会被发布这个数字签名的CA认证机构的用私钥进行RSA加密,注意:是发布这个数字签名的CA认证机构,如果现在被加密的数字证书是属于二级CA认证机构的,那么用来加密这个证书的私钥是根CA认证机构的私钥!!RAS加密完后,就形成密文F’。

当你要验证这个数字证书可信/合法性时,你需要找到你的上一层CA认证中心的数字证书,并且从中获取公钥,把数据证书中的密文F’进行RSA解密,如果得出的值h2和h1比较(h1可以立即用数据证书中的F现场算出来),如果相等,则认为证书是可信的,合法的!由于你是不可能知道上一层CA认证中心的私钥,所以你无法伪造一个可以用上一层CA认证中心公钥解密的数字证书!!

详细流程图如下:

img

核心代码实现

加载本地证书

    auto certs = QSslCertificate::fromPath(crtPath,QSsl::Der);

    if (certs.isEmpty()) {
        QString localPersPath = QString("%1/xxxxx.*cer").arg(QCoreApplication::applicationDirPath()+"/cer");
        qInfo()<<"localPersPath: "<<localPersPath;
        certs = QSslCertificate::fromPath(localPersPath,QSsl::Der);
    }
    if (!certs.isEmpty()) {
        qInfo()<<"setLocalSslCertificate certs size: "<<certs.size();
        m_list_certs.append(certs);
        //设置SSL验证模式(四种模式)
        m_ssl_config.setPeerVerifyMode(QSslSocket::VerifyPeer);
        //使用TLS 1.2协议版本 这得看你服务器端的支持情况
        m_ssl_config.setProtocol(QSsl::TlsV1_2);
        //加入本地cer证书
        //qInfo()<<"m_list_certs size: "<<m_list_certs.size();
        m_ssl_config.setCaCertificates(m_list_certs);
        return true;
    }
    return false;

设置证书

 QNetworkRequest request;
    request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute,true);
    request.setUrl(url);
    request.setRawHeader( "Content-Type", "application/json" );
    // 清空上一次请求reply
    if (m_reply != nullptr) {
        m_reply->deleteLater();
    }
    //支持ssl
    if (QSslSocket::supportsSsl()) {
        //qInfo()<<"支持ssl";
        QSslConfiguration SslConfig = m_cert_manage->getSslConfiguration();
        request.setSslConfiguration(SslConfig);
    } else {
        //qInfo()<<"不支持ssl";
    }

    m_reply = m_manage->get(request);

获取远程证书信息,提取公钥,并RSA解密,计算hash值,并进行比较

 //获取远程证书,并进行认证
    if(reply == nullptr) return false;
    if (!reply->isRunning()) {
        return false;
    }
    QSslCertificate cert = reply->sslConfiguration().peerCertificate();
    if (!cert.isNull()) {
        qInfo()<<"server cert: "<<cert;
        //数字证书密文base64编码
        qInfo()<<"server-cert.pem: "<<QString(cert.toPem());
        //qInfo()<<"version: "<<cert.version();
        qInfo()<<"serialNumber: "<<cert.serialNumber();
        //qInfo()<<"digest: "<<cert.digest().toHex();
        //qInfo()<<"SHA-1: "<<cert.digest(QCryptographicHash::Sha1).toHex();
        //计算Hash后的值
        qInfo()<<"SHA-256: "<<cert.digest(QCryptographicHash::Sha256).toHex();
        qInfo()<<"证书的生效日期:"<<cert.effectiveDate();
        qInfo()<<"证书的过期日期:"<<cert.expiryDate();
        //需要先提取公钥后再对证书RSA解密
        QString str_pub_key = QString(cert.publicKey().toPem());
        qInfo()<<"publicKey: "<<str_pub_key;
        //应该用此公钥去解密证书内容得到hash值与cert.digest(QCryptographicHash::Sha256).toHex()相比较
        ....
    }

加解密类

#ifndef RSASIGNATURE_H
#define RSASIGNATURE_H

#include <QObject>
#include <QDebug>

#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include "openssl/ssl.h"
#include "openssl/err.h"

class RSASignature: public QObject
{
    Q_OBJECT
public:
    RSASignature() {};
    ~RSASignature() {};

public:
    RSA* createRSA(unsigned char * key,int type);
    int public_encrypt(QString &data,QString &keystr,QString &encrypted);
    int private_decrypt(QString &data,QString &keystr,QString &decrypted);
    int private_encrypt(QString &data,QString &keystr,QString &encrypted);
    int public_decrypt(QString &data,QString &keystr,QString &decrypted);

    /**
    * @brief rsa_pri_encrypt 私钥加密
    * @param strClearData 明文
    * @param strPriKey 私钥
    * @return 加密后数据(base64格式)
    */
    QString rsa_pri_encrypt_base64 (const QString& strClearData, const QString& strPriKey);
    /**
    * @brief rsa_pub_decrypt 公钥解密
    * @param strDecrypt 待解密数据(base64格式)
    * @param strPubKey 公钥
    * @return 明文
    */
    QString rsa_pub_decrypt_base64 (const QString& strDecryptData, const QString& strPubKey);
    /**
    * @brief rsa_pub_encrypt 公钥加密
    * @param strClearData 明文
    * @param strPubKey 私钥
    * @return 加密后数据(base64格式)
    */
    QString rsa_pub_encrypt_base64 (const QString& strClearData, const QString& strPubKey);
    /**
    * @brief rsa_pri_decrypt 私钥解密
    * @param strDecrypt 待解密数据(base64格式)
    * @param strPriKey 私钥
    * @return 明文
    */
    QString rsa_pri_decrypt_base64 (const QString& strDecryptData, const QString& strPriKey);


    //=========================================分段加解密=========================================
    bool createRsaKey (QString& strPubKey, QString& strPriKey);
    QString encrypt_RSA_by_long_str_public_key(const QString& strPubKey, const std::string& data);
    std::string decrypt_RSA_by_long_str_public_key(std::string publicKey, const std::string& data);
    std::string encrypt_RSA_by_long_str_private_key(std::string privateKey, const std::string& data);
    QString decrypt_RSA_by_long_str_private_key(const QString& strPriKey, const std::string& data);

    std::string RsaPriEncrypt_short(const std::string &clear_text, std::string &pri_key);
    std::string RsaPubDecrypt_short(const std::string & cipher_text, const std::string & pub_key);

    std::string RsaPriEncrypt(const std::string &clear_text, std::string &pri_key);
    std::string RsaPubDecrypt(const std::string & cipher_text, const std::string & pub_key);
    //=========================================test=========================================
    void showError();

    void test();
};

#endif // RSASIGNATURE_H

#include "rsasignature.h"

#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include "openssl/ssl.h"
#include "openssl/err.h"

#include <QDebug>

// define rsa public key
#define BEGIN_RSA_PUBLIC_KEY    "BEGIN RSA PUBLIC KEY"
#define BEGIN_PUBLIC_KEY        "BEGIN PUBLIC KEY"
#define KEY_LENGTH              2048
#define RSA_KEYSUB_LEN          64


/**
 * @brief RSASignature::createRSA 载入密钥
 * @param key 密钥
 * @param public 公钥1 私钥0
 * @return
 */
RSA * RSASignature::createRSA(unsigned char * key,int type)
{
    RSA *rsa= NULL;
    BIO *keybio ;
    keybio = BIO_new_mem_buf(key, -1);
    if (keybio==NULL)
    {
        qDebug()<< "Failed to create key BIO";
        return 0;
    }
    if(type)
    {
        rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
    }
    else
    {
        rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
    }
    if(rsa == NULL)
    {
        qDebug()<< "Failed to create RSA";
    }
    return rsa;
}

/**
 * @brief RSASignature::public_encrypt 公钥加密
 * @param data 待加密数据
 * @param keystr 公钥
 * @param encrypted 加密后数据
 * @return
 */
int RSASignature::public_encrypt(QString &data,QString &keystr,QString &encrypted)
{
    QByteArray keydata=keystr.toLocal8Bit();
    unsigned char *key= (unsigned char*)strdup(keydata.constData());//密钥
    RSA * rsa = createRSA(key,1);
    if(rsa==NULL)
        return 0;
    free(key);
    int rsasize=RSA_size(rsa);
    int exppadding=rsasize;
    int result=-1;
    QByteArray decdata=QByteArray::fromStdString(data.toStdString()).toBase64(QByteArray::Base64Encoding);
    QByteArray signByteArray;
    int data_len=decdata.length();
    if(data_len>exppadding-11)
        exppadding=exppadding-11;
    int b=0;
    int s=data_len/(exppadding);//片数
    if(data_len%(exppadding))
        s++;
    for(int i=0;i<s;i++)
    {
        QByteArray subdata={0};
        for(int j=0;j<exppadding;j++)
        {
            if(i*exppadding+j>data_len)
                break;
            subdata[j]=decdata[j+i*exppadding];
        }
        unsigned char *smldata=(unsigned char*)strdup(subdata.constData());//数据分片
        unsigned char smlencrypted[1024]={0};//片段加密数据
        b +=RSA_public_encrypt(exppadding,smldata,smlencrypted,rsa,RSA_NO_PADDING);
        if(b>0)
        {
            QByteArray subarray=QByteArray::fromRawData((const char *)smlencrypted,rsasize);
            signByteArray.append(subarray);
        }
        free(smldata);
    }
    QString str(signByteArray.toHex());
    qDebug()<<str;
    encrypted.append(str);
    result=b;
    return result;
}

/**
 * @brief RSASignature::private_decrypt 私钥解密
 * @param data 待解密数据
 * @param keystr 私钥
 * @param decrypted 解密后的数据
 * @return
 */
int RSASignature::private_decrypt(QString &data,QString &keystr,QString &decrypted)
{
    QByteArray keydata=keystr.toLocal8Bit();
    unsigned char *key= (unsigned char*)strdup(keydata.constData());//密钥
    RSA * rsa = createRSA(key,0);
    if(rsa==NULL)
        return 0;
    free(key);
    int rsasize=RSA_size(rsa);
    int result=-1;
    QByteArray encdata=QByteArray::fromHex(QByteArray::fromStdString( data.toStdString()));
    QByteArray signByteArray;
    int data_len=encdata.length();
    int b=0;
    int s=data_len/(rsasize);//片数
    if(data_len%(rsasize))
        s++;
    for(int i=0;i<s;i++)
    {
        QByteArray subdata={0};
        for(int j=0;j<rsasize;j++)
        {
            if(i*rsasize+j>data_len)
                break;
            subdata[j]=encdata[j+i*rsasize];
        }
        unsigned char *smldata=(unsigned char*)subdata.data();//(unsigned char*)strdup(subdata.constData());//数据分片
        unsigned char smlencrypted[1024]={0};//片段加密数据
        b +=RSA_private_decrypt(rsasize,smldata,smlencrypted,rsa,RSA_NO_PADDING);
        if(b>0)
        {
            QByteArray decdata((char*)smlencrypted);
            signByteArray.append(decdata);
        }
    }
    QByteArray b1= QByteArray::fromBase64(signByteArray,QByteArray::Base64Encoding);
    std::string str=b1.toStdString();
    decrypted.append(QString::fromStdString( str));
    result=b;
    return result;
}

/**
 * @brief RSASignature::private_encrypt 私钥加密
 * @param data 待加密数据
 * @param keystr 私钥
 * @param encrypted 解密后的数据
 * @return
 */
int RSASignature::private_encrypt(QString &data,QString &keystr,QString &encrypted)
{
    QByteArray keydata=keystr.toLocal8Bit();
    unsigned char *key= (unsigned char*)strdup(keydata.constData());//密钥
    RSA * rsa = createRSA(key,0);
    if(rsa==NULL)
        return 0;
    free(key);
    int rsasize=RSA_size(rsa);
    int exppadding=rsasize;
    int result=-1;
    QByteArray decdata=QByteArray::fromStdString(data.toStdString()).toBase64(QByteArray::Base64Encoding);
    QByteArray signByteArray;
    int data_len=decdata.length();
    if(data_len>exppadding-11)//padding占11位
        exppadding=exppadding-11;
    int b=0;
    int s=data_len/(exppadding);//片数
    if(data_len%(exppadding))
        s++;
    for(int i=0;i<s;i++)
    {
        //分片加密
        QByteArray subdata={0};
        for(int j=0;j<exppadding;j++)
        {
            if(i*exppadding+j>data_len)
                break;
            subdata[j]=decdata[j+i*exppadding];
        }
        unsigned char *smldata=(unsigned char*)strdup(subdata.constData());//数据分片
        unsigned char smlencrypted[1024]={0};//片段加密数据
        b +=RSA_private_encrypt(exppadding,smldata,smlencrypted,rsa,RSA_NO_PADDING);
        if(b>0)
        {
            QByteArray subarray=QByteArray::fromRawData((const char *)smlencrypted,rsasize);
            signByteArray.append(subarray);
        }
        free(smldata);
    }
    QString str(signByteArray.toHex());
    qDebug()<<str;
    encrypted.append(str);
    result=b;
    return result;
}

/**
 * @brief RSASignature::public_decrypt 公钥解密
 * @param data 待解密数据
 * @param keystr 公钥
 * @param decrypted 解密后的数据
 * @return
 */
int RSASignature::public_decrypt(QString &data,QString &keystr,QString &decrypted)
{
    QByteArray keydata=keystr.toLocal8Bit();
    unsigned char *key= (unsigned char*)strdup(keydata.constData());//密钥
    RSA * rsa = createRSA(key,1);
    if(rsa==NULL)
        return 0;
    free(key);
    int rsasize=RSA_size(rsa);
    int result=-1;
    QByteArray encdata=QByteArray::fromHex(QByteArray::fromStdString( data.toStdString()));
    QByteArray signByteArray;
    int data_len=encdata.length();
    int b=0;
    int s=data_len/(rsasize);//片数
    if(data_len%(rsasize))
        s++;
    for(int i=0;i<s;i++)
    {
        QByteArray subdata={0};
        for(int j=0;j<rsasize;j++)
        {
            if(i*rsasize+j>data_len)
                break;
            subdata[j]=encdata[j+i*rsasize];
        }
        unsigned char *smldata=(unsigned char*)subdata.data();//(unsigned char*)strdup(subdata.constData());//数据分片
        unsigned char smlencrypted[1024]={0};//片段加密数据
        b +=RSA_public_decrypt(rsasize,smldata,smlencrypted,rsa,RSA_NO_PADDING);
        if(b>0)
        {
            QByteArray decdata((char*)smlencrypted);
            signByteArray.append(decdata);
        }
    }
    QByteArray b1= QByteArray::fromBase64(signByteArray,QByteArray::Base64Encoding);
    std::string str=b1.toStdString();
    decrypted.append(QString::fromStdString( str));
    result=b;
    return result;
}

QString RSASignature::rsa_pri_encrypt_base64(const QString &strClearData, const QString &strPriKey)
{
    QString strEncryptData = "";
        QByteArray encryptData;
        QByteArray priKeyArry = strPriKey.toUtf8();
        uchar* pPriKey = (uchar*)priKeyArry.data();
        BIO* pKeyBio = BIO_new_mem_buf(pPriKey, strPriKey.length());
        if (pKeyBio == NULL){
            return "";
        }
        RSA* pRsa = RSA_new();
        pRsa = PEM_read_bio_RSAPrivateKey(pKeyBio, &pRsa, NULL, NULL);
        if ( pRsa == NULL ){
             BIO_free_all(pKeyBio);
             return "";
        }
        int nLen = RSA_size(pRsa);
        char* pEncryptBuf = new char[nLen];
        memset(pEncryptBuf, 0, nLen);
        QByteArray clearDataArry = strClearData.toUtf8();
        int nClearDataLen = clearDataArry.length();
    //    qDebug() << "nClearDataLen = " << nClearDataLen;

        uchar* pClearData = (uchar*)clearDataArry.data();
    //    int nSize = RSA_private_encrypt(nClearDataLen,          //字符串的长度
    //                                    pClearData,             //字符串unsigned char*格式
    //                                    (uchar*)pEncryptBuf,    //加密后的数据缓存
    //                                    pRsa,
    //                                    RSA_PKCS1_PADDING);     //1
    //    QString strEncryptData = "";
    //    if ( nSize >= 0 ){
    //         QByteArray arry(pEncryptBuf, nSize);
    //         strEncryptData = arry.toBase64();
    //    }

        int pdBlock = nLen - 11;
        int nCount = (nClearDataLen / pdBlock) + 1;//分段次数

    //    qDebug() << "nClearDataLen = " << nClearDataLen << "nCount = " << nCount << pdBlock;
        //分段加密
        for (int i = 0; i < nCount; i++)
        {
            int nSize = 0;
            pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;

            nSize = RSA_private_encrypt(pdBlock,
                                       pClearData,
                                       (uchar*)pEncryptBuf,
                                       pRsa,
                                       RSA_PKCS1_PADDING);
            pClearData += pdBlock;      //指针往前移
            nClearDataLen -= pdBlock;

            if ( nSize >= 0 ){
                QByteArray arry(pEncryptBuf, nSize);
                encryptData.append(arry);
    //            qDebug() << "strEncryptData = " << strEncryptData;
            }
    //        qDebug() << "nSize = " << nSize;
        }
        strEncryptData += encryptData.toBase64();       //最后才转,很重要,否则后面解密不成功


        // 释放内存
        delete []pEncryptBuf;
        BIO_free_all(pKeyBio);
        RSA_free(pRsa);
        return strEncryptData;
}

QString RSASignature::rsa_pub_decrypt_base64(const QString &strDecryptData, const QString &strPubKey)
{
    QString strClearData = "";
       QByteArray pubKeyArry = strPubKey.toUtf8();
       unsigned char* pPubKey = (unsigned char*)pubKeyArry.data();
       BIO* pKeyBio = BIO_new_mem_buf(pPubKey, strPubKey.length());
       if (pKeyBio == NULL){
           return "";
       }

       RSA* pRsa = RSA_new();
       if ( strPubKey.contains(BEGIN_RSA_PUBLIC_KEY) ){
           pRsa = PEM_read_bio_RSAPublicKey(pKeyBio, &pRsa, NULL, NULL);
       }else{
           pRsa = PEM_read_bio_RSA_PUBKEY(pKeyBio, &pRsa, NULL, NULL);
       }

       if ( pRsa == NULL ){
           showError();
           BIO_free_all(pKeyBio);
           return "";
       }
       int nLen = RSA_size(pRsa);
       char* pClearBuf = new char[nLen];
       memset(pClearBuf, 0, nLen);
       //解密
       QByteArray decryptDataArry = strDecryptData.toUtf8();
       decryptDataArry = QByteArray::fromBase64(decryptDataArry);
       int nDecryptDataLen = decryptDataArry.length();
       const unsigned char* pDecryptData = (unsigned char*)decryptDataArry.data();

       int pdBlock = nLen;
       int nCount = (nDecryptDataLen / pdBlock) + 1;//分段次数
       qDebug() << "nClearDataLen = " << nDecryptDataLen << "nCount = " << nCount << pdBlock;

       //分段解密
       for (int i = 0; i < nCount; i++)
       {
           int nSize = 0;

           pdBlock = (nDecryptDataLen > pdBlock) ? pdBlock : nDecryptDataLen;

           nSize = RSA_public_decrypt(pdBlock,
                                      pDecryptData,
                                      (unsigned char*)pClearBuf,
                                      pRsa,
                                      RSA_NO_PADDING);
           qInfo()<<"RSA_public_decrypt ret: "<<nSize;
           pDecryptData += pdBlock;        //加密数据指针往前移
           nDecryptDataLen -= pdBlock;

               if ( nSize >= 0 ){
                   strClearData += QByteArray(pClearBuf, nSize);
                   //qInfo()<<"strClearData: "<<strClearData;

   //                qDebug() << "nSize " << nSize;
   //                qDebug() << "strClearData = " << strClearData;
               } else {
                   showError();
               }
   //            qDebug() << "nSize " << nSize;
       }

       // 释放内存
       delete []pClearBuf;
       BIO_free_all(pKeyBio);
       RSA_free(pRsa);
       return strClearData;
}

QString RSASignature::rsa_pub_encrypt_base64(const QString &strClearData, const QString &strPubKey)
{
    qDebug() << "rsa_pub_encrypt_base64 start...";
        QString strEncryptData;
        QByteArray encryptData;
        QByteArray pubKeyArry = strPubKey.toUtf8();
        uchar* pPubKey = (uchar*)pubKeyArry.data();
        BIO* pKeyBio = BIO_new_mem_buf(pPubKey, pubKeyArry.length());
        if (pKeyBio == NULL){
            return "pKeyBio = NULL";
        }
        RSA* pRsa = RSA_new();
        if ( strPubKey.contains(BEGIN_RSA_PUBLIC_KEY) ){
            pRsa = PEM_read_bio_RSAPublicKey(pKeyBio, &pRsa, NULL, NULL);
        }else{
            pRsa = PEM_read_bio_RSA_PUBKEY(pKeyBio, &pRsa, NULL, NULL);
        }
        if ( pRsa == NULL ){
            BIO_free_all(pKeyBio);
            return "Rsa = NULL";
        }

        int nLen = RSA_size(pRsa);
        char* pEncryptBuf = new char[nLen];


        QByteArray clearDataArry = strClearData.toUtf8();
        int nClearDataLen = clearDataArry.length();
        uchar* pClearData = (uchar*)clearDataArry.data();

        int pdBlock = nLen - 11;
        int nCount = (nClearDataLen / pdBlock) + 1;//分段次数

    //    qDebug() << "nClearDataLen = " << nClearDataLen << "nCount = " << nCount << pdBlock;

        //分段加密
        for (int i = 0; i < nCount; i++)
        {
            int nSize = 0;
            pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;

    //        qDebug() << "RSA_public_encrypt start...";
            nSize = RSA_public_encrypt(pdBlock,
                                       pClearData,
                                       (unsigned char*)pEncryptBuf,
                                       pRsa,
                                       RSA_PKCS1_PADDING);


    //        qDebug() << "RSA_public_encrypt mid...";
            pClearData += pdBlock;      //指针往前移
            nClearDataLen -= pdBlock;

    //        qDebug() << "RSA_public_encrypt end...";
            if ( nSize >= 0 ){
                QByteArray arry((char*)pEncryptBuf, nSize);
                encryptData.append(arry);
    //            qDebug() << "strEncryptData = " << strEncryptData;
            }
    //        qDebug() << "nSize = " << nSize;
        }
        strEncryptData += encryptData.toBase64();       //最后才转,很重要,否则后面解密不成功

    //    qDebug() << "rsa_pub_encrypt_base64 end...";
        // 释放内存
        delete [] pEncryptBuf;
        BIO_free_all(pKeyBio);
        RSA_free(pRsa);
        return strEncryptData;
}

QString RSASignature::rsa_pri_decrypt_base64(const QString &strDecryptData, const QString &strPriKey)
{
    QString strClearData = "";
       QByteArray priKeyArry = strPriKey.toUtf8();
       uchar* pPriKey = (uchar*)priKeyArry.data();
       BIO* pKeyBio = BIO_new_mem_buf(pPriKey, priKeyArry.length());
       if (pKeyBio == NULL){
           return "";
       }
       RSA* pRsa = RSA_new();
       pRsa = PEM_read_bio_RSAPrivateKey(pKeyBio, &pRsa, NULL, NULL);
       if ( pRsa == NULL ){
           BIO_free_all(pKeyBio);
           return "";
       }
       int nLen = RSA_size(pRsa);
       char* pClearBuf = new char[nLen];
       memset(pClearBuf, 0, nLen);

       //解密
       QByteArray decryptDataArry = strDecryptData.toUtf8();
       decryptDataArry = QByteArray::fromBase64(decryptDataArry);
       int nDecryptDataLen = decryptDataArry.length();
       uchar* pDecryptData = (uchar*)decryptDataArry.data();

   //    qDebug() << "decryptDataArry === " <<  decryptDataArry.toHex().toUpper();

       int pdBlock = nLen;
       int nCount = (nDecryptDataLen / pdBlock) + 1;//分段次数
   //    qDebug() << "nClearDataLen = " << nDecryptDataLen << "nCount = " << nCount << pdBlock;

       //分段解密
       for (int i = 0; i < nCount; i++)
       {
           int nSize = 0;

           pdBlock = (nDecryptDataLen > pdBlock) ? pdBlock : nDecryptDataLen;

           nSize = RSA_private_decrypt(pdBlock,
                                       pDecryptData,
                                       (uchar*)pClearBuf,
                                       pRsa,
                                       RSA_NO_PADDING);
           pDecryptData += pdBlock;        //加密数据指针往前移
           nDecryptDataLen -= pdBlock;

               if ( nSize >= 0 ){
                   strClearData += QByteArray(pClearBuf, nSize);

   //                qDebug() << "nSize " << nSize;
   //                qDebug() << "strClearData = " << strClearData;
               }
   //            qDebug() << "nSize " << nSize;
       }

       // 释放内存
       delete []pClearBuf;
       BIO_free_all(pKeyBio);
       RSA_free(pRsa);
       return strClearData;
}




/**
* @brief createRsaKey 生成秘钥对
* @param strPubKey 公钥
* @param strPriKey 私钥
* @return 成功状态
*/
bool RSASignature::createRsaKey (QString& strPubKey, QString& strPriKey)
{
     RSA *pRsa = RSA_generate_key(KEY_LENGTH, RSA_F4, NULL, NULL);       //RSA_3-->RSA_F4
     if ( !pRsa ){
         return false;
     }
     BIO *pPriBio = BIO_new(BIO_s_mem());
     PEM_write_bio_RSAPrivateKey(pPriBio, pRsa, NULL, NULL, 0, NULL, NULL);

     BIO *pPubBio = BIO_new(BIO_s_mem());
     //生成-----BEGIN RSA PUBLIC KEY-----公钥格式
     //PEM_write_bio_RSAPublicKey(pPubBio, pRsa);
     //生成-----BEGIN PUBLIC KEY-----公钥格式
     PEM_write_bio_RSA_PUBKEY(pPubBio, pRsa);

     // 获取长度
     size_t nPriKeyLen = BIO_pending(pPriBio);
     size_t nPubKeyLen = BIO_pending(pPubBio);
     // 密钥对读取到字符串
     char* pPriKey = new char[nPriKeyLen];
     char* pPubKey = new char[nPubKeyLen];
     BIO_read(pPriBio, pPriKey, nPriKeyLen);
     BIO_read(pPubBio, pPubKey, nPubKeyLen);
     // 存储密钥对
     strPubKey = QByteArray(pPubKey, nPubKeyLen);
     strPriKey = QByteArray(pPriKey, nPriKeyLen);
     // 内存释放
     RSA_free(pRsa);
     BIO_free_all(pPriBio);
     BIO_free_all(pPubBio);
     delete [] pPriKey;
     delete [] pPubKey;
     return true;
}


/*
 * 公钥加密
 */
QString RSASignature::encrypt_RSA_by_long_str_public_key(const QString& strPubKey, const std::string& data)
{
    QString strRet;
    ///创建RSA指针
//    RSA* rsa = create_RSA((unsigned char*)publicKey.c_str(), 1);
    qDebug() << "pk";
    QByteArray pubKeyArry = strPubKey.toUtf8();
    uchar* pPubKey = (uchar*)pubKeyArry.data();
    BIO* pKeyBio = BIO_new_mem_buf(pPubKey, pubKeyArry.length());
    if (pKeyBio == NULL){
        return "ERROR";
    }
    RSA* pRsa = RSA_new();
    if ( strPubKey.contains(BEGIN_RSA_PUBLIC_KEY) ){
        pRsa = PEM_read_bio_RSAPublicKey(pKeyBio, &pRsa, NULL, NULL);
    }else{
        pRsa = PEM_read_bio_RSA_PUBKEY(pKeyBio, &pRsa, NULL, NULL);
    }
    if ( pRsa == NULL ){
        BIO_free_all(pKeyBio);
        return "ERROR";
    }

    int len = RSA_size(pRsa);

    char* decryptedText = (char*)malloc(len + 1);
    memset(decryptedText, 0, len + 1);

    int nClearDataLen = data.length();

    int pdBlock = len - 11;
    int nCount = (nClearDataLen / pdBlock) + 1;//分段次数
    qDebug() << "nClearDataLen" << nClearDataLen << "pdBlock" << pdBlock << "nCount" << nCount;

    unsigned char* pClearData = (unsigned char*)data.c_str();
    //分段加密
    for (int i = 0; i < nCount; i++)
    {
        int nSize = 0;
        pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
        nSize = RSA_public_encrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, pRsa, RSA_PKCS1_PADDING);
        pClearData += pdBlock;
        nClearDataLen -= pdBlock;

        if (nSize >= 0)
        {
//            strRet += std::string(decryptedText, nSize);
            QByteArray arry(decryptedText, nSize);
            strRet += arry.toBase64();
        }
    }

    // 释放内存
    free (decryptedText);
    RSA_free(pRsa);
    return strRet;
}

/*
 * 公钥解密
 */
std::string RSASignature::decrypt_RSA_by_long_str_public_key(std::string publicKey, const std::string& data)
{
    std::string strRet;
    ///创建RSA指针
    RSA* rsa = createRSA((unsigned char*)publicKey.c_str(), 1);

    int len = RSA_size(rsa);
    char* decryptedText = (char*)malloc(len + 1);
    memset(decryptedText, 0, len + 1);

    int nClearDataLen = data.length();

    int pdBlock = len;
    int nCount = (nClearDataLen / pdBlock) + 1;//分段次数
    unsigned char* pClearData = (unsigned char*)data.c_str();
    qDebug()<<"nCount: "<<nCount;
    //分段解密
    for (int i = 0; i < nCount; i++)
    {
        int nSize = 0;

        pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
        nSize = RSA_public_decrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_NO_PADDING);
        qDebug()<<"RSA_public_decrypt ires: "<<nSize;
        pClearData += pdBlock;
        nClearDataLen -= pdBlock;

        if (nSize >= 0)
        {
            strRet += std::string(decryptedText, nSize);
        } else
        {
            showError();
            return "";
        }
    }
    free (decryptedText);
    // 释放内存
    RSA_free(rsa);
    return strRet;
}


/*
 * 私钥加密
 */
std::string RSASignature::encrypt_RSA_by_long_str_private_key(std::string privateKey, const std::string& data)
{
    std::string strRet;
    ///创建RSA指针
    RSA* rsa = createRSA((unsigned char*)privateKey.c_str(), 0);

    int len = RSA_size(rsa);

    char* decryptedText = (char*)malloc(len + 1);
    memset(decryptedText, 0, len + 1);

    int nClearDataLen = data.length();

    int pdBlock = len - 11;         //padding占11位
    int nCount = (nClearDataLen / pdBlock) + 1;//分段次数
    unsigned char* pClearData = (unsigned char*)data.c_str();
    //分段加密
    for (int i = 0; i < nCount; i++)
    {
        int nSize = 0;
        pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
        nSize = RSA_private_encrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
        pClearData += pdBlock;
        nClearDataLen -= pdBlock;

        if (nSize >= 0)
        {
            strRet += std::string(decryptedText, nSize);
        }
    }

    // 释放内存
    free (decryptedText);
    RSA_free(rsa);
    return strRet;
}
/*
 * 私钥解密
 */
QString RSASignature::decrypt_RSA_by_long_str_private_key(const QString& strPriKey, const std::string& data)
{
    QString strRet;
    ///创建RSA指针
//    RSA* rsa = create_RSA((unsigned char*)privateKey.c_str(), 0);
    QByteArray priKeyArry = strPriKey.toUtf8();
    uchar* pPriKey = (uchar*)priKeyArry.data();
    BIO* pKeyBio = BIO_new_mem_buf(pPriKey, priKeyArry.length());
    if (pKeyBio == NULL){
        return "";
    }
    RSA* pRsa = RSA_new();
    pRsa = PEM_read_bio_RSAPrivateKey(pKeyBio, &pRsa, NULL, NULL);
    if ( pRsa == NULL ){
        BIO_free_all(pKeyBio);
        return "error";
    }


    int len = RSA_size(pRsa);
    char* decryptedText = (char*)malloc(len + 1);
    memset(decryptedText, 0, len + 1);

    int nClearDataLen = data.length();
    int pdBlock = len;
    int nCount = (nClearDataLen / pdBlock) + 1;//分段次数
    unsigned char* pClearData = (unsigned char*)data.c_str();
    //分段解密
    for (int i = 0; i < nCount; i++)
    {
        int nSize = 0;

        pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
        nSize = RSA_private_decrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, pRsa, RSA_PKCS1_PADDING);
        pClearData += pdBlock;
        nClearDataLen -= pdBlock;

        if (nSize >= 0)
        {
//            strRet += std::string(decryptedText, nSize);
            strRet += QByteArray(decryptedText, nSize);

            qDebug() << "nSize = " << nSize;
        }
    }
    free (decryptedText);
    // 释放内存
    RSA_free(pRsa);
    return strRet;
}

/*
@brief : 私钥加密(短数据)
@para  : clear_text  -[i] 需要进行加密的明文
         pri_key     -[i] 私钥
@return: 加密后的数据
**/
std::string RSASignature::RsaPriEncrypt_short(const std::string &clear_text, std::string &pri_key)
{
    std::string encrypt_text;
    BIO *keybio = BIO_new_mem_buf((unsigned char *)pri_key.c_str(), -1);
    RSA* rsa = RSA_new();
    rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
    if (!rsa)
    {
        BIO_free_all(keybio);
        return std::string("");
    }

    // 获取RSA单次可以处理的数据的最大长度
    int len = RSA_size(rsa);

    // 申请内存:存贮加密后的密文数据
    char *text = new char[len + 1];
    memset(text, 0, len + 1);

    // 对数据进行私钥加密(返回值是加密后数据的长度)
    int ret = RSA_private_encrypt(clear_text.length(), (const unsigned char*)clear_text.c_str(), (unsigned char*)text, rsa, RSA_PKCS1_PADDING);
    if (ret >= 0) {
        encrypt_text = std::string(text, ret);
    }

    // 释放内存
    free(text);
    BIO_free_all(keybio);
    RSA_free(rsa);

    return encrypt_text;
}

/*
@brief : 公钥解密(短数据)
@para  : cipher_text -[i] 加密的密文
         pub_key     -[i] 公钥
@return: 解密后的数据
**/
std::string RSASignature::RsaPubDecrypt_short(const std::string &cipher_text, const std::string &pub_key)
{
    std::string decrypt_text;
    BIO *keybio = BIO_new_mem_buf((unsigned char *)pub_key.c_str(), -1);
    RSA *rsa = RSA_new();

    // 注意--------使用第1种格式的公钥进行解密
    //rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
    // 注意--------使用第2种格式的公钥进行解密(我们使用这种格式作为示例)
    rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
    if (!rsa)
    {
        showError();
        BIO_free_all(keybio);
        return decrypt_text;
    }

    int len = RSA_size(rsa);
    char *text = new char[len + 1];
    memset(text, 0, len + 1);
    // 对密文进行解密
    int ret = RSA_public_decrypt(cipher_text.length(), (const unsigned char*)cipher_text.c_str(), (unsigned char*)text, rsa, RSA_PKCS1_PADDING);
    if (ret >= 0) {
        decrypt_text.append(std::string(text, ret));
    } else {
        showError();
        return "";
    }

    // 释放内存
    delete []text;
    BIO_free_all(keybio);
    RSA_free(rsa);

    return decrypt_text;
}

/*
@brief : 私钥加密
@para  : clear_text  -[i] 需要进行加密的明文
         pri_key     -[i] 私钥
@return: 加密后的数据
**/
std::string RSASignature::RsaPriEncrypt(const std::string &clear_text, std::string &pri_key)
{
    std::string encrypt_text;
    BIO *keybio = BIO_new_mem_buf((unsigned char *)pri_key.c_str(), -1);
    RSA* rsa = RSA_new();
    rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
    if (!rsa)
    {
        BIO_free_all(keybio);
        return std::string("");
    }

    // 获取RSA单次可以处理的数据块的最大长度
    int key_len = RSA_size(rsa);
    int block_len = key_len - 11;    // 因为填充方式为RSA_PKCS1_PADDING, 所以要在key_len基础上减去11

    // 申请内存:存贮加密后的密文数据
    char *sub_text = new char[key_len + 1];
    memset(sub_text, 0, key_len + 1);
    int ret = 0;
    int pos = 0;
    std::string sub_str;
    // 对数据进行分段加密(返回值是加密后数据的长度)
    while (pos < clear_text.length()) {
        sub_str = clear_text.substr(pos, block_len);
        memset(sub_text, 0, key_len + 1);
        ret = RSA_private_encrypt(sub_str.length(), (const unsigned char*)sub_str.c_str(), (unsigned char*)sub_text, rsa, RSA_PKCS1_PADDING);
        if (ret >= 0) {
            encrypt_text.append(std::string(sub_text, ret));
        } else {
            showError();
        }
        pos += block_len;
    }

    // 释放内存
    delete []sub_text;
    BIO_free_all(keybio);
    RSA_free(rsa);

    return encrypt_text;
}

/*
@brief : 公钥解密
@para  : cipher_text -[i] 加密的密文
         pub_key     -[i] 公钥
@return: 解密后的数据
**/
std::string RSASignature::RsaPubDecrypt(const std::string &cipher_text, const std::string &pub_key)
{
    std::string decrypt_text;
    BIO *keybio = BIO_new_mem_buf((unsigned char *)pub_key.c_str(), -1);
    RSA* rsa = RSA_new();

    // 注意-------使用第1种格式的公钥进行解密
    //rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
    // 注意-------使用第2种格式的公钥进行解密(我们使用这种格式作为示例)
    rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
    if (!rsa)
    {
        showError();
        BIO_free_all(keybio);
        return decrypt_text;
    }

    // 获取RSA单次处理的最大长度 len = 256
    int len = RSA_size(rsa);
    char *sub_text = new char[len + 1];
    memset(sub_text, 0, len + 1);
    int ret = 0;
    std::string sub_str;
    int pos = 0;
    // 对密文进行分段解密,先base64解码
//    QString decrypt_str = QString::fromStdString(cipher_text);
//    QByteArray decryptDataArry = decrypt_str.toUtf8();
//    decryptDataArry = QByteArray::fromBase64(decryptDataArry);
//    qInfo()<<"decryptDataArry size: "<<decryptDataArry.size();
//    std::string decrypt_str2 = decryptDataArry.toStdString();
//    qInfo()<<"decrypt_str2: "<<decrypt_str2.c_str();
    while (pos < cipher_text.length()) {
        sub_str = cipher_text.substr(pos, len);
        memset(sub_text, 0, len + 1);
        ret = RSA_public_decrypt(sub_str.length(), (const unsigned char*)sub_str.c_str(), (unsigned char*)sub_text, rsa, RSA_NO_PADDING);
        qInfo()<<"RSA_public_decrypt ret: "<<ret;
        if (ret >= 0) {
            decrypt_text.append(std::string(sub_text, ret));
            //printf("pos:%d, sub: %s\n", pos, sub_text);
            pos += len;
            qInfo()<<"sub_text: "<<sub_text;
        } else {
            showError();
            return "";
        }
    }

    // 释放内存
    delete []  sub_text;
    BIO_free_all(keybio);
    RSA_free(rsa);

    return decrypt_text;
}

void RSASignature::showError()
{
    unsigned long err = ERR_get_error(); //获取错误号
    char err_msg[1024] = { 0 };
    ERR_error_string(err, err_msg); // 格式:error:errId:库:函数:原因
    qWarning()<<"err_code: "<<err <<" err_msg: "<<err_msg;
}

void RSASignature::test()
{
    /**< rsa private/public key 若从文件中拷贝出来,需要注意保存元先文件格式,即换行符需要带上,包括最后一行的换行符 */
      QString strPriKey = "";
      QString strPubKey = "";
      /**
       *  用代码生成的key与openssl命令生成的key区别:
       *  1、代码生成key,标题为 -----BEGIN RSA PUBLIC KEY-----,openssl命令生成key, 标题为 -----BEGIN PUBLIC KEY-----
       *  2、获取RSA函数不同,代码生成key,用PEM_read_bio_RSAPublicKey,openssl命令生成key,用PEM_read_bio_RSA_PUBKEY
      */
      createRsaKey(strPubKey, strPriKey);
      qInfo()<<"strPubKey: "<<strPubKey.toStdString().c_str();
      qInfo()<<"strPriKey: "<<strPriKey.toStdString().c_str();

      QString strClear = "2975e34952c84987b9c77bc24390a802063d5f1734a01dfc8d87b1d83941e973";
      //qDebug()<<"原始数据:"<<strClear;

//      qDebug() << "private key encrypt, public key decrypt";

      QString strEncryptData = rsa_pri_encrypt_base64 (strClear, strPriKey);
      qDebug() <<"私钥加密后数据:"<< strEncryptData;
      QString strClearData = rsa_pub_decrypt_base64 (strEncryptData, strPubKey);
      qDebug() <<"公钥解密后数据:"<< strClearData;

//      std::string strEncryptData = encrypt_RSA_by_long_str_private_key(strPriKey.toStdString(), strClear.toStdString());
//      qDebug() <<"私钥加密后数据:"<< strEncryptData.c_str();
//      std::string strClearData = decrypt_RSA_by_long_str_public_key(strPriKey.toStdString(), strEncryptData);
//      qDebug() <<"公钥解密后数据:"<< strClearData.c_str();


  //    qDebug() << "public key encrypt, private key decrypt";
  //    QString strEncryptData = rsa_pub_encrypt_base64 (strClear, strPubKey);
  //    qDebug() << strEncryptData;
  //    QString strClearData = rsa_pri_decrypt_base64 (strEncryptData, strPriKey);
  //    qDebug() << strClearData;

//      QString strEncryptData = encrypt_RSA_by_long_str_public_key(strPubKey, strClear.toStdString());
//      QString strClearData = decrypt_RSA_by_long_str_private_key(strPriKey, strEncryptData.toStdString());

}

代码下载地址

https_test_v2.7z-网络安全文档类资源-CSDN下载

参考

一文看懂HTTPS、证书机构(CA)、证书、数字签名、私钥、公钥 - 简书 (jianshu.com)

彻底搞懂HTTPS的加密原理 - 知乎 (zhihu.com)

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ZLOZL

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值