In PHP, the crypt() function is a widely used password hashing tool that enhances password security by using a specified “salt.” The salt adds randomness to the hash, helping to prevent rainbow table attacks. Understanding how to extract and validate the salt from the hash generated by the crypt() function is an important part of mastering secure password handling.
This article will demonstrate how to use PHP’s substr() function to extract the salt portion from the return value of crypt() and perform a simple validation on it.
Salt is a random string combined with the original password during encryption. It ensures that even if two users have the same password, the resulting hash values will be different.
In the crypt() function, the format and length of the salt vary depending on the encryption algorithm, for example:
DES: 2-character salt
MD5: starts with $1$, followed by up to 8 characters of salt
Blowfish: starts with $2a$ or $2y$, followed by a two-digit cost factor and 22 characters of salt
Assuming you are using the MD5 algorithm, its salt format is as follows:
$1$ + 8-character salt
For example, a typical MD5 hash might be:
$hash = crypt('password', '$1$abcdefgh$');
The returned hash could be:
$1$abcdefgh$ZxR0LnxZPbQ5Cj7JlYiGp0
The salt is the first 12 characters: $1$abcdefgh$
<?php
$hash = crypt('password', '$1$abcdefgh$');
<p>// Extract salt of length 12 characters<br>
$salt = substr($hash, 0, 12);</p>
<p>echo "Extracted salt is: " . $salt;<br>
?><br>
We can use a regular expression to validate whether the extracted salt matches the expected format. For MD5 salt, the regex is:
/^(\$1\$[\.\/0-9a-zA-Z]{1,8}\$)$/
Example code:
<?php
$salt = substr($hash, 0, 12);
<p>if (preg_match('/^$1$[./0-9a-zA-Z]{1,8}$/', $salt)) {<br>
echo "Salt format is correct";<br>
} else {<br>
echo "Salt format is incorrect";<br>
}<br>
?><br>
Below is a full example including hash generation, salt extraction, and salt validation:
<?php
$password = 'mypassword';
<p>// Generate salt for MD5 algorithm ($1$ + 8 random characters + $)<br>
$salt = '$1$' . substr(strtr(base64_encode(random_bytes(6)), '+', '.'), 0, 8) . '$';</p>
<p>// Generate hash<br>
$hash = crypt($password, $salt);</p>
<p>echo "Generated hash: $hash\n";</p>
<p>// Extract salt from hash<br>
$extracted_salt = substr($hash, 0, 12);</p>
<p>echo "Extracted salt: $extracted_salt\n";</p>
<p>// Validate salt format<br>
if (preg_match('/^$1$[./0-9a-zA-Z]{1,8}$/', $extracted_salt)) {<br>
echo "Salt format validation passed\n";<br>
} else {<br>
echo "Salt format validation failed\n";<br>
}<br>
?><br>
The salt format of the crypt() function depends on the encryption algorithm, with varying length and structure.
Using substr() makes it easy to extract the salt part from the hash.
Validating the salt format with regular expressions ensures the salt meets algorithm requirements and enhances security.