Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicitly require the hash extension. #8138

Closed
wants to merge 8 commits into from
Next Next commit
Explicitly require the hash extension.
  • Loading branch information
johnbillion committed Jan 16, 2025
commit 6e66fd2263a1081060bb2f312524979e7be7eb5a
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
"issues": "https://core.trac.wordpress.org/"
},
"require": {
"ext-hash": "*",
"ext-json": "*",
"php": ">=7.2.24"
},
2 changes: 1 addition & 1 deletion src/wp-admin/includes/class-wp-site-health.php
Original file line number Diff line number Diff line change
@@ -923,7 +923,7 @@ public function get_test_php_extensions() {
),
'hash' => array(
'function' => 'hash',
'required' => false,
'required' => true,
),
'imagick' => array(
'extension' => 'imagick',
13 changes: 13 additions & 0 deletions src/wp-admin/includes/update-core.php
Original file line number Diff line number Diff line change
@@ -1194,6 +1194,19 @@ function update_core( $from, $to ) {
);
}

// Add a warning when the hash PHP extension is missing (only affects PHP < 7.4).
if ( ! extension_loaded( 'hash' ) ) {
return new WP_Error(
'php_not_compatible_hash',
sprintf(
/* translators: 1: WordPress version number, 2: The PHP extension name needed. */
__( 'The update cannot be installed because WordPress %1$s requires the %2$s PHP extension.' ),
$wp_version,
'hash'
)
);
}

/** This filter is documented in wp-admin/includes/update-core.php */
apply_filters( 'update_feedback', __( 'Preparing to install the latest version&#8230;' ) );

7 changes: 1 addition & 6 deletions src/wp-includes/class-wp-session-tokens.php
Original file line number Diff line number Diff line change
@@ -68,12 +68,7 @@ final public static function get_instance( $user_id ) {
* @return string A hash of the session token (a verifier).
*/
private function hash_token( $token ) {
// If ext/hash is not present, use sha1() instead.
if ( function_exists( 'hash' ) ) {
return hash( 'sha256', $token );
} else {
return sha1( $token );
}
return hash( 'sha256', $token );
}

/**
4 changes: 1 addition & 3 deletions src/wp-includes/class-wpdb.php
Original file line number Diff line number Diff line change
@@ -2406,12 +2406,10 @@ public function placeholder_escape() {
static $placeholder;

if ( ! $placeholder ) {
// If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
$algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
// Old WP installs may not have AUTH_SALT defined.
$salt = defined( 'AUTH_SALT' ) && AUTH_SALT ? AUTH_SALT : (string) rand();

$placeholder = '{' . hash_hmac( $algo, uniqid( $salt, true ), $salt ) . '}';
$placeholder = '{' . hash_hmac( 'sha256', uniqid( $salt, true ), $salt ) . '}';
}

/*
112 changes: 0 additions & 112 deletions src/wp-includes/compat.php
Original file line number Diff line number Diff line change
@@ -263,118 +263,6 @@ function _mb_strlen( $str, $encoding = null ) {
return --$count;
}

if ( ! function_exists( 'hash_hmac' ) ) :
/**
* Compat function to mimic hash_hmac().
*
* The Hash extension is bundled with PHP by default since PHP 5.1.2.
* However, the extension may be explicitly disabled on select servers.
* As of PHP 7.4.0, the Hash extension is a core PHP extension and can no
* longer be disabled.
* I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
* and the associated `_hash_hmac()` function can be safely removed.
*
* @ignore
* @since 3.2.0
*
* @see _hash_hmac()
*
* @param string $algo Hash algorithm. Accepts 'md5' or 'sha1'.
* @param string $data Data to be hashed.
* @param string $key Secret key to use for generating the hash.
* @param bool $binary Optional. Whether to output raw binary data (true),
* or lowercase hexits (false). Default false.
* @return string|false The hash in output determined by `$binary`.
* False if `$algo` is unknown or invalid.
*/
function hash_hmac( $algo, $data, $key, $binary = false ) {
return _hash_hmac( $algo, $data, $key, $binary );
}
endif;

/**
* Internal compat function to mimic hash_hmac().
*
* @ignore
* @since 3.2.0
*
* @param string $algo Hash algorithm. Accepts 'md5' or 'sha1'.
* @param string $data Data to be hashed.
* @param string $key Secret key to use for generating the hash.
* @param bool $binary Optional. Whether to output raw binary data (true),
* or lowercase hexits (false). Default false.
* @return string|false The hash in output determined by `$binary`.
* False if `$algo` is unknown or invalid.
*/
function _hash_hmac( $algo, $data, $key, $binary = false ) {
$packs = array(
'md5' => 'H32',
'sha1' => 'H40',
);

if ( ! isset( $packs[ $algo ] ) ) {
return false;
}

$pack = $packs[ $algo ];

if ( strlen( $key ) > 64 ) {
$key = pack( $pack, $algo( $key ) );
}

$key = str_pad( $key, 64, chr( 0 ) );

$ipad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x36 ), 64 ) );
$opad = ( substr( $key, 0, 64 ) ^ str_repeat( chr( 0x5C ), 64 ) );

$hmac = $algo( $opad . pack( $pack, $algo( $ipad . $data ) ) );

if ( $binary ) {
return pack( $pack, $hmac );
}

return $hmac;
}

if ( ! function_exists( 'hash_equals' ) ) :
/**
* Timing attack safe string comparison.
*
* Compares two strings using the same time whether they're equal or not.
*
* Note: It can leak the length of a string when arguments of differing length are supplied.
*
* This function was added in PHP 5.6.
* However, the Hash extension may be explicitly disabled on select servers.
* As of PHP 7.4.0, the Hash extension is a core PHP extension and can no
* longer be disabled.
* I.e. when PHP 7.4.0 becomes the minimum requirement, this polyfill
* can be safely removed.
*
* @since 3.9.2
*
* @param string $known_string Expected string.
* @param string $user_string Actual, user supplied, string.
* @return bool Whether strings are equal.
*/
function hash_equals( $known_string, $user_string ) {
$known_string_length = strlen( $known_string );

if ( strlen( $user_string ) !== $known_string_length ) {
return false;
}

$result = 0;

// Do not attempt to "optimize" this.
for ( $i = 0; $i < $known_string_length; $i++ ) {
$result |= ord( $known_string[ $i ] ) ^ ord( $user_string[ $i ] );
}

return 0 === $result;
}
endif;

// sodium_crypto_box() was introduced in PHP 7.2.
if ( ! function_exists( 'sodium_crypto_box' ) ) {
require ABSPATH . WPINC . '/sodium_compat/autoload.php';
8 changes: 2 additions & 6 deletions src/wp-includes/pluggable.php
Original file line number Diff line number Diff line change
@@ -768,9 +768,7 @@ function wp_validate_auth_cookie( $cookie = '', $scheme = '' ) {

$key = wp_hash( $username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );

// If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
$algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
$hash = hash_hmac( $algo, $username . '|' . $expiration . '|' . $token, $key );
$hash = hash_hmac( 'sha256', $username . '|' . $expiration . '|' . $token, $key );

if ( ! hash_equals( $hash, $hmac ) ) {
/**
@@ -871,9 +869,7 @@ function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $toke

$key = wp_hash( $user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );

// If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
$algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
$hash = hash_hmac( $algo, $user->user_login . '|' . $expiration . '|' . $token, $key );
$hash = hash_hmac( 'sha256', $user->user_login . '|' . $expiration . '|' . $token, $key );

$cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash;

65 changes: 0 additions & 65 deletions tests/phpunit/tests/compat/hashHmac.php

This file was deleted.

Loading