解密图像与原始图像不同

时间:2016-01-22 09:58:02

标签: c++ qt crypto++

我刚开始研究cryptopp库。我有一个图像缓冲区,我想用一些密钥加密,然后解密但面临问题,解密和原始图像不相同。 我不确定加密天气问题是否可以帮助我解决这个问题。

使用qt creator

代码:

AutoSeededRandomPool prng;

SecByteBlock key(AES::DEFAULT_KEYLENGTH);
prng.GenerateBlock( key, key.size() );

byte ctr[ AES::BLOCKSIZE ];
prng.GenerateBlock( ctr, sizeof(ctr) );

string cipher, encoded, recovered;

QFile file("original.png");
if(!file.open(QIODevice::ReadOnly)){
    cout << "could not open the file"<< endl;
}

QByteArray buffer = file.readAll();

qDebug()<<"buffer length"<<buffer.length();

file.close();

try
{
    CTR_Mode< AES >::Encryption e;
    e.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );

    StringSource ss1( buffer, true,
                      new StreamTransformationFilter( e,
                                                      new StringSink( cipher )
                                                      )
                      );

}
catch( CryptoPP::Exception& e )
{
    cerr << e.what() << endl;
    exit(1);
}

qDebug()<<"cipher length "<<cipher.length();

try
{
    CTR_Mode< AES >::Decryption d;
    d.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
    StringSource ss3( cipher, true,
                      new StreamTransformationFilter( d,
                                                      new StringSink( recovered )
                                                      )
                      );

}
catch( CryptoPP::Exception& e )
{
    cerr << e.what() << endl;
    exit(1);
}

qDebug()<<"recovered length "<<recovered.length();
QFile ouput("recovered.png");
if(ouput.open(QIODevice::WriteOnly)){
    ouput.write(recovered.data(), recovered.size());
    ouput.close();
}

响应:

buffer length 538770
cipher length  8
recovered length  8

为什么我的密码长度仅为8。

3 个答案:

答案 0 :(得分:2)

QFile ouput("recovered.png");
if(ouput.open(QIODevice::WriteOnly)){
    ouput.write(recovered.c_str());
    ouput.close();
}

让我把我扔进锅里......你把二进制数据当作一个C-String,这意味着读/写在第一个NULL字符处停止。您应该使用带有指针和大小的重载。也许是这样的:

ouput.write(recovered.data(), recovered.size());

(代码编辑后)

QByteArray buffer = file.readAll();
...
StringSource ss1( buffer, true, ...);

这可能不会产生预期的结果。也许你应该尝试:

QByteArray buffer = file.readAll();
...
StringSource ss1( buffer.data(), buffer.size(), true, ...);

以上 StringSource 重载,带有 指针 尺寸 ,是您在这种情况下应该选择的尺寸。它是为其设计的确切案例,它保存了 buffer 的额外副本。

您甚至可以使用 FileSource FileSink` 与Crypto ++集成::

FileSource ifile("original.png", true,
                     new StreamTransformationFilter(e,
                         new StringSink( cipher )
                     )
                 );

另外,巴马克的说法是正确的:

  

在你的情况下,你称之为ctr,但它似乎未初始化......

虽然它未初始化,但是相同的[未知]值用于加密和解密,因此问题没有显示出来。它会在稍后出现,就像你在一台机器上加密并在另一台机器上解密一样。

您应该按照巴马克的建议进行初始化。也许是这样的:

byte ctr[16];
OS_GenerateRandomBlock(false, ctr, sizeof(ctr));

OS_GenerateRandomBlockRandomNumberGenerator上的Crypto ++ wiki上进行了讨论。

您通常可以在明文中发送带有消息的计数器,因为它通常被视为公共值。但这实际上取决于您的安全模型。

请确保 从不 在计数器模式下重复使用安全上下文。每条消息都必须在唯一的安全上下文中加密。安全上下文是 {key,ctr} 对。

您也可以使用以下方式打印计数器:

byte ctr[16];
OS_GenerateRandomBlock(false, ctr, sizeof(ctr));

HexEncoder encoder(new FileSink(cout));

cout << "Counter: ";
encoder.Put(ctr, sizeof(ctr));
encoder.MessageEnd();
cout << endl;

上面的代码只是对原始字节数组进行十六进制编码,然后将其打印到 stdout

  

(评论)string key = "7D9BB722DA2DC8674E08C3D44AAE976F"; - 你可能想要一个二进制字符串;不是ASCII字符串。对于Crypto ++,请参阅Crypto ++ wiki上的HexDecoder。我不确定QT为这项服务提供什么。

因为这里有更多空间......这是你可以做的事情之一:

string key, encodedKey = "7D9BB722DA2DC8674E08C3D44AAE976F";
StringSource ss(encodedKey, true, new HexDecoder(key));

执行语句后,字符串 key 将为二进制数据。

答案 1 :(得分:1)

在您的代码中,您将文件内容转换为Base64, 对其进行加密,解密并将其保存到文件中(从而将png文件另存为Base64)

您应该加密原始文件数据(而不是Base64编码的数据)。

编辑:编辑后我不知道失败了什么。请尝试以下功能,这对我有用。使用FileSourceFileSink,但应相应地使用StringSource和StringSink。

bool encryptdecrypt(const std::string& filename)
{
    std::string key = "7D9BB722DA2DC8674E08C3D44AAE976F";
    byte ctr[ CryptoPP::AES::BLOCKSIZE ];
    std::string cipher;

    try
    {
        CryptoPP::CTR_Mode< CryptoPP::AES >::Encryption e;
        e.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );

        CryptoPP::FileSource( filename.c_str(), true,
            new CryptoPP::StreamTransformationFilter( e,
                new CryptoPP::StringSink( cipher )
            )
        );

    }
    catch( CryptoPP::Exception& e )
    {
        std::cerr << e.what() << std::endl;
        return false;
    }

    try
    {
        CryptoPP::CTR_Mode< CryptoPP::AES >::Decryption d;
        d.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
        CryptoPP::StringSource( cipher, true,
            new CryptoPP::StreamTransformationFilter( d,
                new CryptoPP::FileSink( ( "decrypted_" + filename ).c_str() )
            )
        );

    }
    catch( CryptoPP::Exception& e )
    {
        std::cerr << e.what() << std::endl;
        return false;
    }
    return true;
}

答案 2 :(得分:1)

我发现了QByteArray缓冲区的问题。我刚刚转换为std :: string工作。

QByteArray buffer = file.readAll();

// string
std::string stdString(buffer.data(), buffer.length());

//used stdString instead of buffer in pipeline
StringSource ss1(stdString, true,
                              new StreamTransformationFilter( e,
                                                              new StringSink( cipher )
                                                              )
                              );