Qt 操作openssl进行RSA加密解密 PEM_read_bio_RSAPrivateKey 返回NULL
这个根据操作没啥难的,说说我踩的坑.
1 生成的秘钥的格式是固定的,一定注意换行符 \n 不能省略.我曾经使用QLineEdit 输入秘钥,结果就是程序走到 PEM_read_bio_RSAPrivateKey 总是返回 NULL
解决方法 输入秘钥时候,使用 QPlainEdit 替换 QLineEdit 因为 QPlainEdit 能保留 \n QLineEdit在输入时候,默认将 \n 替换为空格,空格输入加密解密程序就会报错
2 在电脑上进行加密解密一般生成的都是客打印字符,但是如果是使用单片机生成的加密数据,那可就不一定是客打印数据了,此时不用担心,因为openssl的解密是支持hex输入的.
3 此处我使用的rsa加密解密是参考别人的,稍作修改,注意网上还有一个说法是必须是 win32 的程序
pro 引入如下
INCLUDEPATH += $$PWD/openssl/ win32 { LIBS += -lwsock32 LIBS += -L$$PWD/lib/ -llibeay32 -lssleay32 }
文件目录如下
rsa.h
#ifndef RSA_H #define RSA_H #include <QString> #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h> #define BEGIN_RSA_PUBLIC_KEY "BEGIN RSA PUBLIC KEY" #define BEGIN_RSA_PRIVATE_KEY "BEGIN RSA PRIVATE KEY" #define BEGIN_PUBLIC_KEY "BEGIN PUBLIC KEY" #define BEGIN_PRIVATE_KEY "BEGIN PRIVATE KEY" #define KEY_LENGTH 1024 class rsa { public: rsa(); ~rsa(); bool createRSAKey(QString &strPubKey, QString &strPriKey); QString rsaPriEncrypt(const QString &strPlainData, const QString &strPriKey); QString rsaPubDecrypt(const QString &strDecryptData, const QString &strPubKey); QString rsaPubEncrypt(const QString &strPlainData, const QString &strPubKey); QString rsaPriDecrypt(const QString &strDecryptData, const QString &strPriKey); QString rsaPriDecryptHex(const QString &strDecryptData, const QString &strPriKey); }; #endif // RSA_H
rsa.cpp
#include <QDebug> #include "rsa.h" #define myDebugMsg(msg) qDebug()<<QString("[Debug] File:%1 Line:%2 Function:%3 Msg:%4").arg(__FILE__).arg(__LINE__).arg(__FUNCTION__).arg(msg) #define myDebug qDebug()<<QString("[Debug] File:%1 Line:%2 Function:%3").arg(__FILE__).arg(__LINE__).arg(__FUNCTION__) rsa::rsa() { } rsa::~rsa() { } bool rsa::createRSAKey(QString &strPubKey, QString &strPriKey) { RSA *pRsa = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL); 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()); PEM_write_bio_RSAPublicKey(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 rsa::rsaPriEncrypt(const QString &strPlainData, const QString &strPriKey) { 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 (strPriKey.contains(BEGIN_RSA_PRIVATE_KEY)) { // pRsa = PEM_read_bio_RSAPrivateKey(pKeyBio, &pRsa, NULL, NULL); // } // else { // pRsa = PEM_read_bio_RSA_PRIVATE(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 plainDataArry = strPlainData.toUtf8(); int nPlainDataLen = plainDataArry.length(); uchar* pPlainData = (uchar*)plainDataArry.data(); int nSize = RSA_private_encrypt(nPlainDataLen, pPlainData, (uchar*)pEncryptBuf, pRsa, RSA_PKCS1_PADDING); QString strEncryptData = ""; if (nSize >= 0) { QByteArray arry(pEncryptBuf, nSize); strEncryptData = arry.toBase64(); } //释放内存 delete pEncryptBuf; BIO_free_all(pKeyBio); RSA_free(pRsa); return strEncryptData; } QString rsa::rsaPubDecrypt(const QString &strDecryptData, const QString &strPubKey) { QByteArray pubKeyArry = strPubKey.toUtf8(); uchar* pPubKey = (uchar*)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) { BIO_free_all(pKeyBio); return ""; } int nLen = RSA_size(pRsa); char* pPlainBuf = new char[nLen]; memset(pPlainBuf, 0, nLen); //解密 QByteArray decryptDataArry = strDecryptData.toUtf8(); decryptDataArry = QByteArray::fromBase64(decryptDataArry); int nDecryptDataLen = decryptDataArry.length(); uchar* pDecryptData = (uchar*)decryptDataArry.data(); int nSize = RSA_public_decrypt(nDecryptDataLen, pDecryptData, (uchar*)pPlainBuf, pRsa, RSA_PKCS1_PADDING); QString strPlainData = ""; if (nSize >= 0) { strPlainData = QByteArray(pPlainBuf, nSize); } //释放内存 delete pPlainBuf; BIO_free_all(pKeyBio); RSA_free(pRsa); return strPlainData; } QString rsa::rsaPubEncrypt(const QString &strPlainData, const QString &strPubKey) { QByteArray pubKeyArry = strPubKey.toUtf8(); uchar* pPubKey = (uchar*)pubKeyArry.data(); BIO* pKeyBio = BIO_new_mem_buf(pPubKey, pubKeyArry.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) { BIO_free_all(pKeyBio); return ""; } int nLen = RSA_size(pRsa); char* pEncryptBuf = new char[nLen]; memset(pEncryptBuf, 0, nLen); //加密 QByteArray plainDataArry = strPlainData.toUtf8(); int nPlainDataLen = plainDataArry.length(); uchar* pPlainData = (uchar*)plainDataArry.data(); int nSize = RSA_public_encrypt(nPlainDataLen, pPlainData, (uchar*)pEncryptBuf, pRsa, RSA_PKCS1_PADDING); QString strEncryptData = ""; if (nSize >= 0) { QByteArray arry(pEncryptBuf, nSize); strEncryptData = arry.toBase64(); } //释放内存 delete pEncryptBuf; BIO_free_all(pKeyBio); RSA_free(pRsa); return strEncryptData; } QString rsa::rsaPriDecrypt(const QString &strDecryptData, const QString &strPriKey) { 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* pPlainBuf = new char[nLen]; memset(pPlainBuf, 0, nLen); //解密 QByteArray decryptDataArry = strDecryptData.toUtf8(); decryptDataArry = QByteArray::fromBase64(decryptDataArry); int nDecryptDataLen = decryptDataArry.length(); uchar* pDecryptData = (uchar*)decryptDataArry.data(); int nSize = RSA_private_decrypt(nDecryptDataLen, pDecryptData, (uchar*)pPlainBuf, pRsa, RSA_PKCS1_PADDING); QString strPlainData = ""; if (nSize >= 0) { strPlainData = QByteArray(pPlainBuf, nSize); } //释放内存 delete pPlainBuf; BIO_free_all(pKeyBio); RSA_free(pRsa); return strPlainData; } QString rsa::rsaPriDecryptHex(const QString &strDecryptData, const QString &strPriKey) { 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* pPlainBuf = new char[nLen]; memset(pPlainBuf, 0, nLen); //解密 // QByteArray decryptDataArry = strDecryptData.toUtf8(); // decryptDataArry = QByteArray::fromBase64(decryptDataArry); // int nDecryptDataLen = decryptDataArry.length(); // uchar* pDecryptData = (uchar*)decryptDataArry.data(); unsigned char pDecryptData[1024] = {0}; for(int i=0;i<strDecryptData.length()/2;i++){ pDecryptData[i] = strDecryptData.mid(2*i,2).toUInt(Q_NULLPTR,16);} int nDecryptDataLen = strDecryptData.length()/2; int nSize = RSA_private_decrypt(nDecryptDataLen, pDecryptData, (uchar*)pPlainBuf, pRsa, RSA_PKCS1_PADDING); QString strPlainData = ""; if (nSize >= 0) { strPlainData = QByteArray(pPlainBuf, nSize); } //释放内存 delete pPlainBuf; BIO_free_all(pKeyBio); RSA_free(pRsa); return strPlainData; }
使用如下
#include "rsa.h"
{ QString strPlainData_before = "123456"; QString strPubKey = ""; QString strPriKey = ""; QString strEncryptData = ""; QString strPlainData = ""; strPubKey = ui->data_rsa_publickey->toPlainText(); strPriKey = ui->data_rsa_privatekey->toPlainText(); myDebugMsg(strPubKey); myDebugMsg(strPriKey); strEncryptData = m_rsa->rsaPubEncrypt(strPlainData_before,strPubKey); myDebugMsg("strEncryptData:"+strEncryptData); strPlainData = m_rsa->rsaPriDecrypt(strEncryptData, strPriKey); myDebugMsg("strPlainData:"+strPlainData); myDebugMsg("data:"+data); //QTimer::singleShot(3000, [=](){ } ); }
// 另一个方法
QString strPriKey = ui->data_rsa_privatekey->toPlainText(); QString strPlainData = m_rsa->rsaPriDecryptHex(strEncryptData, strPriKey); myDebugMsg("strEncryptData:"+strEncryptData); myDebugMsg("strPlainData:"+strPlainData); if(ui->data_rsa->text()==strPlainData){alarmInfo(-11);} else{alarmInfo(-12);}
注意公钥加密,私钥解密 或者 私钥解密 公钥加密
最后附赠上openssl已经打包好的动态库
https://files-cdn.cnblogs.com/files/RYSBlog/openssl%E5%8A%A8%E6%80%81%E5%BA%93.zip
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?