#include "saltywitch.h" ERL_NIF_TERM saltywitch_pwhash(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary pass, salt; ERL_NIF_TERM term; uint64_t len, ops, mem; unsigned char *out; int alg; ERL_NIF_TERM err = atom_badarg; ERL_NIF_TERM reason = atom_err_opaque; if (enif_get_uint64(env, argv[0], &len) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (enif_inspect_iolist_as_binary(env, argv[1], &pass) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (enif_inspect_binary(env, argv[2], &salt) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (salt.size != crypto_pwhash_SALTBYTES) { reason = atom_err_invalid_salt_size; goto badarg_FAULT; } if (enif_get_uint64(env, argv[3], &ops) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (ops > crypto_pwhash_OPSLIMIT_MAX) { reason = atom_err_pwhash_ops_too_large; goto badarg_FAULT; } else if (ops < crypto_pwhash_OPSLIMIT_MIN) { reason = atom_err_pwhash_ops_too_small; goto badarg_FAULT; } if (enif_get_uint64(env, argv[4], &mem) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (mem > crypto_pwhash_OPSLIMIT_MAX) { reason = atom_err_pwhash_mem_too_large; goto badarg_FAULT; } else if (mem < crypto_pwhash_OPSLIMIT_MIN) { reason = atom_err_pwhash_mem_too_small; goto badarg_FAULT; } if (enif_get_int(env, argv[5], &alg) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } out = enif_make_new_binary(env, len, &term); if (out == NULL) { reason = atom_err_nif_alloc; goto error_FAULT; } if (crypto_pwhash(out, len, (char *) pass.data, pass.size, salt.data, ops, mem, alg) != 0) { goto error_FAULT; } return term; error_FAULT: err = atom_error; badarg_FAULT: return saltywitch_exception(env, err, reason); } ERL_NIF_TERM saltywitch_pwhash_str(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { char out[crypto_pwhash_STRBYTES]; uint64_t ops, mem; ErlNifBinary pass; ERL_NIF_TERM err = atom_badarg; ERL_NIF_TERM reason = atom_err_opaque; (void) argc; if (enif_inspect_iolist_as_binary(env, argv[0], &pass) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (enif_get_uint64(env, argv[1], &ops) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (enif_get_uint64(env, argv[2], &mem) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (crypto_pwhash_str(out, (char *) pass.data, pass.size, ops, mem) != 0) { goto error_FAULT; } return enif_make_string(env, out, ERL_NIF_LATIN1); error_FAULT: err = atom_error; badarg_FAULT: return saltywitch_exception(env, err, reason); } #include ERL_NIF_TERM saltywitch_pwhash_str_verify(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary hash, pass; ERL_NIF_TERM err = atom_badarg; ERL_NIF_TERM reason = atom_err_opaque; (void) argc; if (enif_inspect_iolist_as_binary(env, argv[0], &hash) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (hash.size > crypto_pwhash_STRBYTES) { reason = atom_err_pwhash_too_long; goto badarg_FAULT; } if (enif_inspect_iolist_as_binary(env, argv[1], &pass) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (crypto_pwhash_str_verify((char *) hash.data, (char *) pass.data, pass.size) != 0) { reason = atom_err_verification_failed; goto error_FAULT; } return atom_ok; error_FAULT: err = atom_error; badarg_FAULT: return saltywitch_exception(env, err, reason); } ERL_NIF_TERM saltywitch_pwhash_str_needs_rehash(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary hash; uint64_t ops, mem; ERL_NIF_TERM err = atom_badarg; ERL_NIF_TERM reason = atom_err_opaque; if (enif_inspect_binary(env, argv[0], &hash) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (hash.size > crypto_pwhash_STRBYTES) { reason = atom_err_pwhash_too_long; goto badarg_FAULT; } if (enif_get_uint64(env, argv[1], &ops) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } if (enif_get_uint64(env, argv[2], &mem) == false) { reason = atom_err_invalid_type; goto badarg_FAULT; } switch (crypto_pwhash_str_needs_rehash((char *) hash.data, ops, mem)) { case 0: return atom_ok; case 1: reason = atom_err_pwhash_needs_rehash; } err = atom_error; badarg_FAULT: return saltywitch_exception(env, err, reason); }