Packages
argon2_elixir
4.1.1
4.1.3
4.1.2
4.1.1
4.1.0
4.0.0
3.2.1
3.2.0
3.1.0
3.0.0
2.4.1
2.4.0
2.3.0
2.2.1
2.2.0
2.1.2
2.1.1
2.1.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.3.3
1.3.1
1.3.0
1.2.14
1.2.13
1.2.12
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
0.12.0
0.11.4
0.11.3
0.11.2
0.11.0
0.10.1
0.10.0
0.9.1
0.9.0
0.8.0
Argon2 password hashing algorithm for Elixir
Current section
Files
Jump to
Current section
Files
c_src/argon2_nif.c
/* Argon2 password hashing algorithm for use with Elixir
*
* Copyright 2016-2017 David Whitlock
*
* This is licensed under the Apache Public License 2.0
*
* The license and copyright information for the reference implementation
* is detailed below:
*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "argon2.h"
#include "encoding.h"
#include "core.h"
#include "erl_nif.h"
#define MAX_ENCODEDLEN 1024
ERL_NIF_TERM argon2_hash_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary pwd, salt;
ERL_NIF_TERM result_term;
unsigned int t_cost, m, m_cost, parallelism, raw_output, hashlen, encodedlen, type_int, version;
argon2_type type;
argon2_context context;
int result;
uint8_t *out;
char *hash, *encoded;
if (argc != 10 || !enif_get_uint(env, argv[0], &t_cost) ||
!enif_get_uint(env, argv[1], &m) ||
!enif_get_uint(env, argv[2], ¶llelism) ||
!enif_inspect_binary(env, argv[3], &pwd) ||
!enif_inspect_binary(env, argv[4], &salt) ||
!enif_get_uint(env, argv[5], &raw_output) ||
!enif_get_uint(env, argv[6], &hashlen) ||
!enif_get_uint(env, argv[7], &encodedlen) ||
!enif_get_uint(env, argv[8], &type_int) ||
!enif_get_uint(env, argv[9], &version))
return enif_make_badarg(env);
m_cost = 1U << m;
type = (argon2_type)type_int;
if (hashlen > ARGON2_MAX_OUTLEN) {
return enif_make_int(env, ARGON2_OUTPUT_TOO_LONG);
}
if (hashlen < ARGON2_MIN_OUTLEN) {
return enif_make_int(env, ARGON2_OUTPUT_TOO_SHORT);
}
out = malloc(hashlen);
if (!out) {
return enif_make_int(env, ARGON2_MEMORY_ALLOCATION_ERROR);
}
hash = malloc(hashlen * 2 + 1);
if (!hash) {
return enif_make_int(env, ARGON2_MEMORY_ALLOCATION_ERROR);
}
encoded = malloc(encodedlen + 1);
if (!encoded) {
return enif_make_int(env, ARGON2_MEMORY_ALLOCATION_ERROR);
}
context.out = out;
context.outlen = (uint32_t)hashlen;
context.pwd = CONST_CAST(uint8_t *)pwd.data;
context.pwdlen = (uint32_t)pwd.size;
context.salt = CONST_CAST(uint8_t *)salt.data;
context.saltlen = (uint32_t)salt.size;
context.secret = NULL;
context.secretlen = 0;
context.ad = NULL;
context.adlen = 0;
context.t_cost = t_cost;
context.m_cost = m_cost;
context.lanes = parallelism;
context.threads = parallelism;
context.allocate_cbk = NULL;
context.free_cbk = NULL;
context.flags = ARGON2_DEFAULT_FLAGS;
context.version = version ? version : ARGON2_VERSION_NUMBER;
result = argon2_ctx(&context, type);
if (result != ARGON2_OK) {
clear_internal_memory(out, hashlen);
free(out);
free(hash);
free(encoded);
return enif_make_int(env, result);
}
/* if raw hash requested, write it */
if (raw_output) {
int i;
for (i = 0; i < hashlen; i++)
sprintf(hash + i * 2, "%02x", out[i]);
}
/* if encoding requested, write it */
if (encodedlen) {
if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) {
clear_internal_memory(out, hashlen); /* wipe buffers if error */
clear_internal_memory(encoded, encodedlen);
free(out);
free(hash);
free(encoded);
return enif_make_int(env, ARGON2_ENCODING_FAIL);
}
}
clear_internal_memory(out, hashlen);
free(out);
result_term = enif_make_tuple2(env, enif_make_string(env, hash, ERL_NIF_LATIN1),
enif_make_string(env, encoded, ERL_NIF_LATIN1));
free(hash);
free(encoded);
return result_term;
}
static ERL_NIF_TERM argon2_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
char encoded[MAX_ENCODEDLEN];
ErlNifBinary pwd;
unsigned int type_int;
argon2_type type;
int ret;
if (argc != 3 || !enif_get_string(env, argv[0], encoded, sizeof(encoded), ERL_NIF_LATIN1) ||
!enif_inspect_binary(env, argv[1], &pwd) ||
!enif_get_uint(env, argv[2], &type_int))
return enif_make_badarg(env);
type = (argon2_type)type_int;
ret = argon2_verify(encoded, pwd.data, pwd.size, type);
return enif_make_int(env, ret);
}
static ERL_NIF_TERM argon2_error_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
int error_code;
char const *ret;
if (argc != 1 || !enif_get_int(env, argv[0], &error_code))
return enif_make_badarg(env);
ret = argon2_error_message(error_code);
return enif_make_string(env, ret, ERL_NIF_LATIN1);
}
static ERL_NIF_TERM argon2_encodedlen_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
unsigned int t_cost, m, m_cost, parallelism, saltlen, hashlen, type_int;
argon2_type type;
int ret;
if (argc != 6 || !enif_get_uint(env, argv[0], &t_cost) ||
!enif_get_uint(env, argv[1], &m) ||
!enif_get_uint(env, argv[2], ¶llelism) ||
!enif_get_uint(env, argv[3], &saltlen) ||
!enif_get_uint(env, argv[4], &hashlen) ||
!enif_get_uint(env, argv[5], &type_int))
return enif_make_badarg(env);
m_cost = 1U << m;
type = (argon2_type)type_int;
ret = argon2_encodedlen(t_cost, m_cost, parallelism, saltlen, hashlen, type);
return enif_make_int(env, ret);
}
static int upgrade(ErlNifEnv *env, void **priv_data, void **old_priv_data, ERL_NIF_TERM load_info)
{
return 0;
}
static ErlNifFunc argon2_nif_funcs[] =
{
{"hash_nif", 10, argon2_hash_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"verify_nif", 3, argon2_verify_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"error_nif", 1, argon2_error_nif},
{"encodedlen_nif", 6, argon2_encodedlen_nif}
};
ERL_NIF_INIT(Elixir.Argon2.Base, argon2_nif_funcs, NULL, NULL, upgrade, NULL)