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