RE: [EXTERNAL] Re: Clarification on doc for EVP_DecryptUpdate
"'Sands, Daniel N.' via openssl-users" <[email protected]> Thu, 2 Oct 2025 16:37:33 +0000
| Newsgroups | gmane.comp.encryption.openssl.user |
|---|---|
| Message-ID | <SA9PR09MB5309C29FDC08F30CF6A28ADDDBE7A@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. What version of the docs are you using? That isn't what the current version says: This is current for 3.0 to 3.3, which is what my distro offers. 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. You may call `EVP_DecryptUpdate` many times in order to stream data. However, when working with padded data we have no idea when the last block is coming. So if you pass some multiple of the block size bytes of ciphertext into `EVP_DecryptUpdate` then the last block will be buffered internally. If that turns out to be the final block of the whole stream of data then the padding will be stripped in the `EVP_DecryptFinal` call. But if you call `EVP_DecryptUpdate` again then the whole buffered block will be decrypted and passed back. So lets say the block size is 16, padding is in use and you call `EVP_DecryptUpdate` and pass 16 bytes of ciphertext. You will get no output at this point because we don't know if you're going to pass more, or whether that is the final block. Now lets say you pass an additional 1 byte of ciphertext. At this point we can decrypt the previously buffered block and pass all of that back. We can't yet decrypt the 1 byte you just passed because it's not a complete block. So in this case `inl` is 1, but the size of the output is the entire previously buffered block = 16. This is also equal to inl + cipher_block_size - 1 = 1 + 16 - 1 = 16 Okay, so this is for the case of adding less than a block size of cipher-text. That makes sense. The statement in question may be a bit too broad in its wording, which made me wonder, if I added another 16 bytes, why would I need 16+block-size to decrypt into? Anyway, could you also comment on the weirdness I saw with the first case below, as explained with the pseudo-code, and if the latter case should be trusted as expected behavior? 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 -- 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/SA9PR09MB5309C29FDC08F30CF6A28ADDDBE7A%40SA9PR09MB5309.namprd09.prod.outlook.com.