Fix QuickXorHash-implementering og tilføj manglende længde-XOR
- Opdaterer quickxorhash til at bruge en 160-bit heltalsbuffer for korrekt cirkulær rotation - Tilføjer det obligatoriske XOR-trin med filens længde, som manglede tidligere - Sikrer korrekt 20-byte little-endian format ved base64-encoding - Dette løser problemet med konstante hash-mismatch på ellers korrekte filer
This commit is contained in:
@@ -80,24 +80,33 @@ def safe_get(url, headers, stream=False, timeout=60, params=None):
|
||||
# --- Punkt 4: Integrity Validation (QuickXorHash) ---
|
||||
def quickxorhash(file_path):
|
||||
"""Compute Microsoft QuickXorHash for a file. Returns base64-encoded string.
|
||||
Uses 3 × uint64 cells matching Microsoft's C# reference implementation."""
|
||||
SHIFT = 11
|
||||
WIDTH = 160
|
||||
data = [0, 0, 0] # 3 × 64-bit unsigned integers
|
||||
i = 0
|
||||
Follows the official Microsoft/Rclone implementation:
|
||||
160-bit circular XOR with a final length XOR."""
|
||||
h = 0
|
||||
length = 0
|
||||
mask = (1 << 160) - 1
|
||||
|
||||
with open(file_path, 'rb') as f:
|
||||
while True:
|
||||
chunk = f.read(CHUNK_SIZE)
|
||||
if not chunk:
|
||||
break
|
||||
for byte in chunk:
|
||||
bit_idx = (i * SHIFT) % WIDTH
|
||||
cell = bit_idx // 64
|
||||
shift = bit_idx % 64
|
||||
data[cell] = (data[cell] ^ (byte << shift)) & 0xFFFFFFFFFFFFFFFF
|
||||
i += 1
|
||||
result = struct.pack('<QQQ', data[0], data[1], data[2])
|
||||
return base64.b64encode(result[:20]).decode('ascii')
|
||||
for b in chunk:
|
||||
shift = (length * 11) % 160
|
||||
# Circular shift left: the byte is XORed into the 160-bit state
|
||||
# at a position that rotates 11 bits for every byte.
|
||||
shifted = b << shift
|
||||
wrapped = (shifted & mask) | (shifted >> 160)
|
||||
h ^= wrapped
|
||||
length += 1
|
||||
|
||||
# Finalize: XOR the 64-bit length into the 160-bit state.
|
||||
# This affects the first 8 bytes of the little-endian representation.
|
||||
h ^= length
|
||||
|
||||
# Convert to 20 bytes (160 bits) in little-endian format
|
||||
result = h.to_bytes(20, byteorder='little')
|
||||
return base64.b64encode(result).decode('ascii')
|
||||
|
||||
def verify_integrity(local_path, remote_hash):
|
||||
"""Verifies file integrity using Microsoft QuickXorHash."""
|
||||
|
||||
Reference in New Issue
Block a user