fix(intunewin): compute HMAC over IV+ciphertext, not ciphertext alone

The reference implementation (svrooij/ContentPrep Zipper.cs DecryptFileAsync)
reads the first 32 bytes as the stored HMAC, then hashes the *remaining* bytes
— i.e. IV (16 bytes) || ciphertext — to verify integrity. ImpTune was computing
HMAC(mac_key, ciphertext) which omits the IV. Intune's server-side HMAC check
would therefore always fail, manifesting as the same silent symptom as the
Detection.xml bug: empty wizard fields, greyed OK button, no error banner.

The blob layout is unchanged: [HMAC(32)] + [IV(16)] + [ciphertext].
Only the hash input is corrected: iv + ciphertext instead of ciphertext.

The Mac field in Detection.xml is also updated accordingly (it stores the same
HMAC value that is prepended to the blob).

Tests updated: test_hmac_matches now verifies HMAC over blob[32:] (= IV+ciphertext),
which is exactly what the reference decryption algorithm verifies against.

All 114 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-13 12:08:43 +02:00
co-authored by Claude Sonnet 4.6
parent 44a4f2c573
commit 74535ea089
2 changed files with 18 additions and 7 deletions
+7 -2
View File
@@ -77,8 +77,13 @@ def build_intunewin(source_dir: str, setup_file: str, output_path: str) -> None:
cipher = AES.new(aes_key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
# --- Step 4: Compute HMAC-SHA256 over ciphertext (using mac_key) ---
mac_digest = hmac.new(mac_key, ciphertext, hashlib.sha256).digest()
# --- Step 4: Compute HMAC-SHA256 over (IV + ciphertext) using mac_key ---
# The reference (svrooij/ContentPrep Zipper.cs DecryptFileAsync) reads the first
# 32 bytes as the stored HMAC, then computes the hash of the *remaining* bytes
# (= IV || ciphertext) to verify integrity. Authenticated-encryption best
# practice (Encrypt-then-MAC) also requires the IV to be covered by the MAC so
# that a forged IV cannot redirect decryption.
mac_digest = hmac.new(mac_key, iv + ciphertext, hashlib.sha256).digest()
# --- Step 5: Assemble encrypted blob: [HMAC(32)] + [IV(16)] + [ciphertext] ---
encrypted_blob = mac_digest + iv + ciphertext