我有一个零大小文件。7-zip 会da39a3ee5e6b4b0d3255bfef95601890afd80709
为其生成文件。没问题。
但如果我选择 2 个零大小文件,7zip 会b47346ddbdd6961a64aa7edf2bc130205fb10f12
为它们生成压缩包。这是怎么回事?
尝试了SHA1(SHA1(file1) + SHA1(file2))
算法,但结果却不同:43b1e995dbead10e335145327cf24f8d0ec38f88
。
答案1
笔记
7-Zip 显示每个文件的哈希值、哈希值的总和以及包含所有数据哈希值和所有文件名哈希值的总和。
'C:\Program Files\7-Zip\7z.exe' h -scrcsha1 .\new*
7-Zip 19.00 (x64) : Copyright (c) 1999-2018 Igor Pavlov : 2019-02-21
Scanning
2 files, 0 bytes
SHA1 Size Name
---------------------------------------- ------------- ------------
DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 0 New Text Document (2).txt
DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 0 New Text Document.txt
---------------------------------------- ------------- ------------
B47346DDBDD6961A64AA7EDF2BC130205FB10F12 0
Files: 2
Size: 0
SHA1 for data: B47346DDBDD6961A64AA7EDF2BC130205FB10F12
SHA1 for data and names: AFF4696D47DF1F0699A236DD70D5D51B960DD360
Everything is Ok
两个零字节文件的单个文件数据确实相同,但两个零字节文件连接在一起不一定与一个单字节文件相同。7zip 可能在内部将其表示为末梢血每个文件都有一个字节,没有实际数据。
使用 Python 进行快速测试:
>>> a = 0xDA39A3EE5E6B4B0D3255BFEF95601890AFD80709
>>> b = 0xDA39A3EE5E6B4B0D3255BFEF95601890AFD80709
>>> c = a + b
>>> hex(c)
'0x1b47347dcbcd6961a64ab7fdf2ac031215fb00e12'
>>>
区别在于
0x0b47346ddbdd6961a64aA7埃df2bC130205FB10F12 0x1b47347dCbCd6961a64ab7Fdf2AC031215FB00埃12
这意味着它不是简单的加法,还有其他事情发生。
如果你想知道数据是如何处理的,那么 7-zip 的源代码是这里。
答案2
感谢 Mokubai 的回答,我明白了它是如何工作的。
它是哈希数组中相同索引上相应字节的总和。如果总和超过,则255
后续总和(如果存在)增加1
。
以下是 JS 代码:
/** @param {...(Buffer|Uint8Array)} arrays
* @return {Uint8Array} */
function zipByteArrays(...arrays) {
const result = _zipByteArrays(arrays[0], arrays[1]);
for (let i = 2; i < arrays.length; i++) {
_zipByteArrays(result, arrays[i], result);
}
return result;
}
function _zipByteArrays(a, b, result = new Uint8Array(a.length)) {
let extra = 0;
for (let i = 0; i < a.length; i++) {
const sum = a[i] + b[i] + extra;
result[i] = sum % 256;
if (sum > 255) {
extra = 1;
} else {
extra = 0;
}
}
return result;
}
附加演示代码:
import crypto from "node:crypto";
// Empty file hash
const hash1 = Buffer.from("b47246dcbcd6961a64aa7ede2ac030205eb00e12", "hex");
console.log(hex(zipByteArrays(hash1, hash1)) === "b47346ddbdd6961a64aa7edf2bc130205fb10f12");
console.log(hex(zipByteArrays(hash1, hash1, hash1)) === "8eade9cb1c42e22796ff3dcfc12149b00e8a171b");
console.log(hex(zipByteArrays(hash1, hash1, hash1, hash1)) === "68e78cba7bad2d35c854fdbe57826140be621f24");
console.log(hex(zipByteArrays(hash1, hash1, hash1, hash1, hash1)) === "422130a9da187942faa9bcaeede279d06d3b272d");
function hex(array) {
return Buffer.from(array).toString("hex")
}
function sha1(value) {
const hasher = crypto.createHash("sha1");
hasher.update(value);
return hasher.digest();
}
但是,另一个问题是,当 7-zip 创建“数据和名称”哈希时它是如何工作的?
例如,
const f1_name = sha1("file1.txt");
const f2_name = sha1("file2.txt");
console.log(hex(zipByteArrays(hash1, f1_name, hash1, f2_name)));
打印,而 2 个具有和名称447d1e8e010c7344dfa2be63c7ab561b8de1d186
的空文件的预期哈希值为file1.txt
file2.txt
5d0543836f28cd8c93975c90c61373cd30c9c73f