lists.openwall.net | 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 linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <20150313142613.GA2303@bolet.org> Date: Fri, 13 Mar 2015 15:26:13 +0100 From: Thomas Pornin <pornin@...et.org> To: discussions@...sword-hashing.net 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 library. 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 advantage. 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 issue. 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