2022-12-14 16:38:46 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Security\Hasher;
|
|
|
|
|
2022-12-16 15:00:14 +01:00
|
|
|
use App\SQLLogin\Exception\InvalidSQLLoginConfigurationException;
|
2022-12-14 16:38:46 +01:00
|
|
|
use App\SQLLogin\Exception\InvalidSQLPasswordException;
|
|
|
|
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
|
|
|
use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait;
|
|
|
|
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
|
|
|
|
|
|
|
|
class PasswordEncoder implements LegacyPasswordHasherInterface
|
|
|
|
{
|
|
|
|
use CheckPasswordLengthTrait;
|
2022-12-16 15:00:14 +01:00
|
|
|
public const PASSWORD_PATTERN = 'password';
|
|
|
|
public const SALT_PATTERN = 'salt';
|
|
|
|
public const PEPPER_PATTERN = 'pepper';
|
|
|
|
|
2022-12-14 16:38:46 +01:00
|
|
|
protected ?string $pepper;
|
2022-12-16 15:00:14 +01:00
|
|
|
protected array $hashAlgoLegacy;
|
|
|
|
protected array $securityPattern;
|
2022-12-14 16:38:46 +01:00
|
|
|
|
2022-12-16 16:49:24 +01:00
|
|
|
public function __construct(?string $pepper, string $hashAlgoLegacy, string $securityPattern)
|
2022-12-14 16:38:46 +01:00
|
|
|
{
|
|
|
|
$this->pepper = $pepper;
|
2022-12-16 15:00:14 +01:00
|
|
|
$this->hashAlgoLegacy = explode(',', $hashAlgoLegacy);
|
|
|
|
$this->securityPattern = explode(',', $securityPattern);
|
2022-12-14 16:38:46 +01:00
|
|
|
}
|
|
|
|
|
2022-12-16 15:00:14 +01:00
|
|
|
/**
|
2023-01-05 11:31:29 +01:00
|
|
|
* Pas utilisé, mais on doit le garder pour le implements
|
2022-12-16 15:00:14 +01:00
|
|
|
*/
|
2022-12-14 16:38:46 +01:00
|
|
|
public function hash(string $plainPassword, string $salt = null): string
|
|
|
|
{
|
|
|
|
if ($this->isPasswordTooLong($plainPassword)) {
|
|
|
|
throw new InvalidPasswordException();
|
|
|
|
}
|
|
|
|
|
2022-12-16 16:49:24 +01:00
|
|
|
return hash($plainPassword.$salt, $this->hashAlgoLegacy[0]);
|
2022-12-14 16:38:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool
|
|
|
|
{
|
|
|
|
if ('' === $plainPassword || $this->isPasswordTooLong($plainPassword)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-12-16 15:00:14 +01:00
|
|
|
$completedPassword = $this->getPasswordToHash($plainPassword, $salt);
|
|
|
|
|
2022-12-16 16:49:24 +01:00
|
|
|
foreach ($this->hashAlgoLegacy as $algo) {
|
2023-01-11 10:30:24 +01:00
|
|
|
if ('ssha' === $algo && $this->compareSsha($hashedPassword, $completedPassword)) {
|
|
|
|
return true;
|
2023-01-06 17:06:29 +01:00
|
|
|
}
|
2022-12-16 16:49:24 +01:00
|
|
|
if ($this->isObsoleteAlgo($algo)) {
|
|
|
|
if (hash_equals(hash($algo, $completedPassword), $hashedPassword)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (password_verify($completedPassword, $hashedPassword)) {
|
|
|
|
return true;
|
2022-12-16 15:00:14 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-14 16:38:46 +01:00
|
|
|
}
|
2022-12-16 16:49:24 +01:00
|
|
|
throw new InvalidSQLPasswordException();
|
2022-12-14 16:38:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function needsRehash(string $hashedPassword): bool
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2022-12-16 15:00:14 +01:00
|
|
|
|
|
|
|
public function isObsoleteAlgo($algo): bool
|
|
|
|
{
|
|
|
|
return in_array($algo, hash_algos());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retourne la string à hasher en fonction du pattern indiqué
|
|
|
|
*
|
|
|
|
* @param mixed $plainTextPassword
|
|
|
|
* @param mixed $salt
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
protected function getPasswordToHash($plainTextPassword, $salt)
|
|
|
|
{
|
|
|
|
$arrayRef = [
|
|
|
|
self::PASSWORD_PATTERN => $plainTextPassword,
|
|
|
|
self::SALT_PATTERN => $salt,
|
|
|
|
self::PEPPER_PATTERN => $this->pepper,
|
|
|
|
];
|
|
|
|
|
|
|
|
foreach ($this->securityPattern as $term) {
|
|
|
|
if (self::PEPPER_PATTERN !== $term && self::PASSWORD_PATTERN !== $term && self::SALT_PATTERN !== $term) {
|
|
|
|
throw new InvalidSQLLoginConfigurationException();
|
|
|
|
}
|
|
|
|
}
|
2022-12-16 15:39:42 +01:00
|
|
|
$completedPlainPassword = '';
|
2022-12-16 15:00:14 +01:00
|
|
|
foreach ($this->securityPattern as $term) {
|
2022-12-16 15:39:42 +01:00
|
|
|
$completedPlainPassword .= $arrayRef[$term];
|
2022-12-16 15:00:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $completedPlainPassword;
|
|
|
|
}
|
2023-01-06 17:06:29 +01:00
|
|
|
|
|
|
|
protected function compareSsha($hashPassword, $plainPassword)
|
|
|
|
{
|
|
|
|
$base_64_hash_with_salt = substr($hashPassword, 6);
|
|
|
|
$hash_with_salt = base64_decode($base_64_hash_with_salt);
|
|
|
|
$hash = substr($hash_with_salt, 0, 20);
|
|
|
|
$salt = substr($hash_with_salt, 20);
|
|
|
|
|
|
|
|
// hash given password
|
|
|
|
$hash_given = sha1($plainPassword.$salt, true);
|
|
|
|
|
|
|
|
return $hash == $hash_given;
|
|
|
|
}
|
2022-12-14 16:38:46 +01:00
|
|
|
}
|