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

[10.x] Verify hash config #48814

Merged
merged 2 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
use ReflectionClass;
use ReflectionMethod;
use ReflectionNamedType;
use RuntimeException;

trait HasAttributes
{
Expand Down Expand Up @@ -1316,7 +1317,19 @@ public static function encryptUsing($encrypter)
*/
protected function castAttributeAsHashedString($key, $value)
{
return $value !== null && ! Hash::isHashed($value) ? Hash::make($value) : $value;
if ($value === null) {
return null;
}

if (! Hash::isHashed($value)) {
return Hash::make($value);
}

if (! Hash::verifyConfiguration($value)) {
throw new RuntimeException("Could not verify the hashed value's configuration.");
}

return $value;
}

/**
Expand Down
13 changes: 12 additions & 1 deletion src/Illuminate/Hashing/Argon2IdHasher.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Argon2IdHasher extends ArgonHasher
*/
public function check($value, $hashedValue, array $options = [])
{
if ($this->verifyAlgorithm && $this->info($hashedValue)['algoName'] !== 'argon2id') {
if ($this->verifyAlgorithm && ! $this->verifyAlgorithm($hashedValue)) {
throw new RuntimeException('This password does not use the Argon2id algorithm.');
}

Expand All @@ -29,6 +29,17 @@ public function check($value, $hashedValue, array $options = [])
return password_verify($value, $hashedValue);
}

/**
* Verify the hashed value's algorithm.
*
* @param string $hashedValue
* @return bool
*/
protected function verifyAlgorithm($hashedValue)
{
return $this->info($hashedValue)['algoName'] === 'argon2id';
}

/**
* Get the algorithm that should be used for hashing.
*
Expand Down
52 changes: 51 additions & 1 deletion src/Illuminate/Hashing/ArgonHasher.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ protected function algorithm()
*/
public function check($value, $hashedValue, array $options = [])
{
if ($this->verifyAlgorithm && $this->info($hashedValue)['algoName'] !== 'argon2i') {
if ($this->verifyAlgorithm && ! $this->verifyAlgorithm($hashedValue)) {
throw new RuntimeException('This password does not use the Argon2i algorithm.');
}

Expand All @@ -118,6 +118,56 @@ public function needsRehash($hashedValue, array $options = [])
]);
}

/**
* Verifies that the configuration is less than or equal to what is configured.
*
* @internal
*/
public function verifyConfiguration($value)
{
return $this->verifyAlgorithm($value) && $this->verifyOptions($value);
}

/**
* Verify the hashed value's algorithm.
*
* @param string $hashedValue
* @return bool
*/
protected function verifyAlgorithm($hashedValue)
{
return $this->info($hashedValue)['algoName'] === 'argon2i';
}

/**
* Verify the hashed value's options.
*
* @param string $hashedValue
* @return bool
*/
protected function verifyOptions($hashedValue)
{
['options' => $options] = $this->info($hashedValue);

if (
! is_int($options['memory_cost'] ?? null) ||
! is_int($options['time_cost'] ?? null) ||
! is_int($options['threads'] ?? null)
) {
return false;
}

if (
$options['memory_cost'] > $this->memory ||
$options['time_cost'] > $this->time ||
$options['threads'] > $this->threads
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should compare the other way, allowing more threads (maybe until a limit) because less threads means more computation time

) {
return false;
}

return true;
}

/**
* Set the default password memory factor.
*
Expand Down
44 changes: 43 additions & 1 deletion src/Illuminate/Hashing/BcryptHasher.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function make($value, array $options = [])
*/
public function check($value, $hashedValue, array $options = [])
{
if ($this->verifyAlgorithm && $this->info($hashedValue)['algoName'] !== 'bcrypt') {
if ($this->verifyAlgorithm && ! $this->verifyAlgorithm($hashedValue)) {
throw new RuntimeException('This password does not use the Bcrypt algorithm.');
}

Expand All @@ -88,6 +88,48 @@ public function needsRehash($hashedValue, array $options = [])
]);
}

/**
* Verifies that the configuration is less than or equal to what is configured.
*
* @internal
*/
public function verifyConfiguration($value)
{
return $this->verifyAlgorithm($value) && $this->verifyOptions($value);
}

/**
* Verify the hashed value's algorithm.
*
* @param string $hashedValue
* @return bool
*/
protected function verifyAlgorithm($hashedValue)
{
return $this->info($hashedValue)['algoName'] === 'bcrypt';
}

/**
* Verify the hashed value's options.
*
* @param string $hashedValue
* @return bool
*/
protected function verifyOptions($hashedValue)
{
['options' => $options] = $this->info($hashedValue);

if (! is_int($options['cost'] ?? null)) {
return false;
}

if ($options['cost'] > $this->rounds) {
return false;
}

return true;
}

/**
* Set the default password work factor.
*
Expand Down
Loading