(** Bcrypt implementation of the {!Hito_app.Password_hash.S} port, over safepass. The one place that names a hashing algorithm. *) (* The log2 work factor. safepass defaults to 6, which is far too cheap for a stored password verifier; 12 is the common baseline and makes a verification take on the order of a quarter second, so an offline attack against a leaked verifier pays that cost for every guess. Raising this later is safe: a hash records its own cost, so existing verifiers keep verifying. *) let cost = 12 let hash password = Bcrypt.string_of_hash (Bcrypt.hash ~count:cost password) (* A stored verifier that does not parse as a bcrypt hash is corrupt storage, not a wrong password. safepass reports it from [verify], not from [hash_of_string]. Refuse the sign-in (fail closed) but say so on stderr, so the corruption is visible rather than read as a typo. *) let verify ~hash password = match Bcrypt.verify password (Bcrypt.hash_of_string hash) with | verified -> verified | exception e -> Printf.eprintf "hito: stored password verifier is not a bcrypt hash: %s\n%!" (Printexc.to_string e); false