OpenSSL 1.1.1中未调用EVP_CipherInit_ex却崩溃,是否应使用该接口?
Let's tackle your two core questions and dig into the possible root causes of that intermittent crash.
1. Should you use EVP_CipherInit_ex with OpenSSL 1.1.1?
Short answer: You can use it, but it's better to stick with the more explicit EVP_DecryptInit_ex (for decryption) or EVP_EncryptInit_ex (for encryption) instead.
Here's why:
- In OpenSSL 1.1.0+, the old generic
EVP_CipherInit_exis actually a macro that maps to eitherEVP_DecryptInit_exorEVP_EncryptInit_exdepending on context. It's kept for backward compatibility, but using the specific init functions makes your code clearer and avoids any ambiguity. - OpenSSL's official documentation recommends moving to the dedicated decrypt/encrypt init functions for modern code, as the generic interface is legacy.
2. Why are you crashing at EVP_CipherInit_ex when you aren't calling it directly?
That crash trace might be misleading—here's what's likely happening:
Under the hood, EVP_DecryptInit_ex (which you are calling) actually invokes EVP_CipherInit_ex internally as part of its implementation. So the crash is occurring inside OpenSSL's code path triggered by your EVP_DecryptInit_ex calls.
Now let's break down the most probable causes of that intermittent crash:
a. Unchecked EVP_CIPHER_CTX_new() return value
If EVP_CIPHER_CTX_new() fails (e.g., due to memory exhaustion), it returns NULL. If you proceed to call EVP_DecryptInit_ex with a NULL ctx, this will trigger a crash inside OpenSSL's internal code, which might show up as EVP_CipherInit_ex in the stack trace.
Fix: Always check if ctx is valid before using it:
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!ctx) { // Handle error (log, return failure, etc.) return -1; }
b. Invalid key/IV parameters
AES-256-CBC requires:
- A 32-byte (256-bit) encryption key
- A 16-byte (128-bit) initialization vector (IV)
If you're passing keys/IVs of the wrong length (even occasionally, leading to intermittent crashes), OpenSSL's internal validation will fail, causing a crash in the init path.
Fix: Add assertions or checks to verify the length of your key and IV before passing them to EVP_DecryptInit_ex.
c. Insufficient output buffer size
When calling EVP_DecryptUpdate, the output buffer (decryptedPassword) needs to be large enough to hold the maximum possible output. The required size is:input_length + EVP_CIPHER_block_size(EVP_aes_256_cbc()) - 1
If your buffer is too small, you'll get a memory overwrite (buffer overflow), which can corrupt arbitrary memory—including the stack frame that leads to a misleading crash trace pointing to EVP_CipherInit_ex.
Fix: Calculate the correct buffer size upfront and allocate accordingly.
d. Thread safety issues
EVP_CIPHER_CTX instances are not thread-safe. If you're sharing a single ctx across multiple threads, or if you're using OpenSSL functions without proper thread synchronization, you can get race conditions that lead to intermittent crashes.
Fix: Ensure each thread creates its own EVP_CIPHER_CTX instance, and never share ctx objects between threads.
e. Version mismatch between headers and linked library
If your code was compiled against OpenSSL 1.1.1 headers but is linked against an older version (like 1.0.x), or vice versa, you'll get symbol mismatches and undefined behavior. This can manifest as crashes in unexpected places, including the internal EVP_CipherInit_ex call.
Fix: Verify that your build system is using the same OpenSSL version for compilation and linking.
Quick Debugging Tips
- Enable debug symbols (
-gflag in GCC/Clang) to get more precise stack traces. - Use AddressSanitizer (
-fsanitize=address) to catch buffer overflows and memory access errors—this will often point you directly to the root cause instead of a misleading internal OpenSSL function. - Add error checking for all OpenSSL calls (most return 1 on success, 0 on failure) and log the error details using
ERR_print_errors_fpor similar functions.
内容的提问来源于stack exchange,提问作者thahgr

