PHP AES-256-CBC解密图片文件后显示损坏的排查与解决求助
PHP AES-256-CBC解密图片文件后显示损坏的排查与解决求助
我最近在做一个PHP项目,用AES-256-CBC算法对图片文件进行加密和解密,但遇到了一个棘手的问题:把加密后的.aes文件解密还原成图片时,图片总是显示损坏状态,完全无法正常打开。
我的流程是:通过image_encrypt.php处理图片加密生成.aes文件,再用image_decrypt.php读取上传目录里最新的.aes文件,输入密钥后解密还原图片。目前解密过程没有抛出错误,但输出的图片就是损坏的,我已经加了一些调试信息还是没找到根源,麻烦各位帮忙看看代码哪里出问题了!
解密代码(image_decrypt.php)
<?php session_start(); if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['dec_key'])) { $decryptionKey = $_POST['dec_key']; // Fetch the latest uploaded .aes file from the uploads directory $uploadsDir = __DIR__ . '/uploads/'; $aesFiles = glob($uploadsDir . '*.aes'); if (empty($aesFiles)) { echo "Error: No .aes files found in the uploads directory."; exit; } // Sort files by modification time, descending usort($aesFiles, function ($a, $b) { return filemtime($b) - filemtime($a); }); // Use the most recently uploaded .aes file $aesFilePath = $aesFiles[0]; $aesFileName = basename($aesFilePath); // Debug: Check the selected file echo "Debug: Selected .aes file: $aesFileName<br>"; if (!file_exists($aesFilePath)) { echo "Error: The file does not exist."; exit; } $aesFileContent = file_get_contents($aesFilePath); // Debug: Check the .aes file content length echo "Debug: .aes file content length: " . strlen($aesFileContent) . "<br>"; $metadataEndPos = strpos($aesFileContent, "#####"); if ($metadataEndPos === false) { echo "Error: Invalid .aes file format."; exit; } $metadata = substr($aesFileContent, 0, $metadataEndPos); $encryptedHex = trim(substr($aesFileContent, $metadataEndPos + 5)); // Debug: Show metadata echo "Debug: Metadata: $metadata<br>"; preg_match('/Salt:\s([a-f0-9]{32})/', $metadata, $saltMatches); preg_match('/IV:\s([a-f0-9]{32})/', $metadata, $ivMatches); if (!isset($saltMatches[1]) || !isset($ivMatches[1])) { echo "Error: Salt or IV not found in metadata."; exit; } $salt = hex2bin($saltMatches[1]); $iv = hex2bin($ivMatches[1]); // Debug: Verify salt and IV echo "Debug: Salt: " . bin2hex($salt) . "<br>"; echo "Debug: IV: " . bin2hex($iv) . "<br>"; $encryptedContent = hex2bin(str_replace(' ', '', $encryptedHex)); if ($encryptedContent === false) { echo "Error: Invalid encrypted content format."; exit; } // Debug: Check encrypted content length echo "Debug: Encrypted content length: " . strlen($encryptedContent) . "<br>"; $cipher = 'aes-256-cbc'; $key = hash_pbkdf2('sha256', $decryptionKey, $salt, 1000, 32, true); // Debug: Key length echo "Debug: Key length: " . strlen($key) . "<br>"; $decryptedContent = openssl_decrypt($encryptedContent, $cipher, $key, OPENSSL_RAW_DATA, $iv); if ($decryptedContent === false) { echo "Error: Decryption failed. Incorrect key or corrupted data."; exit; } // Debug: Check decrypted content length echo "Debug: Decrypted content length: " . strlen($decryptedContent) . "<br>"; preg_match('/Original File-Extension:\s\.(\w+)/', $metadata, $extMatches); $originalExtension = isset($extMatches[1]) ? $extMatches[1] : 'jpg'; $decryptedFileName = "decrypted_image.$originalExtension"; if (!is_dir('decrypted_images')) { mkdir('decrypted_images', 0777, true); } $filePath = 'decrypted_images/' . $decryptedFileName; $fileHandle = fopen($filePath, 'wb'); if ($fileHandle) { fwrite($fileHandle, $decryptedContent); fclose($fileHandle); } else { echo "Error: Failed to open the file for writing."; exit; } // Debug: Check if the file was saved echo "Debug: Decrypted file saved at $filePath<br>"; // Redirect or display success message echo " <form id='redirectForm' action='image_index.php' method='POST'> <input type='hidden' name='decryptedData' value='" . base64_encode($decryptedContent) . "'> <input type='hidden' name='decryptedFileName' value='" . htmlspecialchars($decryptedFileName) . "'> </form> <script> document.getElementById('redirectForm').submit(); </script>"; exit; } else { echo "Error: Decryption key and/or file is missing."; }
加密代码(image_encrypt.php)
<?php if ($_SERVER['REQUEST_METHOD'] == 'POST') { $encryptionKey = $_POST['enc_key']; $fileContentBase64 = $_POST['fileContent']; $fileName = $_POST['fileName']; if (strlen($encryptionKey) < 8 || !preg_match('/^[\w!@#$%^&*()_+\-=\[\]{};:\"\\|,.<>\/?]+$/', $encryptionKey)) { echo "Error: Encryption key must be at least 8 characters long and can include letters, numbers, and symbols."; exit; } $fileContent = base64_decode($fileContentBase64); $cipher = 'aes-256-cbc'; $salt = openssl_random_pseudo_bytes(16); $key = hash_pbkdf2('sha256', $encryptionKey, $salt, 1000, 32, true); $ivLength = openssl_cipher_iv_length($cipher); $iv = openssl_random_pseudo_bytes($ivLength); $encryptedContent = openssl_encrypt($fileContent, $cipher, $key, OPENSSL_RAW_DATA, $iv); $finalEncryptedContent = $iv . $encryptedContent; $hexEncryptedContent = strtoupper(bin2hex($finalEncryptedContent)); $formattedHexOutput = implode(' ', str_split($hexEncryptedContent, 2)); $currentDateTime = date('d/m/Y h:i:s A'); $aesFileName = 'encrypted_' . pathinfo($fileName, PATHINFO_FILENAME) . '.aes'; $aesFilePath = 'encrypted_images/' . $aesFileName; if (!is_dir('encrypted_images')) { mkdir('encrypted_images', 0777, true); } // Optional: Include file size and signature in metadata $fileSize = strlen($fileContent); $fileSignature = bin2hex(substr($fileContent, 0, 4)); $aesContent = "Original File-Name: $fileName\n"; $aesContent .= "Original File-Size: $fileSize bytes\n"; $aesContent .= "Original File-Signature: $fileSignature\n"; $aesContent .= "Original File-Extension: ." . pathinfo($fileName, PATHINFO_EXTENSION) . "\n"; $aesContent .= "Encryption Date & Time: $currentDateTime\n"; $aesContent .= "Salt: " . bin2hex($salt) . "\n"; $aesContent .= "IV: " . bin2hex($iv) . "\n"; $aesContent .= "#####\n"; $aesContent .= "$formattedHexOutput\n"; // Save the encrypted data to .aes file if (file_put_contents($aesFilePath, $aesContent) === false) { echo "Error: Failed to save encrypted file."; exit; } $encryptedOutput = $formattedHexOutput; include('image_index.php'); } ?>
目前的调试情况
我已经在解密代码中添加了一些调试输出,能确认以下几点:
- 程序正确读取到了最新的
.aes文件 - 能从
.aes文件的metadata中正常提取到Salt和IV openssl_decrypt没有返回false,说明解密过程没有触发算法层面的错误- 解密后的内容也成功写入了目标文件,但打开就是损坏的图片
我怀疑可能是加密或解密时的字节流处理、IV和密钥的使用逻辑哪里出了问题,但自己排查了好久没找到,希望各位能帮忙指出问题所在!
备注:内容来源于stack exchange,提问作者Po Po
相关产品推荐
相关产品推荐

