4
votes

I've got a big problem with AES Cryptography between Java and C++ (CryptoPP to be specific), that I was expecting to be way easier than asymetric cryptography, that I managed to solve earlier.

When I'm decrypting 48 bytes and the result is byte[] array of 38 bytes (size + code + hashOfCode), the last 22 bytes are decrypted properly and the first 16 are wrong.

try {
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
        byte[] key = { 107, -39, 87, -65, -1, -28, -85, -94, 105, 76, -94,
                110, 48, 116, -115, 86 };
        byte[] vector = { -94, 112, -23, 93, -112, -58, 18, 78, 1, 69, -92,
                102, 33, -96, -94, 59 };
        SecretKey aesKey = new SecretKeySpec(key, "AES");
        byte[] message = { 32, -26, -72, 25, 63, 114, -58, -5, 4, 90, 54,
                88, -28, 3, -72, 25, -54, -60, 17, -53, -27, -91, 34, -101,
                -93, -3, -47, 47, -12, -35, -118, -122, -77, -7, -9, -123,
                7, -66, 10, -93, -29, 4, -60, -102, 16, -57, -118, 94 };

        IvParameterSpec aesVector = new IvParameterSpec(vector);
        cipher.init(Cipher.DECRYPT_MODE, aesKey, aesVector);
        byte[] wynik = cipher.doFinal(message);
        Log.d("Solution here", "Solution");
        for (byte i : wynik)
            Log.d("Solution", "" + i);
    } catch (Exception e) {
        Log.d("ERROR", "TU");
        e.printStackTrace();
    }

Decrypted message, that I'm expecting to get is:

 0 0 0 32 10 0 16 43 81 -71 118 90 86 -93 -24 -103 -9 -49 14 -29 -114 82 81 -7 -59 3 -77 87 -77 48 -92 -111 -125 -21 123 21 86 4

But what I'm getting is

28 127 -111 92 -75 26 18 103 79 13 -51 -60 -60 -44 18 126 -9 49 14 -29 -114 82 81 -7 -59 3 -77 87 -77 48 -92 -111 -125 -21 123 21 86 4 

As you can see only last 22 bytes are the same.

I know that AES works with blocks and so I was thinking that maybe something with initialization vector is wrong (because only the first block is broken), but as you can see I'm setting vector in the way I think is OK.

And I have no idea why is it working that way. Any help will be really appreciated, cause I'm running out of time.

[EDIT] I add the Cipher initialization. As you wrote, it is AES/CBC/PKCS5Padding.

On the CryptoPP/C++ side (that is in fact not my code, so I'd provide the least piece of information that I can find useful) there is:

CryptoPP::CBC_Mode< CryptoPP::AES>::Encryption m_aesEncryption;
CryptoPP::CBC_Mode< CryptoPP::AES>::Decryption m_aesDecryption;

QByteArray AESAlgorithmCBCMode::encrypt(const QByteArray& plain)
{
std::string encrypted;

try {
    StringSource(reinterpret_cast<const byte*>(plain.data()), plain.length(), true,
            new StreamTransformationFilter(m_aesEncryption,
                    new StringSink(encrypted)));

} catch (const CryptoPP::Exception& e) {
    throw SymmetricAlgorithmException(e.what());
}

return QByteArray(encrypted.c_str(), encrypted.length());

}

QByteArray AESAlgorithmCBCMode::decrypt(const QByteArray& encrypted)
{
std::string plain;
try {
    StringSource(reinterpret_cast<const byte*>(encrypted.data()), encrypted.length(), true,
            new StreamTransformationFilter(m_aesDecryption,
                    new StringSink(plain)));
} catch (const CryptoPP::Exception& e) {
    throw SymmetricAlgorithmException(e.what());
}

return QByteArray(plain.c_str(), plain.length());

}

Key and initialization vector are exactly the same (I checked). The fun part is that is a part of a bigger communication protocol, and the previous message was encrypted and decrypted perfectly fine. And there were also zeros at the beginning.

1
I think you should also add to post: 1. How you are instatiate cipher, for example Cipher.getInstance("AES/CBC/PKCS5Padding") 2. C++ version of your code. - user1516873
And first three zero in your expected result looks very suspicious - user1516873
If the first 16 bytes end up corrupted, you're likely using an incorrect initialization vector. Make sure they match. I'd also like to point out that you should always generate a random IV when encrypting a message – using a static IV leaks information about the plaintext much like ECB mode does. - ntoskrnl
Ya, I know, that vector should be changed for each message, but I'll do it as soon as I figure out this problem. And vector on both sides is totally the same - I checked a couple of times. Is there a way (maybe some online encryptor/decryptor) where I can test, which side is right? Cause I didn't manage to find one that would work with bytes instead of Strings. - markubik
This question shows up as one that has many upvotes and no solution. Could you change the last part of the question to an answer so it is marked as solved? You can accept your own answer after 2 days or so. - Maarten Bodewes

1 Answers

0
votes

The answer was provided in the question; that didn't change even after a clear comment that it should be posted as an answer.

This is said answer:

The point is that every time doFinal() is invoked, it resets the state of cipher. What you should do is store last block of message (encrypted for Decryptor and decrypted for Encryptor) that will be used next time as a new InitializationVector. Then init() with this new IV should be invoked. Naturally, different instances of Cipher for Encryption and Decryption should be provided.