summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2025-12-23 14:29:39 +0900
committergit <svn-admin@ruby-lang.org>2026-04-14 06:18:11 +0000
commit4f26d8061a68dc13abd16a6ceb03bdacacffabef (patch)
tree20e4714f1cb4960a33058b75ccc5dea1f365c6fa
parent921e1f37d1c0d8caab49619261733ae48a59beef (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.c6
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));