C++, CryptoPP decrypted data first 16 bytes are junk

104 views Asked by At

I use CryptoPP library and obviously I make bunch of mistakes, because I get weird results and have not idea what I am doing.

I have a lot of data to encrypt and I divide it to chunks of N*BLOCKSIZE (BLOCKSIZE is 16 bytes in my case). Therefore all chunks are full of data (no padding needed) with an exception of maybe the last chunk. In my case padding is not desired.

As I decrypt encrypted data, only the last chunk I encrypted (and it's also the first chunk I decrypt) is okay. Other chunks have the first 16 bytes messed up. Why did that happen? I have read somwhere it happens because of incorrect initialization vector. Which seems to be correct for one chunk only and not others. Also I do not know, does CryptoPP work in such a way, where it stores IV in the first block of a chunk or not.

    CryptoPP::SecBlock<CryptoPP::byte> key(reinterpret_cast<const CryptoPP::byte*>("my_superb_key"), CryptoPP::AES::MAX_KEYLENGTH);
    CryptoPP::SecBlock<CryptoPP::byte> iv(reinterpret_cast<const CryptoPP::byte*>("dkdforodosoeosod5"), CryptoPP::AES::BLOCKSIZE);
    //

    while(i_block != n_block){
        CryptoPP::byte* chunk_encrypted = new CryptoPP::byte[sz_chunk];
        CryptoPP::ArraySink sink(chunk_encrypted, sz_chunk);

        CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption enc;
        enc.SetKeyWithIV(key, key.size(), iv, iv.size());

        CryptoPP::ArraySource(chunk, sz_chunk, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::Redirector(sink)));
    }

The problem I see right away is I use StreamTransformationFilter() which does apply padding. How do I not use padding? Need other way to encrypt data. Also I encrypt bytes of data, it's not a string of human-readable characters. Which method of encryption most suitable for this purpose? Obviously not the one I am using right now.

And for decryption I use this

CryptoPP::SecBlock<CryptoPP::byte> key(reinterpret_cast<const CryptoPP::byte*>("my_superb_key"), CryptoPP::AES::MAX_KEYLENGTH);
CryptoPP::SecBlock<CryptoPP::byte> iv(reinterpret_cast<const CryptoPP::byte*>("dkdforodosoeosod5"), CryptoPP::AES::BLOCKSIZE);
//

CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec;
dec.SetKeyWithIV(key, key.size(), iv, iv.size());

do {
    source = new CryptoPP::byte[sz_chunk];
    CryptoPP::ArraySink sink(source, sz_chunk);

    CryptoPP::ArraySource(dest, sz_chunk, true, new CryptoPP::StreamTransformationFilter(dec, new CryptoPP::Redirector(sink)));
} while(/* not done yet */);
1

There are 1 answers

3
Maarten Bodewes On

I use CryptoPP library and obviously I make bunch of mistakes, because I get weird results and have not idea what I am doing.

In that case you might want to get a book, course or something because you can have working code that is not secure. Cryptography (and security in general) is a bit weird in the sense that you can entirely miss your goal while the program is running fine.

As I decrypt encrypted data, only the last chunk I encrypted (and it's also the first chunk I decrypt) is okay. Other chunks have the first 16 bytes messed up. Why did that happen? I have read somwhere it happens because of incorrect initialization vector.

Yes, that's correct.

Also I do not know, does CryptoPP work in such a way, where it stores IV in the first block of a chunk or not.

Although CryptoPP provides some higher level constructs, it does still work on the algorithm level. The algorithm doesn't define what you do with the IV, just that it needs one. How you calculate or store the IV is up to you.

I have a lot of data to encrypt and I divide it to chunks of N*BLOCKSIZE (BLOCKSIZE is 16 bytes in my case). Therefore all chunks are full of data (no padding needed) with an exception of maybe the last chunk. In my case padding is not desired.

You are working with a high level crypto API that can perform streaming. In these stream implementations the plaintext is already encrypted piece-meal, so why are you defining a "chunk size" yourself? You might need that if you did want to operate on separate "messages", but you implicitly indicate that you do not want to do that - as each message would require padding.

The problem I see right away is I use StreamTransformationFilter() which does apply padding. How do I not use padding? Need other way to encrypt data.

To use CBC on messages (that are not always a multiple of the blocksize) you will either need padding or ciphertext stealing. Most other secure modes will actually not require padding, such as CTR mode. However, if you're OK with a single pad of the message then you just need to remove the chunking and make better use of the streaming API.