Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractHasher
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
6 / 6
8
100.00% covered (success)
100.00%
1 / 1
 make
n/a
0 / 0
n/a
0 / 0
0
 requiresRehash
n/a
0 / 0
n/a
0 / 0
0
 setOptions
n/a
0 / 0
n/a
0 / 0
0
 create
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 createHash
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getInfo
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAlgorithms
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 needsRehash
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 verify
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Crypt\Hashing;
16
17/**
18 * Pop Crypt abstract hasher
19 *
20 * @category   Pop
21 * @package    Pop\Crypt
22 * @author     Nick Sagona, III <nick@popphp.org>
23 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    4.0.0
26 */
27abstract class AbstractHasher
28{
29
30    /**
31     * Maximum allowed length, in bytes, for a value passed to createHash() or verify().
32     *
33     * Argon2's cost scales with input size, so without a cap an attacker-controlled
34     * value of unbounded length becomes an algorithmic-complexity denial-of-service
35     * vector. 4096 matches the limit used by Symfony's password hasher.
36     */
37    const MAX_VALUE_LENGTH = 4096;
38
39    /**
40     * Make hashed value (based on the hasher class)
41     *
42     * @param  string $value
43     * @return string
44     */
45    abstract public function make(#[\SensitiveParameter] string $value): string;
46
47    /**
48     * Determine if the hashed value requires re-hashing (based on the hasher class)
49     *
50     * @param  string $hashedValue
51     * @return bool
52     */
53    abstract public function requiresRehash(string $hashedValue): bool;
54
55    /**
56     * Set hasher options
57     *
58     * @param  array $options
59     * @return static
60     */
61    abstract public function setOptions(array $options): static;
62
63    /**
64     * Create hasher object with options
65     *
66     * @return static
67     */
68    public static function create(array $options = []): static
69    {
70        $hasher = new static();
71        $hasher->setOptions($options);
72        return $hasher;
73    }
74
75    /**
76     * Create hashed value
77     *
78     * @param  string          $value
79     * @param  string|int|null $algorithm
80     * @param  array           $options
81     * @throws Exception
82     * @return string
83     */
84    public function createHash(#[\SensitiveParameter] string $value, string|int|null $algorithm, array $options = []): string
85    {
86        if (strlen($value) > static::MAX_VALUE_LENGTH) {
87            throw new Exception('Error: The value exceeds the maximum allowed length of ' . static::MAX_VALUE_LENGTH . ' bytes.');
88        }
89        return password_hash($value, $algorithm, $options);
90    }
91
92    /**
93     * Get info from hashed value
94     *
95     * @param  string $hashedValue
96     * @return array
97     */
98    public function getInfo(string $hashedValue): array
99    {
100        return password_get_info($hashedValue);
101    }
102
103    /**
104     * Get available hashing algorithms
105     *
106     * @return array
107     */
108    public function getAlgorithms(): array
109    {
110        return password_algos();
111    }
112
113    /**
114     * Determine if the hashed value needs to be re-hashed
115     *
116     * @param  string          $hashedValue
117     * @param  string|int|null $algorithm
118     * @param  array           $options
119     * @return bool
120     */
121    public function needsRehash(string $hashedValue, string|int|null $algorithm, array $options = []): bool
122    {
123        return password_needs_rehash($hashedValue, $algorithm, $options);
124    }
125
126    /**
127     * Verify hash
128     *
129     * @param  string $value
130     * @param  string $hashedValue
131     * @throws Exception
132     * @return bool
133     */
134    public function verify(#[\SensitiveParameter] string $value, string $hashedValue): bool
135    {
136        if (strlen($value) > static::MAX_VALUE_LENGTH) {
137            throw new Exception('Error: The value exceeds the maximum allowed length of ' . static::MAX_VALUE_LENGTH . ' bytes.');
138        }
139        return password_verify($value, $hashedValue);
140    }
141
142}