OpenSSL解密失败求助:附PHP AES-256-CBC相关代码
Let's walk through the most likely causes of your decryption issue, along with actionable fixes based on the code snippet you shared:
1. Invalid Key/IV Length for AES-256-CBC
AES-256-CBC has strict requirements for key and IV sizes:
- The key must be exactly 32 bytes (256 bits)
- The IV must be exactly 16 bytes (128 bits)
Looking at your code:
$kpart1 = "IsdI685cUY"is 10 characters long. For the full$keyto hit 32 bytes,$kpart2(fromtab_sec.crypt_key) needs to be 22 bytes. If it's shorter or longer, OpenSSL will silently adjust the key (truncate or pad), which breaks decryption.$ipart1 = "RkEgfA"is 6 characters long.$ipart2(fromtab_sec.iv) needs to be 10 bytes to make the full$iv16 bytes. Any deviation here will cause immediate decryption failure.
Fix:
Verify the byte lengths with:
// Get byte counts (use 8bit to avoid multi-byte character confusion) $keyByteLength = mb_strlen($key, '8bit'); $ivByteLength = mb_strlen($iv, '8bit'); echo "Key length: $keyByteLength bytes | IV length: $ivByteLength bytes";
Adjust your kpart2 and ipart2 values in the database to meet the exact byte requirements.
2. Character Encoding Mismatches
If your database stores crypt_key or iv in a different encoding than your PHP script uses (e.g., Latin1 vs UTF-8), the actual byte length of the concatenated $key and $iv will be incorrect. Multi-byte characters can inflate the byte count beyond the required 32/16 bytes.
Fix:
Ensure both your database columns and PHP script use the same encoding (preferably UTF-8). Check your database table collation (e.g., utf8mb4_unicode_ci) and confirm your PHP script sets the correct connection encoding:
$conn->exec("SET NAMES utf8mb4");
3. Unsafe SQL Query (Risk of Data Corruption/SQL Injection)
Your second query uses string interpolation (WHERE id = '$q') instead of prepared statements. This is not only a critical security risk (SQL injection) but can also lead to incorrect data being fetched if $q contains special characters (e.g., quotes) that get escaped improperly. If you're fetching the wrong encrypted row, decryption will naturally fail.
Fix:
Rewrite the query using PDO prepared statements:
$statement = $conn->prepare("SELECT * FROM `tab_employees` WHERE `id` = ?"); $statement->execute([$q]); $row = $statement->fetch(PDO::FETCH_ASSOC);
This ensures safe, accurate data retrieval.
4. Mismatched Encryption/Decryption Parameters
Decryption will fail if any parameter doesn't exactly match what was used during encryption:
- Did you use the same
$method(AES-256-CBC) for both encryption and decryption? - Did you apply the same padding (OpenSSL defaults to PKCS7; if you changed it during encryption, you must specify it during decryption)?
- Was the encrypted data stored as raw binary or base64-encoded? If base64, you must decode it before decrypting with
base64_decode($encryptedData). - Are you using the same options (e.g.,
OPENSSL_RAW_DATA) in bothopenssl_encrypt()andopenssl_decrypt()?
Fix:
Add error logging to get specific OpenSSL feedback:
$decrypted = openssl_decrypt($encryptedData, $method, $key, OPENSSL_RAW_DATA, $iv); if (!$decrypted) { echo "OpenSSL Error: " . openssl_error_string(); }
This will tell you exactly what's wrong (e.g., "IV length incorrect").
5. Incomplete PDO Fetch Logic
Your code cuts off at $row = $sth->fetch(PDO::FETCH...—if you're using the wrong fetch mode (e.g., FETCH_NUM instead of FETCH_ASSOC), you might be trying to decrypt an empty or incorrect value.
Fix:
Ensure you're using the correct fetch mode to access your encrypted column. For example, if your encrypted data is in a column named encrypted_info, confirm:
$row = $sth->fetch(PDO::FETCH_ASSOC); $encryptedData = $row['encrypted_info']; // Make sure this is not empty or null
内容的提问来源于stack exchange,提问作者Michal Vlasák

