Clarification on doc for EVP_DecryptUpdate

"'Sands, Daniel N.' via openssl-users" <[email protected]> Wed, 1 Oct 2025 21:59:38 +0000
Newsgroups gmane.comp.encryption.openssl.user
Message-ID <SA9PR09MB53093A0DDBB4F7A3688559F3DBE6A@SA9PR09MB5309.namprd09.prod.outlook.com>
The docs state this:

EVP_DecryptInit_ex2(), EVP_DecryptInit_ex(), EVP_DecryptUpdate() and EVP_DecryptFinal_ex()

These functions are the corresponding decryption operations. EVP_DecryptFinal() will return an error code if padding is enabled and the final block is not correctly formatted. The parameters and restrictions are identical to the encryption operations except that if padding is enabled the decrypted data buffer out passed to EVP_DecryptUpdate() should have sufficient room for (inl + cipher_block_size) bytes unless the cipher block size is 1 in which case inl bytes is sufficient.

Why does the decrypted buffer need to be "inl + cipher block size"?  The ciphertext will be padded to a multiple of cipher block size, but the amount of decrypted text will be less than the amount of ciphertext given.

In addition, there seems to be a restriction which is NOT documented here (or is it a bug?)  I'll put together a simple example:

uint8_t *buf; <function arg, buffer the size of the expected plaintext>
size_t     bufsize; <function arg, expected size>

uint8_t pad[16];

<Read the ciphertext into buf and the final block into pad.  Do the usual setup for AES-128 CBC.>

int len;
EVP_DecryptUpdate(ctx, buf, &len, buf, bufsize & ~15);

int padlen;
EVP_DecryptUpdate(ctx, pad, &padlen, pad, 16);

int finallen;
EVP_DecryptFinal_ex(ctx, <any destination buffer>, &finallen) will fail.  This seems to be because pad was modified by in-place decryption.


If I instead do the following (very slight tweak here):

int len;
EVP_DecryptUpdate(ctx, buf, &len, buf, bufsize & ~15);

int padlen;
EVP_DecryptUpdate(ctx, buf + len, &padlen, pad, 16);

int finallen;
EVP_DecryptFinal_ex(ctx, <any destination buffer including pad>, &finallen) will succeed.  Oddly enough, it will succeed here even if pad was erased just before this call.

<Assert that len + padlen + finallen equals the buffer size>

memcpy(buf + len + padlen, pad, finallen); // Assumes that pad was the destination for EVP_DecryptFinal_ex


Final question:  Is the latter sequence considered couth for reading a stream into a buffer that is only the expected decrypted size, or does this depend on functionality that might change?

-- 
You received this message because you are subscribed to the Google Groups "openssl-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openssl-users+unsubscribe-MCmKBN63+Bmbup2nOX2J7Q@public.gmane.org
To view this discussion visit https://groups.google.com/a/openssl.org/d/msgid/openssl-users/SA9PR09MB53093A0DDBB4F7A3688559F3DBE6A%40SA9PR09MB5309.namprd09.prod.outlook.com.