Skip to content

Commit

Permalink
Fix GH-12936: hash() function hangs endlessly if using sha512 on stri…
Browse files Browse the repository at this point in the history
…ngs >= 4GiB

There's two problems:
- Some loops used `unsigned int` instead of `size_t`.
- The 2*N-bit addition that is emulated using 2 N bit numbers has a bug:
  it first truncated the number to 32/64 bit and only then shifted. This
  resulted in the wrong length info stored inside the resulting hash.

Closes GH-12937.
  • Loading branch information
nielsdos committed Dec 12, 2023
1 parent 623da03 commit 2b8c008
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 24 deletions.
4 changes: 4 additions & 0 deletions NEWS
Expand Up @@ -6,6 +6,10 @@ PHP NEWS
. Fix incorrect timeout in built-in web server when using router script and
max_input_time. (ilutov)

- Hash:
. Fixed bug GH-12936 (hash() function hangs endlessly if using sha512 on
strings >= 4GiB). (nielsdos)

- Opcache:
. Fixed oss-fuzz #64727 (JIT undefined array key warning may overwrite DIM
with NULL when DIM is the same var as result). (ilutov)
Expand Down
4 changes: 2 additions & 2 deletions ext/hash/hash_adler32.c
Expand Up @@ -25,11 +25,11 @@ PHP_HASH_API void PHP_ADLER32Init(PHP_ADLER32_CTX *context, ZEND_ATTRIBUTE_UNUSE

PHP_HASH_API void PHP_ADLER32Update(PHP_ADLER32_CTX *context, const unsigned char *input, size_t len)
{
uint32_t i, s[2];
uint32_t s[2];

s[0] = context->state & 0xffff;
s[1] = (context->state >> 16) & 0xffff;
for (i = 0; i < len; ++i) {
for (size_t i = 0; i < len; ++i) {
s[0] += input[i];
s[1] += s[0];
if (s[1]>=0x7fffffff)
Expand Down
5 changes: 3 additions & 2 deletions ext/hash/hash_haval.c
Expand Up @@ -280,15 +280,16 @@ PHP_HASH_HAVAL_INIT(5,256)
/* {{{ PHP_HAVALUpdate */
PHP_HASH_API void PHP_HAVALUpdate(PHP_HAVAL_CTX *context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 128 */
index = (unsigned int) ((context->count[0] >> 3) & 0x7F);
/* Update number of bits */
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 128 - index;

Expand Down
5 changes: 3 additions & 2 deletions ext/hash/hash_md.c
Expand Up @@ -204,7 +204,8 @@ PHP_HASH_API void PHP_MD4InitArgs(PHP_MD4_CTX * context, ZEND_ATTRIBUTE_UNUSED H
*/
PHP_HASH_API void PHP_MD4Update(PHP_MD4_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
Expand All @@ -213,7 +214,7 @@ PHP_HASH_API void PHP_MD4Update(PHP_MD4_CTX * context, const unsigned char *inpu
if ((context->count[0] += ((uint32_t) inputLen << 3))
< ((uint32_t) inputLen << 3))
context->count[1]++;
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 64 - index;

Expand Down
20 changes: 12 additions & 8 deletions ext/hash/hash_ripemd.c
Expand Up @@ -271,7 +271,8 @@ static void RIPEMD128Transform(uint32_t state[4], const unsigned char block[64])
*/
PHP_HASH_API void PHP_RIPEMD128Update(PHP_RIPEMD128_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
Expand All @@ -280,7 +281,7 @@ PHP_HASH_API void PHP_RIPEMD128Update(PHP_RIPEMD128_CTX * context, const unsigne
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 64 - index;

Expand Down Expand Up @@ -369,7 +370,8 @@ static void RIPEMD256Transform(uint32_t state[8], const unsigned char block[64])
*/
PHP_HASH_API void PHP_RIPEMD256Update(PHP_RIPEMD256_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
Expand All @@ -378,7 +380,7 @@ PHP_HASH_API void PHP_RIPEMD256Update(PHP_RIPEMD256_CTX * context, const unsigne
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 64 - index;

Expand Down Expand Up @@ -468,7 +470,8 @@ static void RIPEMD160Transform(uint32_t state[5], const unsigned char block[64])
*/
PHP_HASH_API void PHP_RIPEMD160Update(PHP_RIPEMD160_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
Expand All @@ -477,7 +480,7 @@ PHP_HASH_API void PHP_RIPEMD160Update(PHP_RIPEMD160_CTX * context, const unsigne
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 64 - index;

Expand Down Expand Up @@ -576,7 +579,8 @@ static void RIPEMD320Transform(uint32_t state[10], const unsigned char block[64]
*/
PHP_HASH_API void PHP_RIPEMD320Update(PHP_RIPEMD320_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
Expand All @@ -585,7 +589,7 @@ PHP_HASH_API void PHP_RIPEMD320Update(PHP_RIPEMD320_CTX * context, const unsigne
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 64 - index;

Expand Down
20 changes: 12 additions & 8 deletions ext/hash/hash_sha.c
Expand Up @@ -222,7 +222,8 @@ PHP_HASH_API void PHP_SHA224InitArgs(PHP_SHA224_CTX * context, ZEND_ATTRIBUTE_UN
*/
PHP_HASH_API void PHP_SHA224Update(PHP_SHA224_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
Expand All @@ -231,7 +232,7 @@ PHP_HASH_API void PHP_SHA224Update(PHP_SHA224_CTX * context, const unsigned char
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 64 - index;

Expand Down Expand Up @@ -299,7 +300,8 @@ PHP_HASH_API void PHP_SHA224Final(unsigned char digest[28], PHP_SHA224_CTX * con
*/
PHP_HASH_API void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
Expand All @@ -308,7 +310,7 @@ PHP_HASH_API void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 64 - index;

Expand Down Expand Up @@ -513,7 +515,8 @@ static void SHA512Transform(uint64_t state[8], const unsigned char block[128])
*/
PHP_HASH_API void PHP_SHA384Update(PHP_SHA384_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i = 0, index, partLen;
unsigned int index, partLen;
size_t i = 0;

/* Compute number of bytes mod 128 */
index = (unsigned int) ((context->count[0] >> 3) & 0x7F);
Expand All @@ -522,7 +525,7 @@ PHP_HASH_API void PHP_SHA384Update(PHP_SHA384_CTX * context, const unsigned char
if ((context->count[0] += ((uint64_t) inputLen << 3)) < ((uint64_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint64_t) inputLen >> 61);
context->count[1] += (uint64_t) (inputLen >> 61);

partLen = 128 - index;

Expand Down Expand Up @@ -666,7 +669,8 @@ PHP_HASH_API void PHP_SHA512_224InitArgs(PHP_SHA512_CTX * context, ZEND_ATTRIBUT
*/
PHP_HASH_API void PHP_SHA512Update(PHP_SHA512_CTX * context, const unsigned char *input, size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 128 */
index = (unsigned int) ((context->count[0] >> 3) & 0x7F);
Expand All @@ -675,7 +679,7 @@ PHP_HASH_API void PHP_SHA512Update(PHP_SHA512_CTX * context, const unsigned char
if ((context->count[0] += ((uint64_t) inputLen << 3)) < ((uint64_t) inputLen << 3)) {
context->count[1]++;
}
context->count[1] += ((uint64_t) inputLen >> 61);
context->count[1] += (uint64_t) (inputLen >> 61);

partLen = 128 - index;

Expand Down
5 changes: 3 additions & 2 deletions ext/standard/sha1.c
Expand Up @@ -173,7 +173,8 @@ PHPAPI void PHP_SHA1InitArgs(PHP_SHA1_CTX * context, ZEND_ATTRIBUTE_UNUSED HashT
PHPAPI void PHP_SHA1Update(PHP_SHA1_CTX * context, const unsigned char *input,
size_t inputLen)
{
unsigned int i, index, partLen;
unsigned int index, partLen;
size_t i;

/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
Expand All @@ -182,7 +183,7 @@ PHPAPI void PHP_SHA1Update(PHP_SHA1_CTX * context, const unsigned char *input,
if ((context->count[0] += ((uint32_t) inputLen << 3))
< ((uint32_t) inputLen << 3))
context->count[1]++;
context->count[1] += ((uint32_t) inputLen >> 29);
context->count[1] += (uint32_t) (inputLen >> 29);

partLen = 64 - index;

Expand Down

0 comments on commit 2b8c008

Please sign in to comment.