Make WordPress Core


Ignore:
Timestamp:
02/11/2025 11:12:03 AM (18 months ago)
Author:
johnbillion
Message:

Security: Explicitly require the hash PHP extension and add requirement checks during installation and upgrade.

This extension provides the hash() function and support for the SHA-256 algorithm, both of which are required for upcoming security related changes. This extension is almost universally enabled, however it is technically possible to disable it on PHP 7.2 and 7.3, hence the introduction of this requirement and the corresponding requirement checks prior to installing or upgrading WordPress.

Props peterwilsoncc, ayeshrajans, dd32, SergeyBiryukov, johnbillion.

Fixes #60638, #62815, #56017

See #21022

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/compat.php

    r59783 r59803  
    264264}
    265265
    266 if ( ! function_exists( 'hash_hmac' ) ) :
    267         /**
    268          * Compat function to mimic hash_hmac().
    269          *
    270          * The Hash extension is bundled with PHP by default since PHP 5.1.2.
    271          * However, the extension may be explicitly disabled on select servers.
    272          * As of PHP 7.4.0, the Hash extension is a core PHP extension and can no
    273          * longer be disabled.
    274          * I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
    275          * and the associated `_hash_hmac()` function can be safely removed.
    276          *
    277          * @ignore
    278          * @since 3.2.0
    279          *
    280          * @see _hash_hmac()
    281          *
    282          * @param string $algo   Hash algorithm. Accepts 'md5' or 'sha1'.
    283          * @param string $data   Data to be hashed.
    284          * @param string $key    Secret key to use for generating the hash.
    285          * @param bool   $binary Optional. Whether to output raw binary data (true),
    286          *                       or lowercase hexits (false). Default false.
    287          * @return string|false The hash in output determined by `$binary`.
    288          *                      False if `$algo` is unknown or invalid.
    289          */
    290         function hash_hmac( $algo, $data, $key, $binary = false ) {
    291                 return _hash_hmac( $algo, $data, $key, $binary );
    292         }
    293 endif;
    294 
    295 /**
    296  * Internal compat function to mimic hash_hmac().
    297  *
    298  * @ignore
    299  * @since 3.2.0
    300  *
    301  * @param string $algo   Hash algorithm. Accepts 'md5' or 'sha1'.
    302  * @param string $data   Data to be hashed.
    303  * @param string $key    Secret key to use for generating the hash.
    304  * @param bool   $binary Optional. Whether to output raw binary data (true),
    305  *                       or lowercase hexits (false). Default false.
    306  * @return string|false The hash in output determined by `$binary`.
    307  *                      False if `$algo` is unknown or invalid.
    308  */
    309 function _hash_hmac( $algo, $data, $key, $binary = false ) {
    310         $packs = array(
    311                 'md5'  => 'H32',
    312                 'sha1' => 'H40',
    313         );
    314 
    315         if ( ! isset( $packs[ $algo ] ) ) {
    316                 return false;
    317         }
    318 
    319         $pack = $packs[ $algo ];
    320 
    321         if ( strlen( $key ) > 64 ) {
    322                 $key = pack( $pack, $algo( $key ) );
    323         }
    324 
    325         $key = str_pad( $key, 64, chr( 0 ) );
    326 
    327         $ipad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x36 ), 64 ) );
    328         $opad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x5C ), 64 ) );
    329 
    330         $hmac = $algo( $opad . pack( $pack, $algo( $ipad . $data ) ) );
    331 
    332         if ( $binary ) {
    333                 return pack( $pack, $hmac );
    334         }
    335 
    336         return $hmac;
    337 }
    338 
    339 if ( ! function_exists( 'hash_equals' ) ) :
    340         /**
    341          * Timing attack safe string comparison.
    342          *
    343          * Compares two strings using the same time whether they're equal or not.
    344          *
    345          * Note: It can leak the length of a string when arguments of differing length are supplied.
    346          *
    347          * This function was added in PHP 5.6.
    348          * However, the Hash extension may be explicitly disabled on select servers.
    349          * As of PHP 7.4.0, the Hash extension is a core PHP extension and can no
    350          * longer be disabled.
    351          * I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
    352          * can be safely removed.
    353          *
    354          * @since 3.9.2
    355          *
    356          * @param string $known_string Expected string.
    357          * @param string $user_string  Actual, user supplied, string.
    358          * @return bool Whether strings are equal.
    359          */
    360         function hash_equals( $known_string, $user_string ) {
    361                 $known_string_length = strlen( $known_string );
    362 
    363                 if ( strlen( $user_string ) !== $known_string_length ) {
    364                         return false;
    365                 }
    366 
    367                 $result = 0;
    368 
    369                 // Do not attempt to "optimize" this.
    370                 for ( $i = 0; $i < $known_string_length; $i++ ) {
    371                         $result |= ord( $known_string[ $i ] ) ^ ord( $user_string[ $i ] );
    372                 }
    373 
    374                 return 0 === $result;
    375         }
    376 endif;
    377 
    378266// sodium_crypto_box() was introduced in PHP 7.2.
    379267if ( ! function_exists( 'sodium_crypto_box' ) ) {
Note: See TracChangeset for help on using the changeset viewer.