diff options
| author | Kazuki Yamaguchi <k@rhe.jp> | 2025-12-23 14:29:39 +0900 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2026-04-14 06:18:11 +0000 |
| commit | 4f26d8061a68dc13abd16a6ceb03bdacacffabef (patch) | |
| tree | 20e4714f1cb4960a33058b75ccc5dea1f365c6fa | |
| parent | 921e1f37d1c0d8caab49619261733ae48a59beef (diff) | |
[ruby/digest] Fix Digest::SHA1#update with large input
Digest::SHA1#update fails when a very large String is passed in a
single call.
Passing 2**29 bytes (512 MB) or more at once does not update the
message length counter correctly, which results in producing an
incorrect output.
$ ruby -rdigest -e'd=Digest::SHA1.new; d<<"a"*(512*1024*1024); puts d.hexdigest'
https://github.com/ruby/digest/commit/40cd9c4b14e7
$ ruby -rdigest -e'd=Digest::SHA1.new; 512.times{d<<"a"*(1024*1024)}; puts d.hexdigest'
https://github.com/ruby/digest/commit/0ea59bfe8787
$ ruby -e'print "a"*(512*1024*1024)'|sha1sum
https://github.com/ruby/digest/commit/0ea59bfe8787 -
Passing 2**32 bytes or more causes an infinite loop because the loop
counter is too small.
https://github.com/ruby/digest/commit/1bf687bf75
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
| -rw-r--r-- | ext/digest/sha1/sha1.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/ext/digest/sha1/sha1.c b/ext/digest/sha1/sha1.c index ce200270b7..003c87d224 100644 --- a/ext/digest/sha1/sha1.c +++ b/ext/digest/sha1/sha1.c @@ -220,14 +220,16 @@ int SHA1_Init(SHA1_CTX *context) */ void SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len) { - uint32_t i, j; + size_t i; + uint32_t j; _DIAGASSERT(context != 0); _DIAGASSERT(data != 0); j = context->count[0]; if ((context->count[0] += len << 3) < j) - context->count[1] += (len>>29)+1; + context->count[1]++; + context->count[1] += (uint32_t)(len >> 29); j = (j >> 3) & 63; if ((j + len) > 63) { (void)memcpy(&context->buffer[j], data, (i = 64-j)); |
