Skip to content

Commit

Permalink
Cookbook recipe for hashing passwords with Argon2 (#2944)
Browse files Browse the repository at this point in the history
  • Loading branch information
boechat107 authored Feb 4, 2025
1 parent b1df194 commit ee98911
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
54 changes: 54 additions & 0 deletions data/cookbook/salt-and-hash-password-with-argon2/00-hashargon2.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
packages:
- name: argon2
tested_version: "1.0.2"
used_libraries:
- argon2
---

(* Configuration for password hashing based on OWASP recommendations and Argon2
default values. Note this example uses only the recommended "Argon2id"
variation.
References:
- https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
- https://github.com/P-H-C/phc-winner-argon2 *)
let t_cost = 2 and
m_cost = 65536 and
parallelism = 1 and
hash_len = 32 and
salt_len = 10

(* The hash output length. *)
let encoded_len =
Argon2.encoded_len ~t_cost ~m_cost ~parallelism ~salt_len ~hash_len ~kind:ID

(* Generate a salt string for a given length using only characters in the range
"A-Z". This is a simplistic generator and should be replaced with
cryptographically secure random number generator ("mirage-crypto", for
example). *)
let gen_salt len =
let rand_char _ = 65 + (Random.int 26) |> char_of_int in
String.init len rand_char

(* Return an encoded hash string for the given password. The encoded password
contains the required metadata for future verification. *)
let hash_password passwd =
Result.map Argon2.ID.encoded_to_string
(Argon2.ID.hash_encoded
~t_cost ~m_cost ~parallelism ~hash_len ~encoded_len
~pwd:passwd ~salt:(gen_salt salt_len))

(* Verifie if the encoded hash string matches the given password. *)
let verify encoded_hash pwd =
match Argon2.verify ~encoded:encoded_hash ~pwd ~kind:ID with
| Ok true_or_false -> true_or_false
| Error VERIFY_MISMATCH -> false
| Error e -> raise (Failure (Argon2.ErrorCodes.message e))

let () =
let hashed_pwd = Result.get_ok (hash_password "my insecure password") in
Printf.printf "Hashed password: %s\n" hashed_pwd;
let fst_attempt = "my secure password" in
Printf.printf "'%s' is correct? %B\n" fst_attempt (verify hashed_pwd fst_attempt);
let snd_attempt = "my insecure password" in
Printf.printf "'%s' is correct? %B\n" snd_attempt (verify hashed_pwd snd_attempt)
2 changes: 2 additions & 0 deletions data/cookbook/tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ categories:
slug: calculate-sha-256-digest-of-file
- title: Sign and Verify a Message With an HMAC Digest
slug: sign-and-verify-hmac-digest
- title: Salt and Hash a Password With Argon2
slug: salt-and-hash-password-with-argon2
- title: Salt and Hash a Password With PBKDF2
slug: salt-and-hash-password-with-pkgdf2
- title: Data Structures & Algorithms
Expand Down

0 comments on commit ee98911

Please sign in to comment.