-module(argus). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/argus.gleam"). -export([hasher/0, hasher_argon2i/0, algorithm/2, time_cost/2, memory_cost/2, parallelism/2, hash_length/2, gen_salt/0, hash/3, verify/2]). -export_type([argon2_algorithm/0, hasher/0, hashes/0, hash_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type argon2_algorithm() :: argon2d | argon2i | argon2id. -opaque hasher() :: {hasher, argon2_algorithm(), integer(), integer(), integer(), integer()}. -type hashes() :: {hashes, bitstring(), binary()}. -type hash_error() :: output_pointer_is_null | output_too_short | output_too_long | password_too_short | password_too_long | salt_too_short | salt_too_long | associated_data_too_short | associated_data_too_long | secret_too_short | secret_too_long | time_cost_too_small | time_cost_too_large | memory_cost_too_small | memory_cost_too_large | too_few_lanes | too_many_lanes | password_pointer_mismatch | salt_pointer_mismatch | secret_pointer_mismatch | associated_data_pointer_mismatch | memory_allocation_error | free_memory_callback_null | allocate_memory_callback_null | incorrect_parameter | incorrect_type | invalid_algorithm | output_pointer_mismatch | too_few_threads | too_many_threads | not_enough_memory | encoding_failed | decoding_failed | thread_failure | decoding_length_failure | verification_failure | unknown_error_code. -file("src/argus.gleam", 71). ?DOC( " Create a new hasher with default settings based on the\n" " [OWASP recommendations](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id).\n" "\n" " Note: if you change the algorithm to Argon2i, you will need to change the\n" " `memory_cost` to 12_228 (12 mebibytes) or less for performance reasons.\n" "\n" " The `hasher_argon2i` function is provided with the recommended settings for\n" " Argon2i.\n" ). -spec hasher() -> hasher(). hasher() -> {hasher, argon2id, 2, 19456, 1, 32}. -file("src/argus.gleam", 85). ?DOC( " Create a new hasher with default settings based on the\n" " [OWASP recommendations](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id) for\n" " Argon2i.\n" ). -spec hasher_argon2i() -> hasher(). hasher_argon2i() -> {hasher, argon2i, 3, 12228, 1, 32}. -file("src/argus.gleam", 97). ?DOC(" Set the algorithm to use for the hasher.\n"). -spec algorithm(hasher(), argon2_algorithm()) -> hasher(). algorithm(Hasher, Algorithm) -> _record = Hasher, {hasher, Algorithm, erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record)}. -file("src/argus.gleam", 102). ?DOC(" Set the time cost to use for the hasher.\n"). -spec time_cost(hasher(), integer()) -> hasher(). time_cost(Hasher, Time_cost) -> _record = Hasher, {hasher, erlang:element(2, _record), Time_cost, erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record)}. -file("src/argus.gleam", 107). ?DOC(" Set the memory cost to use for the hasher.\n"). -spec memory_cost(hasher(), integer()) -> hasher(). memory_cost(Hasher, Memory_cost) -> _record = Hasher, {hasher, erlang:element(2, _record), erlang:element(3, _record), Memory_cost, erlang:element(5, _record), erlang:element(6, _record)}. -file("src/argus.gleam", 112). ?DOC(" Set the parallelism to use for the hasher.\n"). -spec parallelism(hasher(), integer()) -> hasher(). parallelism(Hasher, Parallelism) -> _record = Hasher, {hasher, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), Parallelism, erlang:element(6, _record)}. -file("src/argus.gleam", 117). ?DOC(" Set the hash length to use for the hasher.\n"). -spec hash_length(hasher(), integer()) -> hasher(). hash_length(Hasher, Hash_length) -> _record = Hasher, {hasher, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, _record), Hash_length}. -file("src/argus.gleam", 167). ?DOC(" Generate a random salt of at least 64 bytes.\n"). -spec gen_salt() -> binary(). gen_salt() -> argus_nif:gen_salt(). -file("src/argus.gleam", 139). ?DOC( " Hash a password using the provided hasher.\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " import argus\n" " \n" " let assert Ok(hashes) =\n" " argus.hasher()\n" " |> argus.algorithm(argus.Argon2id)\n" " |> argus.time_cost(3)\n" " |> argus.memory_cost(12228)\n" " |> argus.parallelism(1)\n" " |> argus.hash_length(32)\n" " |> argus.hash(\"password\", gen_salt())\n" " \n" " let assert Ok(True) = argus.verify(hashes.encoded_hash, \"password\")\n" " ```\n" ). -spec hash(hasher(), binary(), binary()) -> {ok, hashes()} | {error, hash_error()}. hash(Hasher, Password, Salt) -> Result = argus_nif:hash( Password, Salt, erlang:element(2, Hasher), erlang:element(3, Hasher), erlang:element(4, Hasher), erlang:element(5, Hasher), erlang:element(6, Hasher) ), case Result of {ok, {Raw_hash, Encoded_hash}} -> {ok, {hashes, Raw_hash, Encoded_hash}}; {error, Error} -> {error, Error} end. -file("src/argus.gleam", 161). ?DOC(" Verify a password using the provided encoded hash.\n"). -spec verify(binary(), binary()) -> {ok, boolean()} | {error, hash_error()}. verify(Encoded_hash, Password) -> jargon:verify(Encoded_hash, Password).