最近在处理加密问题,需要用到数字签名,查询资料得知采用rsa加密基本安全。关于rsa加密算法,网络上关于这类说明比较多。其实关于C++ + openssl + rsa的相关代码比较多,要么要积分,要么写的不是qt方面的。今天抽空整理出qt + openssl + rsa相关加密函数及实现。
首先在实现功能的时候出现的一些问题及解决方法。
1、采用openssl-1_1_0h版本
2、qt pro文件中增加动态库关联,这里是把openssl安装文件中的include和lib文件拷贝至qt项目目录下。
INCLUDEPATH += ./include
LIBS += libcrypto.lib \
libssl.lib
3、openssl有两种生成key的方式,一种是通过openssl命令生成;一种是通过调用接口用代码生成。两者生成的私钥格式一致,
但是公钥格式存在区别,从而导致调用接口不一样。
代码生成的key标题为 -----BEGIN RSA PUBLIC KEY----- ,调用接口PEM_read_bio_RSAPublicKey;
命令生成的key标题为 -----BEGIN PUBLIC KEY----- ,调用接口 PEM_read_bio_RSA_PUBKEY
4、若通过命令生成的key,拷贝至项目中使用时,需要注意格式,标题和每一行后的换行(/n)必须都带上。
5、由于传输的key都是QString类型,需要转化为uchar*。
错误的方式: uchar* pPriKey = (uchar*)strPriKey.toUtf8().data();
正确的方式: QByteArray priKeyArry = strPriKey.toUtf8();
uchar* pPriKey = (uchar*)priKeyArry.data();
6、代码中为方便查看生成的key,统一都转化base64格式,但是在解密的时候需要转化为uchar*。
这里仅处理小于128字节的数据加密,后续把分片加密整理出来。
代码实现如下:
#include
#include
#include
#include
// define rsa public key
#define BEGIN_RSA_PUBLIC_KEY "BEGIN RSA PUBLIC KEY"
#define BEGIN_PUBLIC_KEY "BEGIN PUBLIC KEY"
#define KEY_LENGTH 1024 // 密钥长度
class rsa
{
public:
/**
* @brief createRsaKey 生成秘钥对
* @param strPubKey 公钥
* @param strPriKey 私钥
* @return 状态
*/
static bool createRsaKey (QString& strPubKey, QString& strPriKey);
/**
* @brief rsa_pri_encrypt 私钥加密
* @param strClearData 明文
* @param strPriKey 私钥
* @return 加密后数据(base64格式)
*/
static QString rsa_pri_encrypt_base64 (const QString& strClearData, const QString& strPriKey);
/**
* @brief rsa_pub_decrypt 公钥解密
* @param strDecrypt 待解密数据(base64格式)
* @param strPubKey 公钥钥
* @return 明文
*/
static QString rsa_pub_decrypt_base64 (const QString& strDecryptData, const QString& strPubKey);
/**
* @brief rsa_pub_encrypt 公钥加密
* @param strClearData 明文
* @param strPubKey 私钥
* @return 加密后数据(base64格式)
*/
static QString rsa_pub_encrypt_base64 (const QString& strClearData, const QString& strPubKey);
/**
* @brief rsa_pri_decrypt 私钥解密
* @param strDecrypt 待解密数据(base64格式)
* @param strPriKey 私钥
* @return 明文
*/
static QString rsa_pri_decrypt_base64 (const QString& strDecryptData, const QString& strPriKey);
/**< 测试 */
static void test ();
};
#endif // RSA_H
#include "rsa.h"
/**
* @brief createRsaKey 生成秘钥对
* @param strPubKey 公钥
* @param strPriKey 私钥
* @return 成功状态
*/
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;
}
/**
* @brief rsa_pri_encrypt 私钥加密
* @param strClearData 明文
* @param strPriKey 私钥
* @return 加密后数据(base64格式)
*/
QString rsa::rsa_pri_encrypt_base64 (const QString& strClearData, 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 ( 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();
uchar* pClearData = (uchar*)clearDataArry.data();
int nSize = RSA_private_encrypt(nClearDataLen,
pClearData,
(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;
}
/**
* @brief rsa_pub_decrypt 公钥解密
* @param strDecrypt 待解密数据(base64格式)
* @param strPubKey 公钥
* @return 明文
*/
QString rsa::rsa_pub_decrypt_base64(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* 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();
int nSize = RSA_public_decrypt(nDecryptDataLen,
pDecryptData,
(uchar*)pClearBuf,
pRsa,
RSA_PKCS1_PADDING);
QString strClearData = "";
if ( nSize >= 0 ){
strClearData = QByteArray(pClearBuf, nSize);
}
// 释放内存
delete pClearBuf;
BIO_free_all(pKeyBio);
RSA_free(pRsa);
return strClearData;
}
/**
* @brief rsa_pub_encrypt 公钥加密
* @param strClearData 明文
* @param strPubKey 私钥
* @return 加密后数据(base64格式)
*/
QString rsa::rsa_pub_encrypt_base64 (const QString& strClearData, 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 clearDataArry = strClearData.toUtf8();
int nClearDataLen = clearDataArry.length();
uchar* pClearData = (uchar*)clearDataArry.data();
int nSize = RSA_public_encrypt(nClearDataLen,
pClearData,
(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;
}
/**
* @brief rsa_pri_decrypt 私钥解密
* @param strDecrypt 待解密数据(base64格式)
* @param strPriKey 私钥
* @return 明文
*/
QString rsa::rsa_pri_decrypt_base64(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* 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();
int nSize = RSA_private_decrypt(nDecryptDataLen,
pDecryptData,
(uchar*)pClearBuf,
pRsa,
RSA_PKCS1_PADDING);
QString strClearData = "";
if ( nSize >= 0 ){
strClearData = QByteArray(pClearBuf, nSize);
}
// 释放内存
delete pClearBuf;
BIO_free_all(pKeyBio);
RSA_free(pRsa);
return strClearData;
}
void rsa::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);
qDebug() << strPubKey << endl;
qDebug() << strPriKey << endl;
qDebug() << "private key encrypt, public key decrypt";
QString strClear = "hello";
QString strEncryptData = rsa_pri_encrypt_base64 (strClear, strPriKey);
qDebug() << strEncryptData;
QString strClearData = rsa_pub_decrypt_base64 (strEncryptData, strPubKey);
qDebug() << strClearData;
qDebug() << "public key encrypt, private key decrypt";
strEncryptData = rsa_pub_encrypt_base64 (strClear, strPubKey);
qDebug() << strEncryptData;
strClearData = rsa_pri_decrypt_base64 (strEncryptData, strPriKey);
qDebug() << strClearData;
}