我需要在php中实现文件解密。由于我的尝试,我得到了一个损坏的档案
我使用代码作为基础https://github.com/samloader/samloader/tree/master
我对这个部分感兴趣
elif args.command == "decrypt":
getkey = crypt.getv4key if args.enc_ver == 4 else crypt.getv2key
key = getkey(args.fw_ver, args.dev_model, args.dev_region)
length = os.stat(args.in_file).st_size
with open(args.in_file, "rb") as inf:
with open(args.out_file, "wb") as outf:
crypt.decrypt_progress(inf, outf, key, length)
和
def decrypt_progress(inf, outf, key, length):
""" Decrypt a stream of data while showing a progress bar. """
cipher = AES.new(key, AES.MODE_ECB)
if length % 16 != 0:
raise Exception("invalid input block size")
chunks = length//4096+1
pbar = tqdm(total=length, unit="B", unit_scale=True)
for i in range(chunks):
block = inf.read(4096)
if not block:
break
decblock = cipher.decrypt(block)
if i == chunks - 1:
outf.write(unpad(decblock))
else:
outf.write(decblock)
pbar.update(4096)
def getv4key(version, model, region):
""" Retrieve the AES key for V4 encryption. """
client = fusclient.FUSClient()
version = versionfetch.normalizevercode(version)
req = request.binaryinform(version, model, region, client.nonce)
resp = client.makereq("NF_DownloadBinaryInform.do", req)
root = ET.fromstring(resp)
fwver = root.find("./FUSBody/Results/LATEST_FW_VERSION/Data").text
logicval = root.find("./FUSBody/Put/LOGIC_VALUE_FACTORY/Data").text
deckey = request.getlogiccheck(fwver, logicval)
return hashlib.md5(deckey.encode()).digest()
我重写了,这行有疑问
hashlib.md5(deckey.encode()).digest()
我是这样的 `$deckey = 'AU77D7K3SAU/D3UU';
$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_encrypt($chunk, 'aes-128-ecb', $key, OPENSSL_RAW_DATA);
fwrite($dest, $encryptedChunk);
}
fclose($source);
fclose($dest);
帮我找出我做错了什么
您建议的通过MD5导出密钥的移植是正确的。
但是,填充存在一个问题:从Python代码可以得出结论,在加密过程中,除最后一个块之外的所有块都禁用了PKCS#7填充。使用 PHP 代码解密时必须考虑到这一点。
一个可能的 PHP 实现(基于您的代码)是:
$source = 'file.zip.enc4';
$dest = 'file.zip';
$deckey = "AU77D7K3SAU/D3UU";
$key = hash('md5', $deckey, true);
$chunkSize = 4096;
$fileSize = filesize($source);
$source = fopen($source, 'rb');
$dest = fopen($dest, 'wb');
$totalBytesRead = 0;
while (!feof($source)) {
$chunk = fread($source, $chunkSize);
if (!$chunk) {
break;
}
$totalBytesRead += strlen($chunk);
$padding = ($totalBytesRead < $fileSize) ? OPENSSL_ZERO_PADDING : 0;
$decryptedChunk = openssl_decrypt($chunk, 'aes-128-ecb', $key, OPENSSL_RAW_DATA | $padding);
fwrite($dest, $decryptedChunk);
}
fclose($source);
fclose($dest);
OPENSSL_ZERO_PADDING
禁用 PHP/OpenSSL 中的默认 PKCS#7 填充(请注意,该标志的名称具有误导性,可能会假设启用零填充;但实际上该标志禁用默认填充)。解密后的文件file.zip(4337718623字节)比加密文件file.zip.enc4(4337718624字节)小一个字节,这是由于最后一个块的填充所致。
解密的文件可以成功提取并提供包含 5 个 .tar.md5 文件的存档。