将Python文件解密逻辑转PHP遇归档损坏及解密错误问题排查
PHP实现三星.enc4文件解密遇损坏归档问题
背景
基于samloader项目的解密逻辑,在PHP中实现三星固件.enc4文件解密时,得到损坏的归档文件,但控制台用openssl命令可以正常解密,需要排查问题并修复。
核心疑问
Python代码中hashlib.md5(deckey.encode()).digest()转成PHP的$key = hash('md5', $deckey, true);是否正确?
现有代码问题
初始版本代码
<?php $source = 'file.zip.enc4'; $dest = 'file.zip'; $source = fopen($source, 'r'); $dest = fopen($dest, 'w'); $chunkSize = 4096; while (!feof($source)) { $chunk = fread($source, $chunkSize + 1); if (!$chunk) { break; } $encryptedChunk = openssl_decrypt($chunk, 'aes-128-ecb', $key, OPENSSL_RAW_DATA); fwrite($dest, $encryptedChunk); } fclose($source); fclose($dest); ?>
- 问题:解密后的归档文件损坏
添加OPENSSL_ZERO_PADDING后的错误
修改代码添加该参数后,出现以下错误:
string(58) "error:1C80006B:Provider routines::wrong final block length"
问题排查与解决方案
1. MD5密钥转换验证
hash('md5', $deckey, true)是正确的:
- PHP中
hash函数第三个参数设为true时,返回原始二进制数据,和Python的digest()行为完全一致;如果设为false(默认)则返回十六进制字符串,对应Python的hexdigest()。
2. 修正分块解密逻辑
AES-128-ECB要求输入数据长度必须是16字节(块大小)的整数倍,初始代码的分块逻辑存在问题:
$chunkSize +1会导致读取的块长度不规整,破坏ECB模式的块对齐要求- 三星.enc4加密使用PKCS#7填充(openssl默认填充方式),不需要手动添加
OPENSSL_ZERO_PADDING
修正后的代码:
<?php $sourcePath = 'file.zip.enc4'; $destPath = 'file.zip'; $deckey = '你的解密密钥'; $key = hash('md5', $deckey, true); // 确保密钥为二进制格式 // 以二进制模式读写,避免Windows下换行符转换 $source = fopen($sourcePath, 'rb'); $dest = fopen($destPath, 'wb'); $blockSize = 16; // AES-128的块大小 $chunkSize = 4096; // 必须是blockSize的整数倍,4096=16*256,符合要求 while (!feof($source)) { $chunk = fread($source, $chunkSize); $chunkLen = strlen($chunk); if ($chunkLen === 0) break; $decryptedChunk = openssl_decrypt($chunk, 'aes-128-ecb', $key, OPENSSL_RAW_DATA); if ($decryptedChunk === false) { die("解密失败: " . openssl_error_string()); } fwrite($dest, $decryptedChunk); } fclose($source); fclose($dest); ?>
3. 备用方案:调用系统openssl命令
如果PHP openssl扩展存在兼容性问题,可以直接调用系统openssl命令(需确保服务器允许exec函数,且openssl路径正确):
<?php $sourcePath = 'file.zip.enc4'; $destPath = 'file.zip'; $deckey = '你的解密密钥'; $keyHex = hash('md5', $deckey); // openssl命令需要十六进制格式的密钥 // 复制你控制台能正常解密的命令结构,调整参数 $command = sprintf( 'openssl enc -d -aes-128-ecb -in "%s" -out "%s" -K %s', escapeshellarg($sourcePath), escapeshellarg($destPath), $keyHex ); exec($command, $output, $returnCode); if ($returnCode !== 0) { die("命令执行失败: " . implode("\n", $output)); } ?>
- 提示:如果你的控制台解密命令需要
-nopad参数,就把它加到命令里;不需要则去掉,以实际能正常运行的命令为准。
关键注意事项
- 确保
$deckey和samloader中使用的密钥完全一致,注意编码(比如UTF-8)不要出错 - 必须用二进制模式(
rb/wb)读写文件,避免Windows环境下的换行符自动转换破坏二进制数据 - AES-128-ECB模式不需要初始化向量(IV),因此无需额外设置IV参数
内容的提问来源于stack exchange,提问作者Sergii
相关产品推荐
相关产品推荐

