不受秘钥长度限制RSA加密

背景介绍: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;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值