【问题标题】:Crash when trying to encrypt a file with Crypto++ RSA Scheme尝试使用 Crypto++ RSA 方案加密文件时崩溃
【发布时间】:2018-03-11 00:03:22
【问题描述】:

我已经在我的程序中成功使用了这几行代码:

string tmp;
    StringSource(msg, true, new PK_EncryptorFilter(*rng, *encryptor, new CryptoPP::HexEncoder(new StringSink(tmp))));
    return tmp;

所以你知道 Crypto++ 对象是很好创建的等等。

现在我想加密整个二进制文件并将其保存到相邻的文件中:

FileSource(file.c_str(), true, new PK_EncryptorFilter(*rng, *encryptor, new FileSink((file+".xx").c_str(), true)),true);

但是最后一行崩溃并显示调试错误,指出 abort() 已被调用

寻找错误,我尝试将 FileSource 调用的第二个参数更改为 false,导致以下代码:

FileSource(file.c_str(), false, new PK_EncryptorFilter(*rng, *encryptor, new FileSink((file+".xx").c_str(), true)),true);

然后错误消失了,但目标文件的权重为 0 字节,没有读取/写入任何内容。

不知道有什么可以解决问题的关键,所以,希望有人能帮忙一点。

编辑:我正在使用 Visual Studio 2013 Pro。

EDIT2:我进一步寻找错误。

这有效,文件二进制内容正确打印在屏幕上:

string s;
FileSource file2("C:\\test.jpg", true, new StringSink(s));
std::cout << s << std::endl;

但这不起作用并以提到的崩溃结束。

string s;
FileSource file2("C:\\test.jpg", true, new PK_EncryptorFilter(*rng, *encryptor, new StringSink (s)));
std::cout << s << std::endl;

这很奇怪,因为正如我在帖子开头所说的那样,在另一种方法中使用相同的 PK_EncryptorFilter 过滤器没有问题。

无论如何,我把我的整个班级都贴在这里,以便清楚地了解发生了什么:

RSASystem::RSASystem()
{
    std::string pubkey = "...OMITED...";

    rng = new AutoSeededRandomPool;

    CryptoPP::HexDecoder decoder;
    decoder.Put((byte*)pubkey.c_str(), pubkey.size());
    decoder.MessageEnd();

    CryptoPP::HexDecoder decoder2;
    decoder2.Put((byte*)pubkey.c_str(), pubkey.size());
    decoder2.MessageEnd();

    verifier = new RSASSA_PKCS1v15_SHA_Verifier;
    encryptor = new RSAES_OAEP_SHA_Encryptor;

    verifier->AccessKey().Load(decoder);
    encryptor->AccessKey().Load(decoder2);
}

string RSASystem::encrypt(string msg)
{
    string tmp;
    StringSource(msg, true, new PK_EncryptorFilter(*rng, *encryptor, new CryptoPP::HexEncoder(new StringSink(tmp))));
    return tmp;
}

void RSASystem::encryptFile(string file)
{
    FileSource(file.c_str(), true, new PK_EncryptorFilter(*rng, *encryptor, new FileSink((file+".xx").c_str(), true)),true);
}

编辑 3:用 try..catch() 包围代码后,出现此错误:

RSA/OAEP-MGF1(SHA-1): message length of 490986 exceeds the maximum of 214 for this public key

现在我认为很容易解决。

【问题讨论】:

  • 你能得到 Crypto++ wiki 上提供的示例代码吗? (我想知道它是否是图书馆的问题,维基代码应该是好的)。
  • 我会在几个小时内尝试一下,或者,我现在不在家...
  • 我现在知道这不是安慰,但你已经接近解决这个问题了,因为它只是源和汇之间的区别。这可能是路径或文件名问题。一定要抓住CryptoPP::Exception,看看会发生什么。
  • 好的,用 try..catch() 包围代码我明白了:RSA/OAEP-MGF1(SHA-1): message length of 490986 exceeds the maximum of 214 for this public key 终于有道理了。我该如何解决这个问题?
  • 甚至不用理会上面的(2)或security.stackexchange.com/questions/44702/…。只需使用 ECIES 或 DLIES/DHAES 等集成加密方案。集成方案使用公钥加密,利用对称批量加密并提供身份验证标签。因为身份验证标签内置在方案中,您将不需要需要单独的签名者。

标签: c++ encryption crypto++


【解决方案1】:
FileSource(file.c_str(), false,
    new PK_EncryptorFilter(*rng, *encryptor,
        new FileSink((file+".xx").c_str(), true)
    ),
true);

这看起来不对。 new FileSink((file+".xx").c_str() 返回一个char*,你需要一个指向Sink的指针。另外,还有一个我不习惯看到的额外错误。比如:

FileSource fs1(filename, true,
    new PK_EncryptorFilter(rng, encryptor,
        new FileSink(filename, true)
   ) // PK_EncryptorFilter
); // StringSource

Crypto++ wiki 上有几个示例。请参阅RSA CryptographyRSA Encryption Schemes

以下是 Crypto++ wiki 中使用 RSA 的示例。但是您可以将代码用于任何遵循PK_EncryptorPK_DecryptorSources(如StringSourceFileSource)和Sinks(如StringSinkFileSink)的密码系统也可以互换):

////////////////////////////////////////////////
// Generate keys
AutoSeededRandomPool rng;

InvertibleRSAFunction params;
params.GenerateRandomWithKeySize( rng, 1536 );

RSA::PrivateKey privateKey( params );
RSA::PublicKey publicKey( params );

string plain="RSA Encryption", cipher, recovered;

////////////////////////////////////////////////
// Encryption
RSAES_OAEP_SHA_Encryptor e( publicKey );

StringSource ss1( plain, true,
    new PK_EncryptorFilter( rng, e,
        new StringSink( cipher )
    ) // PK_EncryptorFilter
 ); // StringSource

////////////////////////////////////////////////
// Decryption
RSAES_OAEP_SHA_Decryptor d( privateKey );

StringSource ss2( cipher, true,
    new PK_DecryptorFilter( rng, d,
        new StringSink( recovered )
    ) // PK_DecryptorFilter
 ); // StringSource

assert( plain == recovered );

另外,不要使用匿名声明。某些版本的 GCC 存在问题。也就是说,使用:

StringSource ss1( plain, true,
    ...

而不是:

StringSource( plain, true,
    ...

【讨论】:

  • 我不同意你的观点,new FileSink((file+".xx").c_str(), true) 返回一个指向接收器的指针。与您的代码相同,但将 filename 替换为 (file+".xx").c_str()。如果我错了,请纠正我。
  • @Dark_eye - 是的,你是对的。我的错。我击中了它。谢谢。
  • 我看到你的编辑太晚了。 false 被设置为尝试减轻错误,但随后没有从文件中提取任何数据。从文档中读取的内容似乎是合乎逻辑的。 cryptopp.com/wiki/User_Guide:_filters.h
  • 对。第一个错误是pumpAll。如果它是假的,那么没有数据被抽取。你的问题在别处。您还可以包含EncryptorDecryptor 对象吗?另外,你是否捕捉到 Crypto++ 异常? abort 可能是未捕获的异常。最后,key 加载后是否生效?
  • 正如我一开始所说的,字符串加密和验证完美无缺,因为它们在程序的早期实现。文件处理似乎有些麻烦。
【解决方案2】:

我已经在等待加密和安全主题,所以我不知道 RSA 方案对消息长度的限制。 https://security.stackexchange.com/questions/44702/whats-the-limit-on-the-size-of-the-data-that-public-key-cryptos-can-handle

因此,解决方案通过实施集成或混合加密方案(如 ECIES)而通过。

我已经使用 Crypto++ 成功完成了这项工作:http://www.cryptopp.com/wiki/Elliptic_Curve_Integrated_Encryption_Scheme

感谢jww指出正确的决定。

【讨论】:

    【解决方案3】:

    好的,我想我知道您可能在哪里遇到问题。但我需要查看所有您的代码,而不仅仅是加密。

    我可以通过省略encoder1.MessageEndencoder2.MessageEnd 来哄BER Decode error。显然,我能够在完全写入之前读取密钥。我认为它是在离开 main(并且析构函数运行)后完全编写的,因为 ls 的文件大小看起来不错。

    在下面的代码中,消息在publicKey1 下加密,然后用privateKey2 解密,以确保密钥是往返的。

    try {
    
        ////////////////////////////////////////////////
        // Generate keys
        AutoSeededRandomPool rng;
    
        InvertibleRSAFunction params;
        params.GenerateRandomWithKeySize(rng, 1024);
    
        RSA::PrivateKey privateKey1(params);
        RSA::PublicKey publicKey1(privateKey1);
    
        ////////////////////////////////////////////////
        // Save/Load keys  
        HexEncoder encoder1(new FileSink("private-key-der.txt", true));
        HexEncoder encoder2(new FileSink("public-key-der.txt", true));
    
        privateKey1.Save(encoder1);
        publicKey1.Save(encoder2);
    
        // Must have these. Otherwise, the full key (hex encoded)
        //   is not written until destructors are run
        encoder1.MessageEnd();
        encoder2.MessageEnd();
    
        FileSource fs1("private-key-der.txt", true, new HexDecoder);
        FileSource fs2("public-key-der.txt", true, new HexDecoder);
    
        RSA::PrivateKey privateKey2;
        RSA::PublicKey publicKey2;
    
        privateKey2.Load(fs1);
        bool valid = privateKey2.Validate(rng, 3);
        if(!valid)
            throw Exception(Exception::OTHER_ERROR, "Failed to validate key 1");
    
        publicKey2.Load(fs2);
        valid = publicKey2.Validate(rng, 3);
        if(!valid)
            throw Exception(Exception::OTHER_ERROR, "Failed to validate key 2");
    
        ////////////////////////////////////////////////
        // Scratch
        string plain="RSA Encryption", cipher, recovered;
    
        ////////////////////////////////////////////////
        // Encryption
        RSAES_OAEP_SHA_Encryptor encryptor(publicKey1);
    
        StringSource ss1(plain, true,
                         new PK_EncryptorFilter(rng, encryptor,
                                                new StringSink(cipher)
                                                ) // PK_EncryptorFilter
                         ); // StringSource
    
        ////////////////////////////////////////////////
        // Decryption
        RSAES_OAEP_SHA_Decryptor decryptor(privateKey2);
    
        StringSource ss2(cipher, true,
                         new PK_DecryptorFilter(rng, decryptor,
                                                new StringSink(recovered)
                                                ) // PK_DecryptorFilter
                         ); // StringSource
    
        cout << "Recovered plain text: " << recovered << endl;
    
    } catch (const Exception& ex) {
        cerr << ex.what() << endl;
    }
    

    【讨论】:

    • 我确实调用了相应的 MessageEnd。如果您还记得第一篇文章:CryptoPP::HexDecoder decoder;decoder.Put((byte*)pubkey.c_str(), pubkey.size());decoder.MessageEnd();CryptoPP::HexDecoder decoder2;decoder2.Put((byte*)pubkey.c_str(), pubkey.size());decoder2.MessageEnd();
    • 但是你的代码有std::string pubkey = "...OMITED..."。所以可能会省略一些有趣的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-10
    • 1970-01-01
    • 2019-06-26
    • 2018-12-12
    • 2014-11-10
    • 2012-04-07
    • 1970-01-01
    相关资源
    最近更新 更多