简体   繁体   English

尝试使用Crypto ++ RSA Scheme加密文件时崩溃

[英]Crash when trying to encrypt a file with Crypto++ RSA Scheme

I have successfully used this some lines ago in my program: 我在我的程序中成功地使用了这几行:

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

So you know that the Crypto++ objects are well created and so. 所以你知道Crypto ++对象是很好的创建的。

Now I want to encrypt a whole binary file and save it to an adjacent file: 现在我想加密整个二进制文件并将其保存到相邻文件:

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

But this last line crashes with a debug error stating that abort() has been called . 但最后一行崩溃时出现调试错误,表明已调用abort()

Hunting down the error, I tried to change the second argument to the FileSource call to false, leading to the following code: 解决错误,我试图将FileSource调用的第二个参数更改为false,从而导致以下代码:

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

And then the error gone, but the destination file weights 0 bytes, nothing was read/wrote. 然后错误消失了,但目标文件加权0字节,没有读/写。

I do not know what can can the key to the problem, so, I hope someone can help a little bit. 我不知道问题的关键是什么,所以,我希望有人可以帮助一点点。

EDIT: I am using Visual Studio 2013 Pro. 编辑:我正在使用Visual Studio 2013 Pro。

EDIT2: I hunted the error further. 编辑2:我进一步追捕错误。

This works and the file binary content is correctly printed on screen: 这有效,文件二进制内容正确打印在屏幕上:

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

But this don't work and ends with the mentioned crash. 但这不起作用,并以提到的崩溃结束。

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

This is so strange since the same PK_EncryptorFilter filter is used in another method without trouble, as I stated at the beginning of the post. 这很奇怪,因为相同的PK_EncryptorFilter过滤器在另一种方法中使用没有问题,正如我在帖子开头所说的那样。

Anyway, I post here my entire class, so as to get a clear idea of what is going on: 无论如何,我在这里发布我的全班,以便清楚地知道发生了什么:

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);
}

EDIT 3: After surrounding the code with try..catch() I got this error: 编辑3:用try..catch()包围代码后,我收到此错误:

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

Which now I think can be easily solved. 现在我觉得这很容易解决。

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

This does not look right. 这看起来不对。 new FileSink((file+".xx").c_str() returns a char* , and you need a pointer to a Sink . Plus, there's an extra false in there I'm not used to seeing. Something like: new FileSink((file+".xx").c_str()返回一个 char* ,你需要一个指向 Sink的指针 。另外,还有一个额外的假,我不习惯看到。有点像:

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

There's a couple of examples on the Crypto++ wiki. Crypto ++ wiki上有几个例子。 See RSA Cryptography and RSA Encryption Schemes . 请参阅RSA加密RSA加密方案

The following is an example from the Crypto++ wiki using RSA. 以下是使用RSA的Crypto ++ wiki的示例。 But you can use the code for any cryptosystem that adheres to PK_Encryptor and PK_Decryptor ( Sources (like StringSource and FileSource ) and Sinks (like StringSink and FileSink ) are also interchangeable): 但您可以将代码用于任何符合PK_EncryptorPK_Decryptor密码系统( Sources (如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 );

Also, don't use anonymous declarations. 另外,不要使用匿名声明。 Some versions of GCC has problems with them. 某些版本的GCC存在问题。 That is, use: 也就是说,使用:

StringSource ss1( plain, true,
    ...

rather than: 而不是:

StringSource( plain, true,
    ...

OK, I think I know where you might be having problems. 好的,我想我知道你可能遇到问题的地方。 But I'd need to see all your code and not just the encryption. 但我需要查看所有代码,而不仅仅是加密。

I could coax a BER Decode error by omitting encoder1.MessageEnd and encoder2.MessageEnd . 我可以通过省略 encoder1.MessageEndencoder2.MessageEnd来哄骗BER Decode error Apparently, I was able to read the key before it was fully written. 显然,我能够在完全写入之前阅读密钥。 I assume it was fully written after leaving main (and the destructors ran) because the file sizes looked OK with ls . 我假设它在离开main (和析构函数运行)之后完全写入,因为文件大小看起来很好用ls

In the code below, the message was encrypted under publicKey1 and then decrypted with privateKey2 to ensure the keys were round-tripping. 在下面的代码中,消息在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;
}

I had already pending the encryption and security subject so I wasn't aware of the limitation on the length of the message of the RSA scheme. 我已经等待加密和安全主题,所以我不知道对RSA方案的消息长度的限制。 https://security.stackexchange.com/questions/44702/whats-the-limit-on-the-size-of-the-data-that-public-key-cryptos-can-handle https://security.stackexchange.com/questions/44702/whats-the-limit-on-the-size-of-the-data-that-public-key-cryptos-can-handle

So the solution passes by implementing an Integrated or Hybrid Encryption Scheme, like ECIES. 因此,解决方案通过实施集成或混合加密方案,如ECIES。

I've done this successfully with Crypto++ using: http://www.cryptopp.com/wiki/Elliptic_Curve_Integrated_Encryption_Scheme 我使用Crypto ++成功完成了这项工作: http//www.cryptopp.com/wiki/Elliptic_Curve_Integrated_Encryption_Scheme

Thanks to jww to point to the correct decision. 感谢jww指出正确的决定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM