November 30, 2016 —John Koster
In this article we will create an implementation of Illuminate\Contracts\Hashing\Hasher
using PHP
s crypt
function and the CRYPT_STD_DES
hashing function. Before we write the code for the CRYPT_STD_DES
implementation, we will examine each method that the Hasher
interface requires, as well as think about the options our hasher might utilize:
make($value, array $options = [])
The make
method is responsible for doing the actual hashing. It also accepts an $options
array. We will allow a salt to be supplied using the options array. If no salt is supplied, we will generate one.
For the actual hashing, we will make a call to PHP's crypt
function.
public function check($value, $hashedValue, array $options = [])
The check
method is used to check that a known $value
is the same as a $hashedValue
. We will not need any options for this method.
Internally, we will use the make
method and PHP's hash_equals
function.
public function needsRehash($hashedValue, array $options = [])
The needsRehash
method is used to determine if a given hash needs to be updated, or rehashed. We will accept a salt as an option. If the salt from the $options
array does not match the salt from the $hashedValue
the $hashedValue
needs to be rehashed.
The following is the complete implementation of the StandardDesHasher
class:
StandardDesHasher Option | Description |
---|---|
salt |
Users can supply their own two character salt to the make and needsRehash methods. If no salt is supplied to the make method, one will be generated. |
1<?php 2 3namespace Laravel\Artisan\Hashing; 4 5use RuntimeException; 6use Illuminate\Contracts\Hashing\Hasher as HasherContract; 7use Illuminate\Support\Str; 8 9class StandardDesHasher implements HasherContract10{11 12 const FAILED_HASH = '*0';13 14 /**15 * Hash the given value.16 *17 * @param string $value18 * @param array $options19 * @return string20 *21 * @throws \RuntimeException22 */23 public function make($value, array $options = [])24 {25 // If the user supplied a salt, use that. If not we26 // can generate it using the Str helper methods.27 $salt = isset($options['salt']) ? $options['salt'] : Str::random(2);28 29 $hash = crypt($value, $salt);30 31 if ($hash == self::FAILED_HASH) {32 // Throw an exception because the hashing failed.33 throw new RuntimeException('DES hashing failed.');34 }35 36 return $hash;37 }38 39 /**40 * Check the given plain value against a hash.41 *42 * @param string $value43 * @param string $hashedValue44 * @param array $options45 * @return bool46 */47 public function check($value, $hashedValue, array $options = [])48 {49 $userValue = $this->make($value, ['salt' => $hashedValue]);50 51 return hash_equals($hashedValue, $userValue);52 }53 54 /**55 * Check if the given hash has been hashed using the given options.56 *57 * @param string $hashedValue58 * @param array $options59 * @return bool60 */61 public function needsRehash($hashedValue, array $options = [])62 {63 if (!isset($options['salt'])) {64 return false;65 }66 67 return (mb_substr($hashedValue, 0, 2)68 !== mb_substr($options['salt'], 0, 2));69 }70 71}
The following sample demonstrates the usage of the custom StandardDesHasher
hasher implementation:
1<?php 2 3use Laravel\Artisan\StandardDesHasher; 4 5// Create a new instance of StandardDesHasher 6$hasher = new StandardDesHasher; 7 8// Calculate a hash, randomly generated salt. Output 9// of this method call should change each time.10$randomSalt = $hasher->make('test');11 12// Calculate a hash, with a known salt. Should always13// return 'teH0wLIpW0gyQ'14$suppliedSalt = $hasher->make('test', ['salt' => 'te']);15 16// Check if 'test' matches the hash.17//18// true19$isValid = $hasher->check('test', $randomSalt);20 21// Check if 'test' matches the hash.22//23// true24$isValid = $hasher->check('test', $suppliedSalt);25 26// Check if $randomSalt need to be rehashed. This will most likely27// always return true, but it is possible it will return false.28$needsRehash = $hasher->needsRehash(29 $randomSalt,30 ['salt' => 'te']31);32 33// Check if the $suppliedSalt needs to be rehashed. This will always34// return false, unless the salt option is changed.35$needsRehash = $hasher->needsRehash(36 $suppliedSalt,37 ['salt' => 'te']38);
∎
The following amazing people help support this site and my open source projects ♥️
If you're interesting in supporting my work and want to show up on this list, check out my GitHub Sponsors Profile.