lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Fri, 13 Mar 2015 15:26:13 +0100
From: Thomas Pornin <>
Subject: Re: [PHC] Password hashing by itself is not enough

On Thu, Mar 12, 2015 at 09:19:00PM -0700, Bill Cox wrote:
> Should the PHC recommend that master secrets of some sort be added to
> the key material, so that if the password database is stolen, but not
> the master secret, no harm is done?  There is no parameter for
> additional secret key material in the PHS function.

Adding an additional secret key can be added generically, in (at least)
four ways, to any password hashing function:

 1. Store: salt + HMAC_K(PHS(pass, salt))
 2. Store: salt + PHS(HMAC_K(pass), salt)
 3. Store: salt + AES_K(PHS(pass, salt))
 4. Store: salt + PHS(AES_K(pass), salt)

I have used here "HMAC" to mean "some appropriate MAC function" and
"AES" to mean "some symmetric encryption scheme".

These methods are not completely equivalent:

 -- With method 1, you forfeit any offline work factor extension that
 the PHS may offer (i.e. you can no longer raise the work factor of a
 hash without knowing the password). With methods 2 and 4 such work
 factor extension can be done easily (if the PHS supports it, of
 course). With method 3, you can do it but you need the key.

 -- With methods 2 and 4, you must either encode the output of HMAC
 or AES with Base64 or equivalent; or the PHS must support arbitrary
 binary input (all candidates should support arbitrary binary input
 anyway, it was part of the CfP).

 -- Method 4 requires some form of symmetric encryption that is either
 deterministic, or can be made deterministic (e.g. an extra IV is
 stored). ECB mode, for all its shortcomings, would work.

 -- Method 3 can be rather simple if you configure PHS to output exactly
 128 bits, in which case you can do "raw" single-block encryption.

 -- Methods 1 and 3 require obtaining the "raw" PHS output, not a
 composite string that encodes the output and the salt. In that sense,
 they can be a bit cumbersome to retrofit on, say, an existing bcrypt

The important points (in my opinion) to take into account are:

 1. This key strengthening (some people have coined the expression
 "peppering" as a bad pun on "salting") can be done generically; the
 underlying PHS needs not be modified or even made aware of it.

 2. Keys imply key management, always a tricky thing. Key should be
 generated appropriately (that's not hard but it can be botched in
 horrible ways), and stored with care. Sometimes the OS or programming
 framework can help (e.g. DPAPI on Windows). Sometimes it makes things
 more difficult. You need backups (a lost key implies losing all the
 stored passwords), but stolen backups are a classical source of
 password hashes leakage, so if you do not take enough care of the
 security of your backups then the advantage offered by the key can go
 to naught.

 3. For some historical reasons, many people feel the need to change
 keys regularly. This is rather misguided: key rotation makes sense in
 an army or spy network where there are many keys, and partial
 compromissions are the normal and expected situation, so a spy network
 must, by necessity, be in permanent self-cleansing recovery mode; when
 there is a single key and the normal situation is that the key is NOT
 compromised, changing it brings no tangible advantage. Nevertheless,
 people insist on it, and this is difficult. The "method 3" above
 (encryption of the PHS result) is the one that makes key rotation
 easiest since you can process all stored hashes in one go, as a
 night-time administrative procedure.

 4. Key strengthening makes sense only insofar as you can keep the key
 secret even when the attacker can see the hashes. In a classical
 Web-server-verifies-user-passwords context, the hashes are in the
 database; one can argue that database contents can be dumped through a
 SQL injection attack, but a key stored outside the database might evade
 this partial breach. But if the key is in the database, or the breach
 is a stolen whole-server backup, then the key does not bring any

 5. If you _can_ store a key that attackers won't steal, even if they
 get all the hashes, then you can forget all this PHS nonsense and just
 use HMAC_K(pass) (or HMAC_K(user+pass)). The key must thus be
 envisioned as an additional protection, a third layer (first layer is:
 don't let outsiders read your hashes; second layer is: make it so that
 your hashes are expensive to compute, in case the first layer was
 broken through).

>From all of the above, I recommend the following:

 -- Publish a PHS "standard API" that does not include any provision for
 an additional secret key.

 -- Publish _another_ API, possibly even an _implementation_, that wraps
 around the previous one, and provides key-based password hashing with
 the "method 3": PHS is used to produce a 128-bit output, and that output
 is encrypted symmetrically with AES (single-block encryption).

 -- Write a note that states that an additional key is _possible_, and
 if one wants it then it should be done properly (as demonstrated by the
 implementation from the previous point), but cannot be recommended in
 all generality because whether it is a good idea or not depends on the
 context. Keys mean key management, an often underestimated thorny

Arguably, doing anything with such key strengthening is outside of the
scope of PHC and may/should be left to other people.

	--Thomas Pornin

Powered by blists - more mailing lists