Skip to content

Fix MD5 checksum encoding dropping leading zeros in HashUtils - #1400

Open
UditDewan wants to merge 1 commit into
facebook:mainfrom
UditDewan:fix/md5-checksum-leading-zeros
Open

Fix MD5 checksum encoding dropping leading zeros in HashUtils#1400
UditDewan wants to merge 1 commit into
facebook:mainfrom
UditDewan:fix/md5-checksum-leading-zeros

Conversation

@UditDewan

Copy link
Copy Markdown

Summary

HashUtils hex-encodes MD5 digests with:

BigInteger(1, md.digest()).toString(16)

BigInteger.toString(16) treats the digest as a number, so it drops leading zeros. Any digest that begins with one or more zero nibbles produces a hex string shorter than the expected 32 characters:

Input Correct MD5 What BigInteger produced
"a" 0cc175b9c0f1b6a831c399e269772661 cc175b9c0f1b6a831c399e269772661 (31 chars)
"jk8ssl" 0000000018e6137ac2caab16074784a6 18e6137ac2caab16074784a6 (24 chars)

Roughly one digest in sixteen starts with a zero nibble, so a meaningful fraction of checksums silently did not equal the canonical MD5 value. The same flaw was present in both computeFileMd5 and the PackageManager.requestChecksums path.

Change

Use AppEventUtility.bytesToHex — already defined in the same package — which formats each byte as exactly two hex digits (%02x) and therefore preserves leading zeros. This also removes the now-unused BigInteger import.

Tests

Added a regression test in HashUtilsTest covering a single leading-zero nibble ("a") and many leading-zero nibbles ("jk8ssl"), both of which failed before this change. Existing non-zero-prefixed cases are unchanged.

Note: the SDK test suite needs the Android/Gradle toolchain, which wasn't available in my environment, so the new assertions were verified against the canonical md5 values by inspection. CI should exercise them.

HashUtils encoded MD5 digests with BigInteger(1, digest).toString(16),
which interprets the digest as a number and drops leading zeros. Any
digest beginning with one or more zero nibbles produced a hex string
shorter than the expected 32 characters, e.g. MD5("a") rendered as
"cc175b9c0f1b6a831c399e269772661" (31 chars) and MD5("jk8ssl") as
"18e6137ac2caab16074784a6" (24 chars). Roughly one file in sixteen has
a digest starting with a zero nibble, so those checksums silently did
not match the canonical MD5 value.

Use AppEventUtility.bytesToHex (same package), which formats each byte
as two hex digits and therefore preserves leading zeros, for both the
file digest and the PackageManager checksum paths. Add a regression test
covering single- and multi-zero-nibble digests.

Co-authored-by: Baradhan-Madhu <26barum@gmail.com>
@meta-cla meta-cla Bot added the CLA Signed label Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant