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

时间:2014-04-14 06:55:14

标签: c++ encryption crypto++

我之前在我的程序中成功使用了这几行:

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专业版。

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

现在我认为这很容易解决。

3 个答案:

答案 0 :(得分:3)

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

以下是使用RSA的Crypto ++ wiki的示例。但是,您可以将代码用于符合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,
    ...

答案 1 :(得分:0)

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

我可以通过省略 BER Decode errorencoder1.MessageEnd来哄骗encoder2.MessageEnd。显然,我能够在完全写入之前阅读密钥。我假设它在离开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;
}

答案 2 :(得分:0)

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

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

我使用:http://www.cryptopp.com/wiki/Elliptic_Curve_Integrated_Encryption_Scheme

成功地使用Crypto ++完成了这项工作

感谢 jww 指出正确的决定。