Search code examples
qtencryptioncrypto++

Qt crypto++ aes encrypt/decrypt not decrypting properly


I have the following code:

#define PRIVATE_KEY "729308A8E815F6A46EB3A8AE6D5463CA7B64A0E2E11BC26A68106FC7697E727E37011"

To Encrypt:

QString Encryption::AESEncrypt(const QString &data)
{
string plain = data.toStdString();
string ciphertext;


// Hex decode symmetric key:
HexDecoder decoder;
decoder.Put( (byte *)PRIVATE_KEY, 32*2 );
decoder.MessageEnd();

word64 size = decoder.MaxRetrievable();
char *decodedKey = new char[size];

decoder.Get((byte *)decodedKey, size);

// Generate Cipher, Key, and CBC
byte key[ AES::MAX_KEYLENGTH ];
byte iv[ AES::BLOCKSIZE ];

StringSource( reinterpret_cast<const char *>(decodedKey), true,
              new HashFilter(*(new SHA256), new ArraySink(key, AES::MAX_KEYLENGTH)) );

memset( iv, 0x00, AES::BLOCKSIZE );

CBC_Mode<AES>::Encryption Encryptor( key, sizeof(key), iv );

StringSource( plain, true, new StreamTransformationFilter( Encryptor,
              new HexEncoder(new StringSink( ciphertext ) ) ) );

return QString::fromStdString(ciphertext);

}

To Decrypt:

QString Encryption::AESDecrypt(const QString &data)
{
string plain;
string encrypted = data.toStdString();

// Hex decode symmetric key:
HexDecoder decoder;
decoder.Put( (byte *)PRIVATE_KEY,32*2 );
decoder.MessageEnd();

word64 size = decoder.MaxRetrievable();
char *decodedKey = new char[size];
decoder.Get((byte *)decodedKey, size);

// Generate Cipher, Key, and CBC
byte key[ AES::MAX_KEYLENGTH ];
byte iv[ AES::BLOCKSIZE ];

StringSource( reinterpret_cast<const char *>(decodedKey), true,
              new HashFilter(*(new SHA256), new ArraySink(key, AES::MAX_KEYLENGTH)) );

memset( iv, 0x00, AES::BLOCKSIZE );

try
{
    CBC_Mode<AES>::Decryption Decryptor( key, sizeof(key), iv );


    StringSource( encrypted, true,
                  new HexDecoder(new StreamTransformationFilter( Decryptor,
                                 new StringSink( plain ) ) ) );

}
catch (Exception &e) { // ...

}
catch (...) { // ...

}
return QString::fromStdString(plain);
}

If I run the following:

Encryption encrypt;
QString encdata = encrypt.AESEncrypt("This is my data");
qDebug() << "encrypt: " << encdata;
qDebug() << "decrypt" << encrypt.AESDecrypt(encdata);

I get the following output:

encrypt:  "4E712EFDE13DA42FF798C193D17BE5D2" 
decrypt "" 

So I'm not sure why its not decrypting properly. I took the code from the following conversation. The code is failing on the second StringSource on decrypt and landing on the first Exception. Any ideas on what am I doing wrong?


Solution

  • I was getting a PKCS#7 padding error with the provided code. The code I used was modified to remove the Qt stuff and remove the function calls, so I'm not sure if I accidentally added/removed an error.

    I was able to fix the padding issue by modifying the encoding/decoding of the key. I think the problem was here:

    StringSource( reinterpret_cast<const char *>(decodedKey), true,
              new HashFilter(*(new SHA256), new ArraySink(key, AES::MAX_KEYLENGTH)) );
    

    In the code above, there was no guarantee decodedKey was NULL terminated. The fix was easy - store it in a string and then use length().

    The key you listed is 35 bytes in length (after decoding).

    #define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
    #define PRIVATE_KEY "729308A8E815F6A46EB3A8AE6D5463CA7B64A0E2E11BC26A68106FC7697E727E37011"
    
    string plain1 = "Now is the time for all good men...";
    string decoded1, cipher1;
    
    // Hex decode symmetric key:
    StringSource ss1((const byte*)PRIVATE_KEY, COUNTOF(PRIVATE_KEY), true,
                     new HexDecoder(new StringSink(decoded1)));
    
    // Generate Cipher, Key, and CBC
    byte key1[ AES::MAX_KEYLENGTH ];
    byte iv1[ AES::BLOCKSIZE ];
    
    SHA256 sha1;
    StringSource ss2( decoded1, true,
                     new HashFilter(sha1, new ArraySink(key1, sizeof(key1))) );
    
    memset( iv1, 0x00, AES::BLOCKSIZE );
    
    CBC_Mode<AES>::Encryption encryptor( key1, sizeof(key1), iv1 );
    
    StringSource ss3( plain1, true, new StreamTransformationFilter( encryptor,
                                                                   new HexEncoder(new StringSink( cipher1 ) ) ) );
    
    string plain2, decoded2;
    string cipher2 = cipher1;
    
    // Hex decode symmetric key:
    StringSource ss4((const byte*)PRIVATE_KEY, COUNTOF(PRIVATE_KEY), true,
                     new HexDecoder(new StringSink(decoded2)));
    
    // Generate Cipher, Key, and CBC
    byte key2[ AES::MAX_KEYLENGTH ];
    byte iv2[ AES::BLOCKSIZE ];
    
    SHA256 sha2;
    StringSource ss5( decoded2, true,
                     new HashFilter(sha2, new ArraySink(key2, sizeof(key2))) );
    
    memset( iv2, 0x00, AES::BLOCKSIZE );
    
    
    CBC_Mode<AES>::Decryption decryptor( key2, sizeof(key2), iv2 );
    
    StringSource ss6( cipher2, true,
                     new HexDecoder(new StreamTransformationFilter( decryptor,
                                                                   new StringSink( plain2 ) ) ) );
    
    cout << "Plain 1: " << plain1 << endl;
    cout << "Cipher: " << cipher1 << endl;
    cout << "Plain 2: " << plain2 << endl;
    

    Output from those three cout's is:

    Plain 1: Now is the time for all good men...
    Cipher: 3073448F4A71BC26CF81441F1DEE69C5DE700DF86294181B5E72E19D260DDF1E725DB3EFC74415982FFF45F9F7E290AE
    Plain 2: Now is the time for all good men...