背景介绍:RSA加密一般使用的padding标准有NoPPadding、OAEPPadding、PKCS1Padding等,其中PKCS#1建议的padding就占用了11个字节。128字节(1024bits)-减去11字节正好是117字节,但对于RSA加密来讲,padding也是参与加密的,所以,依然按照1024bits去理解,但实际的明文只有117字节了。即RSA加密算法存在加密数据限制问题(即使用非对称密钥加密数据时,一次加密的数据长度是(密钥长度/8-11)),key的长度为2048位时,2048/8 - 11 = 245,一次加密内容不能超过245bytes。
当使用2048bits的来加密长度不受限制的明文时就需要采用分段加密,然后分段解密的方式来完成。以2048的为例,先取前245(不足245取实际大小)来进行RSA加密,然后base64编码,再连上一个特殊的字符串进行分段标记,接收端在收到密文后先按照事先约定的分段标记进行切割成数组,再循环数组逐一解密即可。代码如下:
/**
* @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 pdBlock = nLen - 11;
int nCount = (nClearDataLen / pdBlock) + 1;//分段次数
QString strEncryptData = "";
for(int i = 0; i <nCount; i++)
{
int nSize = 0;
pdBlock = (nClearDataLen > pdBlock)?pdBlock:nClearDataLen;
nSize = RSA_public_encrypt(pdBlock, pClearData, (uchar*)pEncryptBuf, pRsa, RSA_PKCS1_PADDING);
pClearData += pdBlock;
nClearDataLen -= pdBlock;
if ( nSize >= 0 )
{
QByteArray arry(pEncryptBuf, nSize);
strEncryptData.append(arry.toBase64());
strEncryptData.append("CSDN");//特殊标志位
}
}
// 释放内存
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 "";
}
//解密
QString strClearData = "";
int iStep = strDecryptData.indexOf("CSDN") + 4;//特殊标志位分割密文然后解密
int nCount = strDecryptData.size() / iStep;
int nSize = 0;
qDebug()<<nCount;
for(int i = 0; i < nCount; i++)
{
char* pClearBuf = new char[256];
memset(pClearBuf, 0, 256);
int start = i * iStep;
QByteArray decryptDataArry = strDecryptData.mid(start, iStep-4).toUtf8();
decryptDataArry = QByteArray::fromBase64(decryptDataArry);
nSize = RSA_private_decrypt(256, (uchar*)decryptDataArry.data(), (uchar*)pClearBuf, pRsa, RSA_PKCS1_PADDING);
if ( nSize >= 0 )
{
strClearData.append(QByteArray(pClearBuf, nSize));
}
delete pClearBuf;
}
// 释放内存
BIO_free_all(pKeyBio);
RSA_free(pRsa);
return strClearData;
}