Linux – Why is the output of “openssl passwd” different each time

linuxopenssl

The openssl passwd command computes the hash of a password typed at
run-time or the hash of each password in a list. The password list is
taken from the named file for option -in file, from stdin for option
-stdin, and from the command line otherwise. The UNIX standard algorithm crypt and the MD5-based BSD password algorithm 1 and its
Apache variant apr1 are available.

I understand the term "hash" to mean "turn an input into an output from which is it difficult/impossible to derive the original input." More specifically, the input:output relationship after hashing is N:M, where M<=N (i.e. hash collision is possible).

Why is the output of "openssl passwd" different run successively with the same input?

> openssl passwd
Password:
Verifying - Password:
ZTGgaZkFnC6Pg
> openssl passwd
Password:
Verifying - Password:
wCfi4i2Bnj3FU
> openssl passwd -1 "a"
$1$OKgLCmVl$d02jECa4DXn/oXX0R.MoQ/
> openssl passwd -1 "a"
$1$JhSBpnWc$oiu2qHyr5p.ir0NrseQes1

I must not understand the purpose of this function, because it looks like running the same hash algorithm on the same input produces multiple unique outputs. I guess I'm confused by this seeming N:M input:output relationship where M>N.

Best Answer

> openssl passwd -1 "a"
$1$OKgLCmVl$d02jECa4DXn/oXX0R.MoQ/

This is the extended Unix-style crypt(3) password hash syntax, specifically the MD5 version of it.

The first $1$ identifies the hash type, the next part OKgLCmVlis the salt used in encrypting the password, then after the separator $ character to the end of line is the actual password hash.

So, if you take the salt part from the first encryption and use it with the subsequent ones, you should always get the same result:

> openssl passwd -1 -salt "OKgLCmVl" "a"
$1$OKgLCmVl$d02jECa4DXn/oXX0R.MoQ/
> openssl passwd -1 -salt "OKgLCmVl" "a"
$1$OKgLCmVl$d02jECa4DXn/oXX0R.MoQ/

When you're changing a password, you should always switch to a new salt. This prevents anyone finding out after the fact whether the new password was actually the same as the old one. (If you want to prevent the re-use of old passwords, you can of course hash the new password candidate twice: once with the old salt and then, if the result is different from the old password and thus acceptable, again with a new salt.)

If you use openssl passwd with no options, you get the original crypt(3)-compatible hash, as described by dave_thompson_085. With it, the salt is two first letters of the hash:

> openssl passwd "a"
imM.Fa8z1RS.k
> openssl passwd -salt "im" "a"
imM.Fa8z1RS.k

You should not use this old hash style in any new implementation, as it restricts the effective password length to 8 characters, and has too little salt to adequately protect against modern methods.

(I once calculated the amount of data required to store a full set of rainbow tables for every classic crypt(3) hash. I don't remember the exact result, but assuming my calculations were correct, it was on the order of "a modest stack of multi-terabyte disks". In my opinion, that places it within the "organized criminals could do it" range.)

Related Question