Description
As I understand it, the current best practice to selecting the right number of rounds to use is to figure out how much time you're willing to spend computing password hashes, test to see how many rounds that would be, and then use that many rounds until, say, next year, when you need to reevaluate. Would it be better to allow the work parameter to be sent in units of time?
It seems it would be pretty easy to add a new hash method that would accept a minimum time (maybe in addition to a minimum work factor, as a sanity check) to produce an encrypted value. Here's the pseudo code around what I think would be the key changes (https://github.com/kelektiv/node.bcrypt.js/blob/master/src/bcrypt.cc#L235):
thash(pwd, minTimeMillis, minLogRounds, seed)
// do the usual setup as in hash()
// "seed" is the only portion of the normal salt that is needed for this, I think
...
done = false;
log_rounds = minLogRounds;
startTimeMillis = now
while (!done) {
for (k = 0; k < rounds; k++) {
// do the normal expand state stuff here
}
elapsedTimeMillis = now - startTimeMillis;
if (elapsedTimeMillis < minTimeMillis)
rounds = rounds * 2;
log_rounds = log_rounds + 1;
else
done = true;
}
...
That way, you could use
const hashed = await bcrypt.thash(plainTextPassword, minTimeMillis, minLogRounds);
where minMillis is less likely to need to be periodically re-evaluated and devs can more easily think about how much time they can spare to do the hashing. Also, there may be reasonable default settings for both parameters, which would allow:
const hashed = await bcrypt.thash(plainTextPassword);
The seed parameter could be generated automatically if it's not provided, just like the full salt is generated automatically right now.
The output would look just like the output of hash and would contain all of the usual information (version, seed, logr, encrypted), so there would be no issue with compatibility.