Make WordPress Core


Ignore:
Timestamp:
02/11/2025 11:12:03 AM (2 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.