Thread: MD5 salt in pg_authid password hashes

MD5 salt in pg_authid password hashes

From
Stefan Weiss
Date:
From the manual:

| Because MD5-encrypted passwords use the role name as cryptographic
| salt, renaming a role clears its password if the password is
| MD5-encrypted.

In backend/commands/user.c

    if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
                        encrypted_password))
        elog(ERROR, "password encryption failed");
    new_record[Anum_pg_authid_rolpassword - 1] =
        CStringGetTextDatum(encrypted_password);

I don't understand this. Why was the role name chosen as a salt? Apart
from the problem that the hash becomes unusable when a role is renamed,
roles names are very poor salts. Given how relatively predictable they
are, the hash could just as well be left unsalted.

There is a comment in libpq/md5.c which more or less acknowleges this:
"Place salt at the end because it may be known by users trying to crack
the MD5 output." Ignoring for the moment that cracking PG passwords is
probably not very common, the position of the salt does little to
prevent attacks.

A random salt would eliminate both weaknesses. The only explanation I
can come up with is that the current method of hashing has been kept for
historic reasons, as changing to a random salt would break existing hashes.

Or is there something else I've overlooked?


regards,
stefan


PS: Strictly speaking, the expression "MD5-encrypted" in the manual is
incorrect - MD5 is a hashing algorithm, not an encryption algorithm.
</nitpick>


--
LOAD"Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!",8,1
RUN!

Re: MD5 salt in pg_authid password hashes

From
Adrian Klaver
Date:
On Wednesday, February 15, 2012 6:34:21 pm Stefan Weiss wrote:
> From the manual:
> | Because MD5-encrypted passwords use the role name as cryptographic
> | salt, renaming a role clears its password if the password is
> | MD5-encrypted.
>
> In backend/commands/user.c
>
>     if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
>                         encrypted_password))
>         elog(ERROR, "password encryption failed");
>     new_record[Anum_pg_authid_rolpassword - 1] =
>         CStringGetTextDatum(encrypted_password);
>
> I don't understand this. Why was the role name chosen as a salt? Apart
> from the problem that the hash becomes unusable when a role is renamed,
> roles names are very poor salts. Given how relatively predictable they
> are, the hash could just as well be left unsalted.

When you alter the role name you are told the password has been cleared. It
would be fairly easy to wrap the rename and the setting of the password in a
transaction.

>
> There is a comment in libpq/md5.c which more or less acknowleges this:
> "Place salt at the end because it may be known by users trying to crack
> the MD5 output." Ignoring for the moment that cracking PG passwords is
> probably not very common, the position of the salt does little to
> prevent attacks.
>
> A random salt would eliminate both weaknesses. The only explanation I
> can come up with is that the current method of hashing has been kept for
> historic reasons, as changing to a random salt would break existing hashes.
>
> Or is there something else I've overlooked?

Yes:
http://www.postgresql.org/docs/9.0/static/encryption-options.html
"
Encrypting Passwords Across A Network
The MD5 authentication method double-encrypts the password on the client before
sending it to the server. It first MD5-encrypts it based on the user name, and
then encrypts it based on a random salt sent by the server when the database
connection was made. It is this double-encrypted value that is sent over the
network to the server. Double-encryption not only prevents the password from
being discovered, it also prevents another connection from using the same
encrypted password to connect to the database server at a later time.


Encrypting Data Across A Network
SSL connections encrypt all data sent across the network: the password, the
queries, and the data returned. The pg_hba.conf file allows administrators to
specify which hosts can use non-encrypted connections (host) and which require
SSL-encrypted connections (hostssl). Also, clients can specify that they connect
to servers only via SSL. Stunnel or SSH can also be used to encrypt
transmissions.
"
>
>
> regards,
> stefan
>
>
> PS: Strictly speaking, the expression "MD5-encrypted" in the manual is
> incorrect - MD5 is a hashing algorithm, not an encryption algorithm.
> </nitpick>

--
Adrian Klaver
adrian.klaver@gmail.com

Re: MD5 salt in pg_authid password hashes

From
Stefan Weiss
Date:
On 2012-02-16 04:18, Adrian Klaver wrote:
> When you alter the role name you are told the password has been cleared. It
> would be fairly easy to wrap the rename and the setting of the password in a
> transaction.

But this shouldn't be necessary. I don't get why the salt has to be
linked with the role name. This problem would be a non-issue with a
random salt.

> Encrypting Passwords Across A Network
> The MD5 authentication method double-encrypts the password on the client before
> sending it to the server. It first MD5-encrypts it based on the user name, and
> then encrypts it based on a random salt sent by the server when the database
> connection was made. It is this double-encrypted value that is sent over the
> network to the server. Double-encryption not only prevents the password from
> being discovered, it also prevents another connection from using the same
> encrypted password to connect to the database server at a later time.

I must be missing something here... the *client* applies the salt,
because he knows it, and then sends the salted hash? Then what's the
point of using a salt at all?
The second "encryption" layer just protects the communication channel,
and has nothing to do with what I'm concerned with. It's redundant if a
secure channel already exists (SSL or TLS or whatever). But I have to
admit that I didn't read the source for this part, so I may indeed be
missing something.

> Encrypting Data Across A Network
> SSL connections encrypt all data sent across the network: the password, the
> queries, and the data returned. The pg_hba.conf file allows administrators to
> specify which hosts can use non-encrypted connections (host) and which require
> SSL-encrypted connections (hostssl). Also, clients can specify that they connect
> to servers only via SSL. Stunnel or SSH can also be used to encrypt
> transmissions.

Just so. But this still leaves the question why the hashing/salting in
PG works differently than just about anywhere else. The client isn't
supposed to know or care about the salt. Normally, salting is a purely
server-side protection against attackers who would generate lookup
tables for common password hashes, in the hope of getting their hands on
a list of actual password hashes. If the salt is as predictable as a
user/role name, it's nowhere near good enough to protect against such an
attack. At best, it might increase the size of the lookup tables by 2 or
3 orders of magnitude, which is no challenge at all with a good word
list ("backup", "dba", "slony", "postgres", "master", ...). Compare this
to a 4-byte random salt.


regards,
stefan


--
LOAD"Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!",8,1
RUN!