View raw

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