Slappasswd output randomized
I was expecting slappasswd
to produce a fixed hash but it appears that the output is randomized as I never get the same output for the same input password:
$ slappasswd -s secret
{SSHA}mCXsPZkfgQYZr2mKHpy5Iav+2S2XlVU3
$ slappasswd -s secret
{SSHA}62oXsalJBuopYfHhi6hGp6AESuWNIVnd
$ slappasswd -s secret
{SSHA}0Ulc8+ugMi3NbTtWnclOFW1LKCqRdsT8
During authentication, how does slapd knows how to randomize the hash for the provided password in the same way so that it can match the password defined in the first place?
Going out on a limb here, but I assume slappasswd is using a salted hash instead of a plain hash. This means that it adds a random prefix to your password, and saves that random prefix as part of the string you see in the slappasswd output. When you type your password, it adds the prefix to it, hashes the result and compares that to the string in the slappasswd output. If it matches, you are in. If it does not, you password was wrong :)
SSHA is a salted SHA-1. By default the last 4 Bytes are the salt. The output of slappasswd is
'{<Hash Method>}<base64 converted hash and salt>'
So in order to test, whether a plain text password is equal to the salted SHA, you need to:
- strip the hash method-specifier with e.g. sed.
- decode the base64 string
- extract the last 4 bytes, this is the salt
- concatenate the the salt to the plain text password
- hash it
- compare
The base64-decoded string contains the hash in binary form and can't be printed, so we will convert it to hex with od. The first 3 steps are being done by the following code:
#!/bin/bash
output=$(slappasswd -h {SSHA} -s password)
hashsalt=$( echo -n $output | sed 's/{SSHA}//' | base64 -d)
salt=${hashsalt:(-1),(-4)}
echo $output
echo $(echo -n $hashsalt | od -A n -t x1)
echo "Salt: $salt"
The output could be:
{SSHA}fDu0PgKDn1Di9W1HMINpPXRqQ9jTYjuH
7c 3b b4 3e 02 83 9f 50 e2 f5 6d 47 30 83 69 3d 74 6a 43 d8 d3 62 3b 87
<------------------------- Hash --------------------------> <-- Salt-->
Salt: ▒b;▒
So now we have to concatenate the salt to the plain text password and hash it, this time without salting! The problem I had was understanding, that the salt can really be any character, including non-printable characters. In order to concatenate these non-printable characters we will use printf and their hexadecimal representations:
slappasswd -h {SHA} -s $(printf 'password\xd3\x62\x3b\x87') | sed 's/{SHA}//' | base64 -d | od -A n -t x1
The output is:
7c 3b b4 3e 02 83 9f 50 e2 f5 6d 47 30 83 69 3d 74 6a 43 d8
Which is equal to the hash above. Now we have verified, that 'password' matches the salted SHA.
Thanks and further reading: http://cpansearch.perl.org/src/GSHANK/Crypt-SaltedHash-0.09/lib/Crypt/SaltedHash.pm