You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Crypto++ RSA加密长字符串报消息长度超过公钥最大值问题求解

问题原因

RSA作为非对称加密算法,受填充规则限制天然无法直接加密超过密钥长度对应阈值的明文:3072位RSA使用OAEP-SHA1填充时,最大可加密明文长度就是342字节,这是算法特性不是库的bug。

常见的三种解决方案中,前两种都有明显缺陷:

  • 增大密钥长度会让加解密性能指数级下降,4096位RSA的性能仅为3072位的一半不到,且依然有明文长度上限
  • 手动切分明文加密的方案存在安全漏洞,还会大幅提升编码复杂度

最优的第三种方案就是行业通用的混合加密(数字信封)方案,Crypto++原生支持该模式的实现,不需要手动切分明文,可直接处理任意长度的字符串、文件数据。

修正后的可运行代码
#include <string>
#include <cryptlib.h>
#include <rsa.h>
#include <osrng.h>
#include <iostream>
#include <files.h>
#include <aes.h>
#include <gcm.h>
using namespace std;
using namespace CryptoPP;

void encryptLongText(const string& plain, const RSA::PublicKey& pubKey, string& cipherOut) {
    AutoSeededRandomPool rng;
    // 生成随机AES密钥和IV
    SecByteBlock aesKey(AES::DEFAULT_KEYLENGTH);
    SecByteBlock iv(AES::BLOCKSIZE);
    rng.GenerateBlock(aesKey, aesKey.size());
    rng.GenerateBlock(iv, iv.size());
    
    // 用RSA加密AES密钥
    string encryptedAesKey;
    RSAES_OAEP_SHA_Encryptor e(pubKey);
    StringSource ss1(aesKey, aesKey.size(), true,
        new PK_EncryptorFilter(rng, e,
            new StringSink(encryptedAesKey)
        )
    );
    
    // 用AES-GCM加密长明文
    string encryptedPlain;
    GCM<AES>::Encryption aesEnc;
    aesEnc.SetKeyWithIV(aesKey, aesKey.size(), iv, iv.size());
    StringSource ss2(plain, true,
        new AuthenticatedEncryptionFilter(aesEnc,
            new StringSink(encryptedPlain)
        )
    );
    
    // 拼接结果:加密后的AES密钥长度 + 加密后的AES密钥 + IV + 密文
    cipherOut.append((char*)&encryptedAesKey.size(), sizeof(size_t));
    cipherOut.append(encryptedAesKey);
    cipherOut.append((const char*)iv, iv.size());
    cipherOut.append(encryptedPlain);
}

void decryptLongText(const string& cipherIn, const RSA::PrivateKey& privKey, string& plainOut) {
    AutoSeededRandomPool rng;
    size_t offset = 0;
    // 读取加密后的AES密钥长度
    size_t encryptedAesKeyLen = *(size_t*)(cipherIn.data() + offset);
    offset += sizeof(size_t);
    // 读取加密后的AES密钥
    string encryptedAesKey = cipherIn.substr(offset, encryptedAesKeyLen);
    offset += encryptedAesKeyLen;
    // 读取IV
    SecByteBlock iv(AES::BLOCKSIZE);
    memcpy(iv, cipherIn.data() + offset, AES::BLOCKSIZE);
    offset += AES::BLOCKSIZE;
    // 读取密文
    string encryptedPlain = cipherIn.substr(offset);
    
    // 解密得到AES密钥
    SecByteBlock aesKey(AES::DEFAULT_KEYLENGTH);
    RSAES_OAEP_SHA_Decryptor d(privKey);
    StringSource ss1(encryptedAesKey, true,
        new PK_DecryptorFilter(rng, d,
            new ArraySink(aesKey, aesKey.size())
        )
    );
    
    // 用AES解密得到明文
    GCM<AES>::Decryption aesDec;
    aesDec.SetKeyWithIV(aesKey, aesKey.size(), iv, iv.size());
    StringSource ss2(encryptedPlain, true,
        new AuthenticatedDecryptionFilter(aesDec,
            new StringSink(plainOut)
        )
    );
}

void b(string plain){
    AutoSeededRandomPool rng;
    InvertibleRSAFunction params;
    params.GenerateRandomWithKeySize(rng, 3072);
    RSA::PrivateKey privateKey(params);
    RSA::PublicKey publicKey(params);
    std::string cipher, recovered;
    
    encryptLongText(plain, publicKey, cipher);
    decryptLongText(cipher, privateKey, recovered);

    std::cout << "恢复的明文长度:" << recovered.length() << std::endl;
    std::cout << "恢复的明文前10位:" << recovered.substr(0, 10) << std::endl;
}

int main(){
    string plain;
    for(int i=0;i<1000;++i){
        plain.push_back('A');
    }
    b(plain);
}
方案说明
  • 该实现完全复用了原有RSA密钥生成逻辑,只新增了对称加密处理层,符合Crypto++的官方最佳实践
  • 可处理任意长度的明文,没有342字节的上限限制,同时性能远高于切分RSA加密、增大密钥长度的方案
  • 额外增加了GCM认证加密能力,可自动校验密文是否被篡改,安全性更高

内容的提问来源于stack exchange,提问作者user1407220

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 20:15:00