I want to encrypt input data in blocks of 100 bytes with OpenSSL AES-256-cbc encryption. However, the EVP_EncryptUpdate encrypts only 96 bytes (the parameter tmp = 96). The next call to EVP_EncryptUpdate encrypts the rest of the data (except those 4 missing).
The decryption is fine, except those 4 missing bytyes.
If I call EVP_EncryptUpdate only once, and pass in all data at once, all is fine.
I don't understand why those 4 bytes are missing if I pass only 100 bytes to EVP_EncryptUpdate.
std::string data = "A12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123hgfedcba";
unsigned char key[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
unsigned char iv[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
int i = 0, tmp = 0, ol = 0;
int res = EVP_EncryptInit(&ctx, EVP_aes_256_ecb(), key, iv);
std::unique_ptr<unsigned char[]> ret(new unsigned char[dataLen+EVP_CIPHER_CTX_block_size(&ctx)]);
for (i = 0; i < dataLen / 100; i++)
{
EVP_EncryptUpdate(&ctx,
&ret[ol], &tmp, &data[ol], 100);
ol += tmp;
}
if (dataLen % 100)
{
EVP_EncryptUpdate(&ctx, &ret[ol], &tmp, &data[ol], dataLen % 100);
ol += tmp;
}
EVP_EncryptFinal(&ctx, &ret[ol], &tmp);
EVP_EncryptUpdate
MUST be followed by EVP_EncryptFinal
. CBC mode can only encrypt / decrypt complete blocks. The lib doesn't know that the last call to EVP_EncryptUpdate
isn't followed by another one, so EVP_EncryptFinal
must be used to signal the end of the plaintext message to encrypt / decrypt.
EVP_EncryptUpdate
will try and encrypt as many blocks as possible, and leave the rest in an internal buffer. During EVP_EncryptFinal
the PKCS#7 compliant padding is added to the data that is in the buffer, and the last block(s) are encrypted and the last part of the ciphertext is returned. Note that padding is always applied, even if the internal buffer is empty.
All in all, your final four bytes are padded and encrypted when you call EVP_EncryptFinal
or add enough data using updates to create a full block of plaintext to encrypt. If you don't call EVP_EncryptFinal
then the ciphertext is not padded, and your decryption will either fail or - if the last part of the ciphertext could be seen as valid padding - it will strip some bytes off of the end and return what is left. Again, when using updates you must finalize.
If you don't like this kind of behavior you may look at CTR mode which - at least theoretically - is a streaming mode and can return the encrypted bytes directly, without requiring padding. This is called the "online" property of the block cipher mode. Sometimes implementations still buffer the plaintext until there is a full block though, so beware.
Coding notes:
100 is not a multiple of the block size (16 bytes) so obviously 4 bytes are left.
CBC requires a unique, unpredictable key / IV for CBC mode and CTR requires a unique nonce.
You'd better study these algorithms or otherwise you will fail to create secure code. For transport security you will want to use an authenticated cipher.