From 23a2fa734b80c1973aa08c7cb4c79a8c49ffd95b Mon Sep 17 00:00:00 2001 From: Johnson Ajibi Date: Wed, 30 Sep 2026 22:19:04 +0100 Subject: [PATCH] md5/sha1/ripemd160: fix the same 4GiB ilen truncation as sha256 Per mpg's review, MD5, SHA-1 and RIPEMD-160 have the exact same bug as SHA-256: mbedtls_*_update() truncates ilen to its low 32 bits before adding it to ctx->total[0], and the overflow check right after only catches the single wraparound of that 32-bit addition -- neither step folds in bits 32 and up of ilen itself when a single update() call is passed >= 2^32 bytes on a 64-bit platform. SHA-512 does not have this bug (confirmed by TimothyPMann and independently by me): it tracks its 128-bit byte count in two uint64_t words, so ilen (a 64-bit size_t at most) can never overflow the low word before the carry-in step even runs. Applied the identical fix to all three: fold ilen >> 32 into total[1], guarded on SIZE_MAX so 32-bit platforms are unaffected. Verified live with the same method as the SHA-256 fix: hashed a real 4GiB + 64 byte file with mbedtls_md5_update()/sha1_update()/ ripemd160_update() in a single call and compared against md5sum(1), sha1sum(1), and `openssl dgst -rmd160`. algorithm before fix (wrong) after fix (matches reference tool) MD5 0e8b3fdad1980e2c4e66ef714abc3f0c 8b647773014d9f640da9887274f444cd SHA-1 b190a761fceaafdc19b62cbcc729ec22b02e7d0c 703fe5b4441eb203af67ed4fbc20263d44bc5f5c RIPEMD-160 68956d1517f2ebcef4761d2c0fddf11331a1e6b6 d14d7e80c32ddc603c677151bfd59fd8cf867c42 Also reworded the ChangeLog entry per feedback to cover all four functions concisely instead of describing the SHA-256 internals in detail. Signed-off-by: Johnson Ajibi --- ChangeLog.d/sha256-update-ilen-over-4gib.txt | 9 ++++----- library/md5.c | 4 ++++ library/ripemd160.c | 4 ++++ library/sha1.c | 4 ++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ChangeLog.d/sha256-update-ilen-over-4gib.txt b/ChangeLog.d/sha256-update-ilen-over-4gib.txt index 8769ea10ac..cad065a107 100644 --- a/ChangeLog.d/sha256-update-ilen-over-4gib.txt +++ b/ChangeLog.d/sha256-update-ilen-over-4gib.txt @@ -1,6 +1,5 @@ Bugfix - * Fix mbedtls_sha256_update() computing the wrong digest when a single - call is passed 4GiB (2^32 bytes) or more of input on a 64-bit - platform: the upper 32 bits of the input length were silently - dropped from the running byte count used at finalization. Reported - by TimothyPMann in #10964. + * Fix mbedtls_md5_update(), mbedtls_sha1_update(), + mbedtls_sha256_update() and mbedtls_ripemd160_update() computing the + wrong digest when a single call is passed 4GiB or more of input on a + 64-bit platform. Reported by TimothyPMann in #10964. diff --git a/library/md5.c b/library/md5.c index e4a87a2e09..088061930c 100644 --- a/library/md5.c +++ b/library/md5.c @@ -222,6 +222,10 @@ int mbedtls_md5_update(mbedtls_md5_context *ctx, ctx->total[1]++; } +#if SIZE_MAX > 0xFFFFFFFF + ctx->total[1] += (uint32_t) (ilen >> 32); +#endif + if (left && ilen >= fill) { memcpy((void *) (ctx->buffer + left), input, fill); if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0) { diff --git a/library/ripemd160.c b/library/ripemd160.c index b4fc3cdba1..6a8f3123d3 100644 --- a/library/ripemd160.c +++ b/library/ripemd160.c @@ -285,6 +285,10 @@ int mbedtls_ripemd160_update(mbedtls_ripemd160_context *ctx, ctx->total[1]++; } +#if SIZE_MAX > 0xFFFFFFFF + ctx->total[1] += (uint32_t) (ilen >> 32); +#endif + if (left && ilen >= fill) { memcpy((void *) (ctx->buffer + left), input, fill); diff --git a/library/sha1.c b/library/sha1.c index dfbe481f39..fe28022ae2 100644 --- a/library/sha1.c +++ b/library/sha1.c @@ -257,6 +257,10 @@ int mbedtls_sha1_update(mbedtls_sha1_context *ctx, ctx->total[1]++; } +#if SIZE_MAX > 0xFFFFFFFF + ctx->total[1] += (uint32_t) (ilen >> 32); +#endif + if (left && ilen >= fill) { memcpy((void *) (ctx->buffer + left), input, fill);