We have an application that performs hashing across multiple hosts in a kind of round-robin form. In the past, we could reach into whatever hash we were using and pull its state, and write it into the hash state on the next host to continue processing. With the new opaque hash structures, that ability seems to be lost. Is that the case, or is it still somehow possible?
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?