A good look at the values you are dealing with. The resulting random salt will be, say:
abcdefg...
What is served in crypt as follows:
crypt($password, '$2y$10$abcdefg...') | | | | | +- the salt | +- the cost parameter +- the algorithm type
The result looks like this:
$2y$10$abcdefg...123456789... | | | | | | | +- the password hash | | +- the salt | +- the cost parameter +- the algorithm type
In other words, the first part of the resulting hash matches the original input to the crypt function; it contains the type and parameters of the algorithm, a random salt, and a hash result.
Input: $password + $2y$10$abcdefg... Output: $2y$10$abcdefg...123456789... ^^^^^^^^^^^^^^^^^ first part identical
When you confirm the password, you again need the same original salt. Only with the same salt will the same password hash with the same hash. And it is still present in the hash, in a format that can be transferred to crypt , as well as repeating the same operation as when generating the hash. To do this, you need to pass the password and hash to the verification function:
crypt($passwordToCheck, '$2y$10$abcdefg...123456789...')
crypt takes the first specified number of characters, up to abcdefg... and includes the rest (why salt should be a fixed number of characters). Therefore, it is equal to the same operation as before:
crypt($passwordToCheck, '$2y$10$abcdefg...')
And it will generate the same hash, if and only if $passwordToCheck is the same.