Fix QuickXorHash: XOR længde ind i de sidste 64 bit (bits 96-159)

- Korrigerer finaliseringslogikken så filstørrelsen XOR'es ind i de mest betydende 64 bit af 160-bit staten
- Tidligere version XOR'ede i de mindst betydende bit, hvilket gav forkerte hashes
- Dette matcher nu præcis Microsofts specifikation og fjerner falske hash-mismatches
This commit is contained in:
Martin Tranberg
2026-03-29 17:36:13 +02:00
parent 39a3aff495
commit ad4166fb03

View File

@@ -80,8 +80,8 @@ 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.
Follows the official Microsoft/Rclone implementation:
160-bit circular XOR with a final length XOR."""
Follows the official Microsoft implementation: 160-bit circular XOR
with the file length XORed into the LAST 64 bits."""
h = 0
length = 0
mask = (1 << 160) - 1
@@ -93,16 +93,14 @@ def quickxorhash(file_path):
break
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
# Finalize: XOR the 64-bit length into the LAST 64 bits of the 160-bit state.
# Bits 96 to 159.
h ^= (length << (160 - 64))
# Convert to 20 bytes (160 bits) in little-endian format
result = h.to_bytes(20, byteorder='little')