Passwords should be a bit longer by default.
Internal: Passwords are binary.
Begin work on safe password storage.

HotCRP stores passwords in the database in cleartext. People hate this
but no one wants to fix it right. Let's start trying to fix it.

USERS SHOULD NOT YET SET $Opt["safePasswords"] TO TRUE BECAUSE
PASSWORD RESET FUNCTIONALITY IS NOT YET IMPLEMENTED.

User interface
--------------
Set $Opt["safePasswords"] = true to store hashed passwords in the
database, rather than cleartext passwords.
Set $Opt["safePasswords"] = 2 and current plaintext passwords will
be automatically upgraded to hashed passwords as users log in.

Keys, etc.
----------
HotCRP password hashing uses SHA-256 HMAC by default. HMAC requires a
secret key; HotCRP creates one by default from random bytes and stores
it in the database. Paranoid installations will want to remove this
key from the database, and might want to change the hash algorithm.
This can be controlled in $Opt.

$Opt["passwordHashMethod"]: The hash method for passwords. Defaults to
  sha256. Should be a constant acceptable to PHP's hash_hmac function.

$Opt["passwordHmacKeyid"]: An integer, indicating which secret key to
  use for password HMAC. Defaults to 0. HotCRP supports several keys
  so, for instance, if one key is compromised, you can allow existing
  users to log in with their password, but then re-save the password
  using the new key.

$Opt["passwordHmacKey.ID"]: The secret key with ID "ID".

Database contents and hashing algorithm
---------------------------------------
A secure password hash is stored in the ContactInfo.password field.
Hashes can be distinguished from plaintext passwords because hashes
start with a space. The actual data stored is:

" " . METHOD . " " . KEYID . " " . SALT . HASH

where METHOD is the hash_hmac method ("sha256" by default), KEYID
identifies the secret key, SALT is 16 random bytes, and HASH is a
binary string equal to

hash_hmac(METHOD, KEY[KEYID], SALT . PASSWORD, true).

User interface
--------------
The system cannot recover password plaintext for users with hashed
passwords. Emails to such users don't contain passwords, and their
profile pages also present passwords differently.

Credit
------
In September 2012, Alexandre Dulaunoy at Dragon Research Group offered
this problem as a "DRG Challenge". Two people, Benoit Roussille and
David Durvaux of AutopsIT.org, rose to the challenge. Their patch
allowed the database to contain encrypted or hashed passwords, based
on $Opt entries. For example, $Opt["passwordStorage"] == "encrypted"
stores encrypted passwords using the PHP mcrypt module, and
$Opt["passwordStorage"] == "hash" stores hashed passwords.
Unfortunately, their patches couldn't be applied directly. For one
thing, they arbitrarily changed indentation and whitespace in a large
amount of the code. I am a busy person and it is incredibly annoying
to separate out real changes from stupid, narrow-minded whitespace
changes. Why do people do this? More technically, their design
requires that all passwords in the database be encrypted the same way.
This seems sensible, but makes it difficult or impossible to upgrade a
conference gradually; in fact their system resets all users' passwords
on upgrade! We can't do that to active deployments. There are other
technical issues; they don't use HMAC, they use too many $Opt entries.
But I learned a lot from their implementation, as well as from
https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet

Signed-off-by: Eddie Kohler <ekohler@gmail.com>