执行 RSA 解密时密文无效

Invalid ciphertext when performing RSA decryption

我使用以下代码加密和解密一个使用 Crypto++ 5.6.2 库的字符串

string to_BER(string spriv,bool b)    
{
    string HEADER, FOOTER;

    if(b)
    {
        HEADER = "-----BEGIN RSA PRIVATE KEY-----";
        FOOTER = "-----END RSA PRIVATE KEY-----";
    }
    else
    {
        HEADER = "-----BEGIN PUBLIC KEY-----";
        FOOTER = "-----END PUBLIC KEY-----";
    }

        size_t pos1, pos2;
        pos1 = spriv.find(HEADER);
        if(pos1 == string::npos)
            throw std::runtime_error("PEM header not found");

        pos2 = spriv.find(FOOTER, pos1+1);
        if(pos2 == string::npos)
            throw std::runtime_error("PEM footer not found");

        // Start position and length
        pos1 = pos1 + HEADER.length();
        pos2 = pos2 - pos1;
        string keystr = spriv.substr(pos1, pos2);

        return keystr;
}

string rsa_encrypt(const string &message, const string &public_key)
{    
    string keystr=to_BER(public_key,false);

    ByteQueue queue;
    Base64Decoder decoder;

    decoder.Attach(new Redirector(queue));
    decoder.Put((const byte*)keystr.data(), keystr.length());
    decoder.MessageEnd();

    RSAES_PKCS1v15_Encryptor e;
    e.AccessKey().Load(queue);

    bool key_ok = e.AccessKey().Validate(rng, 3);
    if(!key_ok)
    {
        printf("ERROR IN RSA KEY\n");
        return "";
    }

    string encrypted_data;

    StringSource ss1(message, true,
        new PK_EncryptorFilter(rng, e,
            new StringSink(encrypted_data)
       ) // PK_EncryptorFilter
    ); // StringSource

    return encrypted_data;
}

string rsa_decrypt(const string &message, const string &private_key,bool b_Base64decode)
{
    string keystr=to_BER(private_key,true);

    string decoded=message;

    if(b_Base64decode)
    {
        Base64Decoder decoder;

        decoder.Put( (byte*)message.data(), message.size() );
        decoder.MessageEnd();

        word64 size = decoder.MaxRetrievable();
        if(size && size <= SIZE_MAX)
        {
            decoded.resize(size);
            decoder.Get((byte*)decoded.data(), decoded.size());
        }
    }  

    RSAES_PKCS1v15_Decryptor pri( rng, 1024 );
    TransparentFilter privSink( new StringSink(keystr) );
    pri.DEREncode( privSink );
    privSink.MessageEnd();            

    string decrypted_data;
    try
    {

    StringSource ss( decoded, true,
            new PK_DecryptorFilter( rng, pri, new StringSink( decrypted_data )));
    }
    catch(Exception *e)
    {
        printf("ERROR DECRYPTING RSA\n");
        return "";
    }   

    return decrypted_data;
}

然后我使用这个代码:

string enc=rsa_encrypt("hola mundo","-----BEGIN PUBLIC KEY----- MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAE= -----END PUBLIC KEY-----");

string aaa=rsa_decrypt(
            /*"YTbXg1K4OlXGY6eaLuVTFZrN4qi1zg83h0PjeLd9F3Ge3gKUHsJpoE3iLv1+Gj/PepM8ehiilb5kphxCdcELjaYH9wwYHMpUZUQSRLQUTnofOboI6nfHaKnnNV28QMguM39q1hm7X1wNc69D8R+CkWLka2rQof+BXt+41ivnMj8=",*/
            enc
            ,"-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAECgYBxFL9bVHNprz4PtK3bbc2K9qmv6gxpxx88Dp/hdtm8NfoG0uclNRHALZeRa1Yjwo+Y46zPAwPCDkpGbLC+5S9zfBjtrx/+8zjTyMVb2CcGLfR0H2E/hcCjADXNxs+fmpB3+jyPhgH5ANaTmAXqGXOP56I0Fqo8xCfU/zQELCtzMQJBAN2Kq+9bQW3nKAAJEZqWQlAEjuBQfe1lrvLxc/AgVl9XLWrHre7HSlkyqcFemvqhzlZy1wz0Nv5VpOIGcAKefEMCQQCD4xSbkF1kzZyj8k6P3iUW6ezaK4krOZnpq/wDyOtj0DBAtLt3apyv3BUbe7AH1e8llJ5a8UYVHlsOdRUio+m3AkAB0LYR8wR5OxCn12sughavAyqMifxOKqwhT3sst4cdpuA3ZMV3FGj2jCS58eWBMjw3lx9N+t5MfTUpqPXX/6ZzAkBx9eTXqv3YXYZtb7GMxQI9c3Jy7k1/aS1iaXbA+nrTa5BWSRT30cqEduJSNiVcD/KuAWZ35KWPGATMUEUsAoCvAkEAuVg0OA6L3xJphKEbVYXvTwXrXcoVjjLDnNYjUJuNWrFFjBuNE4whWvdg76Panw3vMhgFc6yVr+VE5XOc7rXPvA== -----END RSA PRIVATE KEY-----"
            ,false
            );

问题是 rsa_decrypt 失败并出现 "invalid ciphertext" 异常,try/catch 代码未捕获该异常。程序崩溃。 我想知道我的代码有什么问题,即使密文错误,如何避免程序崩溃。 我找到了类似的线程 (crypto++ RSA and "invalid ciphertext"),但 none 的解决方案对我有效:我没有发现字符串末尾的 0 有任何问题,我检查密钥是否有效,我知道私有密钥和 public 密钥来自同一密钥对,并且它们与其他 RSA 库一起使用。

这是崩溃的行:

StringSource ss( decoded, true,
                new PK_DecryptorFilter( rng, pri, new StringSink( decrypted_data )));

The problem is that rsa_decrypt fails with a "invalid ciphertext" exception

你创建一个new私钥,然后把它编码成keystr:

RSAES_PKCS1v15_Decryptor pri( rng, 1024 );
TransparentFilter privSink( new StringSink(keystr) );
pri.DEREncode( privSink );

相反,您应该使用 private_key(而不是新密钥)并像在加密器中那样做一些事情:

string keystr=to_BER(private_key,true);

ByteQueue queue;
Base64Decoder decoder;

decoder.Attach(new Redirector(queue));
decoder.Put((const byte*)keystr.data(), keystr.length());
decoder.MessageEnd();

RSAES_PKCS1v15_Decryptor d;
d.AccessKey().Load(queue);

... that isn't caught...

所有内容 包装在 try/catch 块中,而不仅仅是 PK_DecryptorFilter 调用。


您可以看到 public 和私钥之间的差异(或缺失),例如:

try {

    string s1("-----BEGIN PUBLIC KEY-----\n"
              "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHIiecdmRAai"
              "TrCbbEOLBPh+fxp2KyGWyMTeWIj56NRk1CFLfBDT6vOWDceF"
              "puTcrAFGR4Np4JLsssqM24F7bZCKv6eQCV8Xjv6GJiGofKEk"
              "I4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi96CHbg3foLQzZSS"
              "S9oFItGOFF0jDM7lAgMBAAE="
              "\n-----END PUBLIC KEY-----");
    string s2("-----BEGIN RSA PRIVATE KEY-----\n"
              "MIICWwIBAAKBgHIiecdmRAaiTrCbbEOLBPh+fxp2KyGWyMTeWIj"
              "56NRk1CFLfBDT6vOWDceFpuTcrAFGR4Np4JLsssqM24F7bZCKv6"
              "eQCV8Xjv6GJiGofKEkI4b0zwHHEwq63p+9Rb5jYXlPZ7JIud7Yi"
              "96CHbg3foLQzZSSS9oFItGOFF0jDM7lAgMBAAECgYBxFL9bVHNp"
              "rz4PtK3bbc2K9qmv6gxpxx88Dp/hdtm8NfoG0uclNRHALZeRa1Y"
              "jwo+Y46zPAwPCDkpGbLC+5S9zfBjtrx/+8zjTyMVb2CcGLfR0H2"
              "E/hcCjADXNxs+fmpB3+jyPhgH5ANaTmAXqGXOP56I0Fqo8xCfU/"
              "zQELCtzMQJBAN2Kq+9bQW3nKAAJEZqWQlAEjuBQfe1lrvLxc/Ag"
              "Vl9XLWrHre7HSlkyqcFemvqhzlZy1wz0Nv5VpOIGcAKefEMCQQC"
              "D4xSbkF1kzZyj8k6P3iUW6ezaK4krOZnpq/wDyOtj0DBAtLt3ap"
              "yv3BUbe7AH1e8llJ5a8UYVHlsOdRUio+m3AkAB0LYR8wR5OxCn1"
              "2sughavAyqMifxOKqwhT3sst4cdpuA3ZMV3FGj2jCS58eWBMjw3"
              "lx9N+t5MfTUpqPXX/6ZzAkBx9eTXqv3YXYZtb7GMxQI9c3Jy7k1"
              "/aS1iaXbA+nrTa5BWSRT30cqEduJSNiVcD/KuAWZ35KWPGATMUE"
              "UsAoCvAkEAuVg0OA6L3xJphKEbVYXvTwXrXcoVjjLDnNYjUJuNW"
              "rFFjBuNE4whWvdg76Panw3vMhgFc6yVr+VE5XOc7rXPvA=="
              "\n-----END RSA PRIVATE KEY-----");

    ArraySource as1(s1, true), as2(s2, true);

    RSA::PublicKey k1;
    RSA::PrivateKey k2;

    PEM_Load(as1, k1);
    PEM_Load(as2, k2);

    AutoSeededRandomPool prng;
    k1.ThrowIfInvalid(prng, 3);
    k2.ThrowIfInvalid(prng, 3);

    Integer i1 = k1.GetModulus() - k2.GetModulus();
    Integer i2 = k1.GetPublicExponent() - k2.GetPublicExponent();

    cout << i1 << " " << i2 << endl;

} catch (const Exception& ex) {
    cerr << ex.what() << endl;
}

相关,封装边界(-----BEGIN PUBLIC KEY----------END PUBLIC KEY-----)应该各占一行。您应该使用新行 (\n) 而不是 space。所以像:

string enc=rsa_encrypt(
    "hola mundo",
    "-----BEGIN PUBLIC KEY-----\nMIGeMA0G...gMBAAE=\n-----END PUBLIC KEY-----"
    );

并且:

string aaa=rsa_decrypt(
    enc,
    "-----BEGIN RSA PRIVATE KEY-----\nMIICWwIB...7rXPvA==\n-----END RSA PRIVATE KEY-----",
    false
    );

相关,你应该用RSAES_OAEP_SHA_EncryptorRSAES_OAEP_SHA_DecryptorA bad couple of years for the cryptographic token industry.

提供了一种可行的治疗方法