Skip to content

Commit

Permalink
Switch application passwords over to BLAKE2b instead of phpass.
Browse files Browse the repository at this point in the history
  • Loading branch information
johnbillion committed Jan 7, 2025
1 parent 9994922 commit d80491d
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 13 deletions.
49 changes: 46 additions & 3 deletions src/wp-includes/class-wp-application-passwords.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static function is_in_use() {
*
* @since 5.6.0
* @since 5.7.0 Returns WP_Error if application name already exists.
* @since x.y.z The hashed password value now uses wp_hash_value() instead of phpass.
*
* @param int $user_id User ID.
* @param array $args {
Expand Down Expand Up @@ -95,7 +96,7 @@ public static function create_new_application_password( $user_id, $args = array(
}

$new_password = wp_generate_password( static::PW_LENGTH, false );
$hashed_password = wp_hash_password( $new_password );
$hashed_password = self::hash_password( $new_password );

$new_item = array(
'uuid' => wp_generate_uuid4(),
Expand Down Expand Up @@ -124,6 +125,7 @@ public static function create_new_application_password( $user_id, $args = array(
* Fires when an application password is created.
*
* @since 5.6.0
* @since x.y.z @since x.y.z The hashed password value now uses wp_hash_value() instead of phpass.
*
* @param int $user_id The user ID.
* @param array $new_item {
Expand Down Expand Up @@ -249,7 +251,7 @@ public static function application_name_exists_for_user( $user_id, $name ) {
* Updates an application password.
*
* @since 5.6.0
* @since x.y.z The actual password should now be hashed using bcrypt instead of phpass. See wp_hash_password().
* @since x.y.z The actual password should now be hashed using wp_hash_value().
*
* @param int $user_id User ID.
* @param string $uuid The password's UUID.
Expand Down Expand Up @@ -302,7 +304,7 @@ public static function update_application_password( $user_id, $uuid, $update = a
* Fires when an application password is updated.
*
* @since 5.6.0
* @since x.y.z The password is now hashed using bcrypt instead of phpass.
* @since x.y.z The password is now hashed using wp_hash_value() instead of phpass.
* Existing passwords may still be hashed using phpass.
*
* @param int $user_id The user ID.
Expand Down Expand Up @@ -472,4 +474,45 @@ public static function chunk_password( $raw_password ) {

return trim( chunk_split( $raw_password, 4, ' ' ) );
}

/**
* Hashes a plaintext application password.
*
* @since x.y.z
*
* @param string $password Plaintext password.
* @return string Hashed password.
*/
public static function hash_password( $password ) {
return wp_hash_value( $password );
}

/**
* Checks a plaintext application password against a hashed password.
*
* @since x.y.z
*
* @param string $password Plaintext password.
* @param string $hash Hash of the password to check against.
* @return bool Whether the password matches the hashed password.
*/
public static function check_password( $password, $hash ) {
return wp_verify_hashed_value( $password, $hash );
}

/**
* Checks whether a password hash needs to be rehashed.
*
* A password hashed in a prior version of WordPress may still be hashed with phpass and will
* need to be rehashed. If the algorithm is changed in WordPress then a password hashed in a
* previous version will need to be rehashed.
*
* @since x.y.z
*
* @param string $hash Hash of a password to check.
* @return bool Whether the hash needs to be rehashed.
*/
public static function password_needs_rehash( $hash ) {
return ! str_starts_with( $hash, '$generic$' );
}
}
14 changes: 6 additions & 8 deletions src/wp-includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -437,17 +437,10 @@ function wp_authenticate_application_password( $input_user, $username, $password
$hashed_passwords = WP_Application_Passwords::get_user_application_passwords( $user->ID );

foreach ( $hashed_passwords as $key => $item ) {
$valid = wp_check_password( $password, $item['password'], $user->ID );

if ( ! $valid ) {
if ( ! WP_Application_Passwords::check_password( $password, $item['password'] ) ) {
continue;
}

if ( wp_password_needs_rehash( $item['password'] ) ) {
$item['password'] = wp_hash_password( $password );
WP_Application_Passwords::update_application_password( $user->ID, $item['uuid'], $item );
}

$error = new WP_Error();

/**
Expand All @@ -471,6 +464,11 @@ function wp_authenticate_application_password( $input_user, $username, $password
return $error;
}

if ( WP_Application_Passwords::password_needs_rehash( $item['password'] ) ) {
$item['password'] = WP_Application_Passwords::hash_password( $password );
WP_Application_Passwords::update_application_password( $user->ID, $item['uuid'], $item );
}

WP_Application_Passwords::record_application_password_usage( $user->ID, $item['uuid'] );

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/phpunit/tests/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -1039,7 +1039,7 @@ public function test_phpass_password_is_rehashed_after_successful_application_pa

// Verify that the application password needs rehashing.
$hash = WP_Application_Passwords::get_user_application_password( self::$user_id, $uuid )['password'];
$this->assertTrue( wp_password_needs_rehash( $hash ) );
$this->assertTrue( WP_Application_Passwords::password_needs_rehash( $hash ) );

// Authenticate.
$user = wp_authenticate_application_password( null, self::USER_LOGIN, $password );
Expand All @@ -1051,7 +1051,7 @@ public function test_phpass_password_is_rehashed_after_successful_application_pa

// Verify that the application password no longer needs rehashing.
$hash = WP_Application_Passwords::get_user_application_password( self::$user_id, $uuid )['password'];
$this->assertFalse( wp_password_needs_rehash( $hash ) );
$this->assertFalse( WP_Application_Passwords::password_needs_rehash( $hash ) );

// Verify that the user's password has not been touched.
$this->assertSame( $user_pass, get_userdata( self::$user_id )->user_pass );
Expand Down

0 comments on commit d80491d

Please sign in to comment.