简体   繁体   中英

Decrypted image is not same as original image

I just started working on cryptopp library. I have a image buffer and i want to encrypt with some key and then decrypt later but facing issue, decrypted and original images are not same. I am not sure weather issue in encryption or not could some one help me out of this.

using qt creator

Code:

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

response:

buffer length 538770
cipher length  8
recovered length  8

why my cipher length is 8 only.

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

Let me throw mine in the pot.... You are treating binary data as a C-String, which means reading/writing stops at the first NULL character. You should use an overload that takes a pointer and size. Maybe something like:

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

(After code edits)

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

That's probably not producing expected results. Maybe you should try:

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

The above StringSource overload, with a pointer and size , is the one you should prefer in this case. Its the exact case it was designed for, and it saves the extra copy of buffer .

You could even use a FileSource and FileSink` to integrate with Crypto++::

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

Also, Barmak is correct about:

In your case you call it ctr but it seems to be uninitialized...

Though it is uninitialized, the same [unknown] value is used for encryption and decryption, so the problem did not show its head. It will show up later, like when you encrypt on one machine and decrypt on another.

You should follow Barmak advice an initialize it. Maybe something like:

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

OS_GenerateRandomBlock is discussed on Crypto++ wiki at RandomNumberGenerator .


You can usually send the counter in the plaintext with the message because its usually considered a public value. But it really depends on your security model.

Be sure to never reuse a security context in counter mode. Each message must be encrypted under a unique security context. The security context is the {key,ctr} pair.


You can also print the counter with:

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;

The code above simply hex-encodes the raw byte array nd then prints it to stdout .


(comment) string key = "7D9BB722DA2DC8674E08C3D44AAE976F"; - You probably want a binary string; not an ASCII string. For Crypto++, see HexDecoder on the Crypto++ wiki. I'm not sure what QT offers for the service.

Since there's more space here... this is one of the things you could do:

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

After the statements execute, the string key will be binary data.

In your code you are converting the file content to Base64, encrypting it, decrypting it and saving it to a file (thus saving a the png file as Base64)

You should encrypt the raw file data (and not the Base64 encoded one).

Edit: After your edit I don't know what fails. Please try the following function, which works for me. Uses FileSource and FileSink , but should work with StringSource and StringSink accordingly.

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

I found the issue with QByteArray buffer. i just converted to std::string its working.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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