Qt 实现Https ssl认证
安装OpenSSL
先了解一下认证原理
HTTPS单向认证
客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息;
服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书;
客户端使用服务端返回的信息验证服务器的合法性,包括:
- 证书是否过期;
- 发行服务器证书的CA是否可靠;(通过查询浏览器或本机内的CA证书)
- 返回的公钥是否能正确解开返回证书中的数字签名;(通过使用本机或浏览器内置的CA公钥进行解密)
- 服务器证书上的域名是否和服务器的实际域名相匹配;
- 验证通过后,将继续进行通信,否则,终止通信;
客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择;
服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;
服务器将选择好的加密方案通过明文方式返回给客户端;
客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器;
服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥;
在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全;
HTTPS双向认证
客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息;
服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书;
客户端使用服务端返回的信息验证服务器的合法性,包括:
- 证书是否过期;
- 发行服务器证书的CA是否可靠;(通过查询浏览器或本机内的CA证书)
- 返回的公钥是否能正确解开返回证书中的数字签名;(通过使用本机或浏览器内置的CA公钥进行解密)
- 服务器证书上的域名是否和服务器的实际域名相匹配;
- 验证通过后,将继续进行通信,否则,终止通信;
服务端要求客户端发送客户端的证书即客户端证书公钥,客户端会将自己的证书发送至服务端;
验证客户端的证书,通过验证后,会获得客户端的公钥;
客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择
服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;
将加密方案通过使用之前获取到的公钥进行加密,返回给客户端
客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端;
服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全;
Charles抓包原理
数字证书详细认证过程
(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认证中心公钥解密的数字证书!!
详细流程图如下:
核心代码实现
加载本地证书
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-网络安全文档类资源-优快云下载