From de85c2e526755fc4cbf48536133821261e69fcc9 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Fri, 8 Jul 2016 15:27:20 -0500 Subject: [PATCH 01/18] Implementing password_verify and password_get_info for Argon2 --- ext/standard/password.c | 164 +++++++++++++++++++++++++++--------- ext/standard/php_password.h | 10 ++- 2 files changed, 132 insertions(+), 42 deletions(-) diff --git a/ext/standard/password.c b/ext/standard/password.c index d01ddb0563c..82ed9fa7c30 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -39,6 +39,8 @@ PHP_MINIT_FUNCTION(password) /* {{{ */ { REGISTER_LONG_CONSTANT("PASSWORD_DEFAULT", PHP_PASSWORD_DEFAULT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT", PHP_PASSWORD_BCRYPT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2I", PHP_PASSWORD_ARGON2I, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2D", PHP_PASSWORD_ARGON2D, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT_DEFAULT_COST", PHP_PASSWORD_BCRYPT_COST, CONST_CS | CONST_PERSISTENT); @@ -51,6 +53,10 @@ static char* php_password_get_algo_name(const php_password_algo algo) switch (algo) { case PHP_PASSWORD_BCRYPT: return "bcrypt"; + case PHP_PASSWORD_ARGON2I: + return "argon2i"; + case PHP_PASSWORD_ARGON2D: + return "argon2d"; case PHP_PASSWORD_UNKNOWN: default: return "unknown"; @@ -59,7 +65,11 @@ static char* php_password_get_algo_name(const php_password_algo algo) static php_password_algo php_password_determine_algo(const char *hash, const size_t len) { - if (len > 3 && hash[0] == '$' && hash[1] == '2' && hash[2] == 'y' && len == 60) { + if (hash[0] == '$' && strstr(hash, "argon2i")) { + return PHP_PASSWORD_ARGON2I; + } else if (hash[0] == '$' && strstr(hash, "argon2d")) { + return PHP_PASSWORD_ARGON2D; + } else if (len > 3 && hash[0] == '$' && hash[1] == '2' && hash[2] == 'y' && len == 60) { return PHP_PASSWORD_BCRYPT; } @@ -167,6 +177,19 @@ PHP_FUNCTION(password_get_info) add_assoc_long(&options, "cost", cost); } break; + case PHP_PASSWORD_ARGON2I: + case PHP_PASSWORD_ARGON2D: + { + zend_long m_cost = PHP_ARGON2_M_COST; + zend_long t_cost = PHP_ARGON2_T_COST; + zend_long lanes = PHP_ARGON2_LANES; + + sscanf(hash, "$%*[argon2id]$v=%*ld$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &m_cost, &t_cost, &lanes); + add_assoc_long(&options, "m_cost", m_cost); + add_assoc_long(&options, "t_cost", t_cost); + add_assoc_long(&options, "lanes", lanes); + } + break; case PHP_PASSWORD_UNKNOWN: default: break; @@ -213,6 +236,32 @@ PHP_FUNCTION(password_needs_rehash) } } break; + case PHP_PASSWORD_ARGON2I: + case PHP_PASSWORD_ARGON2D: + { + zend_long new_m_cost = PHP_ARGON2_M_COST, m_cost = 0; + zend_long new_t_cost = PHP_ARGON2_T_COST, t_cost = 0; + zend_long new_lanes = PHP_ARGON2_LANES, lanes = 0; + + if (options && (option_buffer = zend_hash_str_find(options, "m_cost", sizeof("m_cost")-1)) != NULL) { + new_m_cost = zval_get_long(option_buffer); + } + + if (options && (option_buffer = zend_hash_str_find(options, "t_cost", sizeof("t_cost")-1)) != NULL) { + new_t_cost = zval_get_long(option_buffer); + } + + if (options && (option_buffer = zend_hash_str_find(options, "lanes", sizeof("lanes")-1)) != NULL) { + new_lanes = zval_get_long(option_buffer); + } + + sscanf(hash, "$%*[argon2id]$v=%*ld$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &m_cost, &t_cost, &lanes); + + if (new_t_cost != t_cost || new_m_cost != m_cost || new_lanes != lanes) { + RETURN_TRUE; + } + } + break; case PHP_PASSWORD_UNKNOWN: default: break; @@ -228,17 +277,34 @@ PHP_FUNCTION(password_verify) size_t i, password_len, hash_len; char *password, *hash; zend_string *ret; + php_password_algo algo; if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &password, &password_len, &hash, &hash_len) == FAILURE) { RETURN_FALSE; } - if ((ret = php_crypt(password, (int)password_len, hash, (int)hash_len, 1)) == NULL) { - RETURN_FALSE; - } - if (ZSTR_LEN(ret) != hash_len || hash_len < 13) { - zend_string_free(ret); - RETURN_FALSE; + algo = php_password_determine_algo(hash, (size_t) hash_len); + + switch(algo) { + case PHP_PASSWORD_BCRYPT: + { + if ((ret = php_crypt(password, (int)password_len, hash, (int)hash_len, 1)) == NULL) { + RETURN_FALSE; + } + + if (ZSTR_LEN(ret) != hash_len || hash_len < 13) { + zend_string_free(ret); + RETURN_FALSE; + } + } + case PHP_PASSWORD_ARGON2I: + case PHP_PASSWORD_ARGON2D: + { + // @todo: Implement argon2_verify via import + } + case PHP_PASSWORD_UNKNOWN: + default: + RETURN_FALSE; } /* We're using this method instead of == in order to provide @@ -275,23 +341,29 @@ PHP_FUNCTION(password_hash) switch (algo) { case PHP_PASSWORD_BCRYPT: - { - zend_long cost = PHP_PASSWORD_BCRYPT_COST; + { + zend_long cost = PHP_PASSWORD_BCRYPT_COST; - if (options && (option_buffer = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) { - cost = zval_get_long(option_buffer); + if (options && (option_buffer = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) { + cost = zval_get_long(option_buffer); + } + + if (cost < 4 || cost > 31) { + php_error_docref(NULL, E_WARNING, "Invalid bcrypt cost parameter specified: " ZEND_LONG_FMT, cost); + RETURN_NULL(); + } + + required_salt_len = 22; + sprintf(hash_format, "$2y$%02ld$", (long) cost); + hash_format_len = 7; } - - if (cost < 4 || cost > 31) { - php_error_docref(NULL, E_WARNING, "Invalid bcrypt cost parameter specified: " ZEND_LONG_FMT, cost); - RETURN_NULL(); + break; + case PHP_PASSWORD_ARGON2I: + case PHP_PASSWORD_ARGON2D: + { + // @todo: Implement Argon2_hash with options } - - required_salt_len = 22; - sprintf(hash_format, "$2y$%02ld$", (long) cost); - hash_format_len = 7; - } - break; + break; case PHP_PASSWORD_UNKNOWN: default: php_error_docref(NULL, E_WARNING, "Unknown password hashing algorithm: " ZEND_LONG_FMT, algo); @@ -356,30 +428,42 @@ PHP_FUNCTION(password_hash) salt_len = required_salt_len; } - salt[salt_len] = 0; + switch (algo) { + case PHP_PASSWORD_BCRYPT: + { + salt[salt_len] = 0; - hash = safe_emalloc(salt_len + hash_format_len, 1, 1); - sprintf(hash, "%s%s", hash_format, salt); - hash[hash_format_len + salt_len] = 0; + hash = safe_emalloc(salt_len + hash_format_len, 1, 1); + sprintf(hash, "%s%s", hash_format, salt); + hash[hash_format_len + salt_len] = 0; - efree(salt); + efree(salt); - /* This cast is safe, since both values are defined here in code and cannot overflow */ - hash_len = (int) (hash_format_len + salt_len); + /* This cast is safe, since both values are defined here in code and cannot overflow */ + hash_len = (int) (hash_format_len + salt_len); - if ((result = php_crypt(password, (int)password_len, hash, hash_len, 1)) == NULL) { - efree(hash); - RETURN_FALSE; + if ((result = php_crypt(password, (int)password_len, hash, hash_len, 1)) == NULL) { + efree(hash); + RETURN_FALSE; + } + + efree(hash); + + if (ZSTR_LEN(result) < 13) { + zend_string_free(result); + RETURN_FALSE; + } + + RETURN_STR(result); + } + case PHP_PASSWORD_ARGON2I: + case PHP_PASSWORD_ARGON2D: + { + // @todo: Implement Argon2_hash with options + } + default: + RETURN_FALSE; } - - efree(hash); - - if (ZSTR_LEN(result) < 13) { - zend_string_free(result); - RETURN_FALSE; - } - - RETURN_STR(result); } /* }}} */ diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index fdc72b0258e..872afb3befe 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -28,13 +28,19 @@ PHP_FUNCTION(password_get_info); PHP_MINIT_FUNCTION(password); -#define PHP_PASSWORD_DEFAULT PHP_PASSWORD_BCRYPT +#define PHP_PASSWORD_DEFAULT PHP_PASSWORD_ARGON2I #define PHP_PASSWORD_BCRYPT_COST 10 +#define PHP_ARGON2_M_COST 1<<16 +#define PHP_ARGON2_T_COST 3 +#define PHP_ARGON2_LANES 1 typedef enum { PHP_PASSWORD_UNKNOWN, - PHP_PASSWORD_BCRYPT + PHP_PASSWORD_BCRYPT, + PHP_PASSWORD_ARGON2, + PHP_PASSWORD_ARGON2I, + PHP_PASSWORD_ARGON2D } php_password_algo; #endif From 3c7fb71a90dcd37ba64dd0623aea13c9d940fe06 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Fri, 8 Jul 2016 15:31:30 -0500 Subject: [PATCH 02/18] Introducing Argon2 memory, time, and lanes constants PASSWORD_ARGON2_MEMORY_COST PASSWORD_ARGON2_TIME_COST PASSWORD_ARGON2_LANES --- ext/standard/password.c | 16 ++++++++++------ ext/standard/php_password.h | 6 +++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ext/standard/password.c b/ext/standard/password.c index 82ed9fa7c30..4da1682056a 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -44,6 +44,10 @@ PHP_MINIT_FUNCTION(password) /* {{{ */ REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT_DEFAULT_COST", PHP_PASSWORD_BCRYPT_COST, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_MEMORY_COST", PHP_PASSWORD_ARGON2_MEMORY_COST, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_TIME_COST", PHP_PASSWORD_ARGON2_TIME_COST, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_LANES", PHP_PASSWORD_ARGON2_LANES, CONST_CS | CONST_PERSISTENT); + return SUCCESS; } /* }}} */ @@ -180,9 +184,9 @@ PHP_FUNCTION(password_get_info) case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { - zend_long m_cost = PHP_ARGON2_M_COST; - zend_long t_cost = PHP_ARGON2_T_COST; - zend_long lanes = PHP_ARGON2_LANES; + zend_long m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; + zend_long t_cost = PHP_PASSWORD_ARGON2_TIME_COST; + zend_long lanes = PHP_PASSWORD_ARGON2_LANES; sscanf(hash, "$%*[argon2id]$v=%*ld$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &m_cost, &t_cost, &lanes); add_assoc_long(&options, "m_cost", m_cost); @@ -239,9 +243,9 @@ PHP_FUNCTION(password_needs_rehash) case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { - zend_long new_m_cost = PHP_ARGON2_M_COST, m_cost = 0; - zend_long new_t_cost = PHP_ARGON2_T_COST, t_cost = 0; - zend_long new_lanes = PHP_ARGON2_LANES, lanes = 0; + zend_long new_m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST, m_cost = 0; + zend_long new_t_cost = PHP_PASSWORD_ARGON2_TIME_COST, t_cost = 0; + zend_long new_lanes = PHP_PASSWORD_ARGON2_LANES, lanes = 0; if (options && (option_buffer = zend_hash_str_find(options, "m_cost", sizeof("m_cost")-1)) != NULL) { new_m_cost = zval_get_long(option_buffer); diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index 872afb3befe..4c6e1133919 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -31,9 +31,9 @@ PHP_MINIT_FUNCTION(password); #define PHP_PASSWORD_DEFAULT PHP_PASSWORD_ARGON2I #define PHP_PASSWORD_BCRYPT_COST 10 -#define PHP_ARGON2_M_COST 1<<16 -#define PHP_ARGON2_T_COST 3 -#define PHP_ARGON2_LANES 1 +#define PHP_PASSWORD_ARGON2_MEMORY_COST 1<<16 +#define PHP_PASSWORD_ARGON2_TIME_COST 3 +#define PHP_PASSWORD_ARGON2_LANES 1 typedef enum { PHP_PASSWORD_UNKNOWN, From c2551a74d479e933054415920d1bcc5fd33d1d33 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Fri, 8 Jul 2016 23:45:19 -0500 Subject: [PATCH 03/18] Working implementation with password_hash, password_verify --- ext/standard/argon2lib/argon2.c | 398 ++++++++++++ ext/standard/argon2lib/argon2.h | 372 +++++++++++ ext/standard/argon2lib/blake2/blake2-impl.h | 143 +++++ ext/standard/argon2lib/blake2/blake2.h | 74 +++ ext/standard/argon2lib/blake2/blake2b.c | 372 +++++++++++ .../argon2lib/blake2/blamka-round-opt.h | 163 +++++ .../argon2lib/blake2/blamka-round-ref.h | 39 ++ ext/standard/argon2lib/core.c | 607 ++++++++++++++++++ ext/standard/argon2lib/core.h | 219 +++++++ ext/standard/argon2lib/encoding.c | 426 ++++++++++++ ext/standard/argon2lib/encoding.h | 40 ++ ext/standard/argon2lib/opt.c | 220 +++++++ ext/standard/argon2lib/opt.h | 52 ++ ext/standard/argon2lib/ref.c | 228 +++++++ ext/standard/argon2lib/ref.h | 51 ++ ext/standard/argon2lib/thread.c | 36 ++ ext/standard/argon2lib/thread.h | 46 ++ ext/standard/config.m4 | 11 +- ext/standard/password.c | 161 ++++- ext/standard/php_password.h | 7 +- .../tests/password/password_get_info.phpt | 17 + 21 files changed, 3652 insertions(+), 30 deletions(-) create mode 100644 ext/standard/argon2lib/argon2.c create mode 100644 ext/standard/argon2lib/argon2.h create mode 100644 ext/standard/argon2lib/blake2/blake2-impl.h create mode 100644 ext/standard/argon2lib/blake2/blake2.h create mode 100644 ext/standard/argon2lib/blake2/blake2b.c create mode 100644 ext/standard/argon2lib/blake2/blamka-round-opt.h create mode 100644 ext/standard/argon2lib/blake2/blamka-round-ref.h create mode 100644 ext/standard/argon2lib/core.c create mode 100644 ext/standard/argon2lib/core.h create mode 100644 ext/standard/argon2lib/encoding.c create mode 100644 ext/standard/argon2lib/encoding.h create mode 100644 ext/standard/argon2lib/opt.c create mode 100644 ext/standard/argon2lib/opt.h create mode 100644 ext/standard/argon2lib/ref.c create mode 100644 ext/standard/argon2lib/ref.h create mode 100644 ext/standard/argon2lib/thread.c create mode 100644 ext/standard/argon2lib/thread.h diff --git a/ext/standard/argon2lib/argon2.c b/ext/standard/argon2lib/argon2.c new file mode 100644 index 00000000000..4f4f6d4249c --- /dev/null +++ b/ext/standard/argon2lib/argon2.c @@ -0,0 +1,398 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include + +#include "argon2.h" +#include "encoding.h" +#include "core.h" + + +int argon2_ctx(argon2_context *context, argon2_type type) { + /* 1. Validate all inputs */ + int result = validate_inputs(context); + uint32_t memory_blocks, segment_length; + argon2_instance_t instance; + + if (ARGON2_OK != result) { + return result; + } + + if (Argon2_d != type && Argon2_i != type) { + return ARGON2_INCORRECT_TYPE; + } + + /* 2. Align memory size */ + /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */ + memory_blocks = context->m_cost; + + if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) { + memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes; + } + + segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS); + /* Ensure that all segments have equal length */ + memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS); + + instance.version = context->version; + instance.memory = NULL; + instance.passes = context->t_cost; + instance.memory_blocks = memory_blocks; + instance.segment_length = segment_length; + instance.lane_length = segment_length * ARGON2_SYNC_POINTS; + instance.lanes = context->lanes; + instance.threads = context->threads; + instance.type = type; + + /* 3. Initialization: Hashing inputs, allocating memory, filling first + * blocks + */ + result = initialize(&instance, context); + + if (ARGON2_OK != result) { + return result; + } + + /* 4. Filling memory */ + result = fill_memory_blocks(&instance); + + if (ARGON2_OK != result) { + return result; + } + /* 5. Finalization */ + finalize(context, &instance); + + return ARGON2_OK; +} + +int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, const size_t saltlen, + void *hash, const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type, + const uint32_t version){ + + argon2_context context; + int result; + uint8_t *out; + + if (hashlen > ARGON2_MAX_OUTLEN) { + return ARGON2_OUTPUT_TOO_LONG; + } + + if (hashlen < ARGON2_MIN_OUTLEN) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + out = malloc(hashlen); + if (!out) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + context.out = (uint8_t *)out; + context.outlen = (uint32_t)hashlen; + context.pwd = CONST_CAST(uint8_t *)pwd; + context.pwdlen = (uint32_t)pwdlen; + context.salt = CONST_CAST(uint8_t *)salt; + context.saltlen = (uint32_t)saltlen; + 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; + + result = argon2_ctx(&context, type); + + if (result != ARGON2_OK) { + secure_wipe_memory(out, hashlen); + free(out); + return result; + } + + /* if raw hash requested, write it */ + if (hash) { + memcpy(hash, out, hashlen); + } + + /* if encoding requested, write it */ + if (encoded && encodedlen) { + if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) { + secure_wipe_memory(out, hashlen); /* wipe buffers if error */ + secure_wipe_memory(encoded, encodedlen); + free(out); + return ARGON2_ENCODING_FAIL; + } + } + secure_wipe_memory(out, hashlen); + free(out); + + return ARGON2_OK; +} + +int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_i, + ARGON2_VERSION_NUMBER); +} + +int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_i, ARGON2_VERSION_NUMBER); +} + +int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_d, + ARGON2_VERSION_NUMBER); +} + +int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER); +} + +static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) { + size_t i; + uint8_t d = 0U; + + for (i = 0U; i < len; i++) { + d |= b1[i] ^ b2[i]; + } + return (int)((1 & ((d - 1) >> 8)) - 1); +} + +int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, + argon2_type type) { + + argon2_context ctx; + uint8_t *out; + int ret; + int decode_result; + uint32_t encoded_len; + size_t encoded_len_tmp; + + if(encoded == NULL) { + return ARGON2_DECODING_FAIL; + } + + encoded_len_tmp = strlen(encoded); + /* max values, to be updated in decode_string */ + if (UINT32_MAX < encoded_len_tmp) { + return ARGON2_DECODING_FAIL; + } + + encoded_len = (uint32_t)encoded_len_tmp; + ctx.adlen = encoded_len; + ctx.saltlen = encoded_len; + ctx.outlen = encoded_len; + ctx.allocate_cbk = NULL; + ctx.free_cbk = NULL; + ctx.secret = NULL; + ctx.secretlen = 0; + ctx.pwdlen = 0; + ctx.pwd = NULL; + ctx.ad = malloc(ctx.adlen); + ctx.salt = malloc(ctx.saltlen); + ctx.out = malloc(ctx.outlen); + if (!ctx.out || !ctx.salt || !ctx.ad) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + out = malloc(ctx.outlen); + if (!out) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + decode_result = decode_string(&ctx, encoded, type); + if (decode_result != ARGON2_OK) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + free(out); + return decode_result; + } + + ret = argon2_hash(ctx.t_cost, ctx.m_cost, ctx.threads, pwd, pwdlen, + ctx.salt, ctx.saltlen, out, ctx.outlen, NULL, 0, type, + ctx.version); + + free(ctx.ad); + free(ctx.salt); + + if (ret == ARGON2_OK && argon2_compare(out, ctx.out, ctx.outlen)) { + ret = ARGON2_VERIFY_MISMATCH; + } + free(out); + free(ctx.out); + + return ret; +} + +int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_i); +} + +int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_d); +} + +int argon2d_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_d); +} + +int argon2i_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_i); +} + +int argon2_verify_ctx(argon2_context *context, const char *hash, + argon2_type type) { + int result; + if (0 == context->outlen || NULL == hash) { + return ARGON2_OUT_PTR_MISMATCH; + } + + result = argon2_ctx(context, type); + + if (ARGON2_OK != result) { + return result; + } + + return 0 == memcmp(hash, context->out, context->outlen); +} + +int argon2d_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_d); +} + +int argon2i_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_i); +} + +const char *argon2_error_message(int error_code) { + switch (error_code) { + case ARGON2_OK: + return "OK"; + case ARGON2_OUTPUT_PTR_NULL: + return "Output pointer is NULL"; + case ARGON2_OUTPUT_TOO_SHORT: + return "Output is too short"; + case ARGON2_OUTPUT_TOO_LONG: + return "Output is too long"; + case ARGON2_PWD_TOO_SHORT: + return "Password is too short"; + case ARGON2_PWD_TOO_LONG: + return "Password is too long"; + case ARGON2_SALT_TOO_SHORT: + return "Salt is too short"; + case ARGON2_SALT_TOO_LONG: + return "Salt is too long"; + case ARGON2_AD_TOO_SHORT: + return "Associated data is too short"; + case ARGON2_AD_TOO_LONG: + return "Associated data is too long"; + case ARGON2_SECRET_TOO_SHORT: + return "Secret is too short"; + case ARGON2_SECRET_TOO_LONG: + return "Secret is too long"; + case ARGON2_TIME_TOO_SMALL: + return "Time cost is too small"; + case ARGON2_TIME_TOO_LARGE: + return "Time cost is too large"; + case ARGON2_MEMORY_TOO_LITTLE: + return "Memory cost is too small"; + case ARGON2_MEMORY_TOO_MUCH: + return "Memory cost is too large"; + case ARGON2_LANES_TOO_FEW: + return "Too few lanes"; + case ARGON2_LANES_TOO_MANY: + return "Too many lanes"; + case ARGON2_PWD_PTR_MISMATCH: + return "Password pointer is NULL, but password length is not 0"; + case ARGON2_SALT_PTR_MISMATCH: + return "Salt pointer is NULL, but salt length is not 0"; + case ARGON2_SECRET_PTR_MISMATCH: + return "Secret pointer is NULL, but secret length is not 0"; + case ARGON2_AD_PTR_MISMATCH: + return "Associated data pointer is NULL, but ad length is not 0"; + case ARGON2_MEMORY_ALLOCATION_ERROR: + return "Memory allocation error"; + case ARGON2_FREE_MEMORY_CBK_NULL: + return "The free memory callback is NULL"; + case ARGON2_ALLOCATE_MEMORY_CBK_NULL: + return "The allocate memory callback is NULL"; + case ARGON2_INCORRECT_PARAMETER: + return "Argon2_Context context is NULL"; + case ARGON2_INCORRECT_TYPE: + return "There is no such version of Argon2"; + case ARGON2_OUT_PTR_MISMATCH: + return "Output pointer mismatch"; + case ARGON2_THREADS_TOO_FEW: + return "Not enough threads"; + case ARGON2_THREADS_TOO_MANY: + return "Too many threads"; + case ARGON2_MISSING_ARGS: + return "Missing arguments"; + case ARGON2_ENCODING_FAIL: + return "Encoding failed"; + case ARGON2_DECODING_FAIL: + return "Decoding failed"; + case ARGON2_THREAD_FAIL: + return "Threading failure"; + case ARGON2_DECODING_LENGTH_FAIL: + return "Some of encoded parameters are too long or too short"; + case ARGON2_VERIFY_MISMATCH: + return "The password does not match the supplied hash"; + default: + return "Unknown error code"; + } +} + +size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism, + uint32_t saltlen, uint32_t hashlen) { + return strlen("$argon2x$v=$m=,t=,p=$$") + numlen(t_cost) + numlen(m_cost) + + numlen(parallelism) + b64len(saltlen) + b64len(hashlen) + + numlen(ARGON2_VERSION_NUMBER); +} diff --git a/ext/standard/argon2lib/argon2.h b/ext/standard/argon2lib/argon2.h new file mode 100644 index 00000000000..d4c7d5b499d --- /dev/null +++ b/ext/standard/argon2lib/argon2.h @@ -0,0 +1,372 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef ARGON2_H +#define ARGON2_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Symbols visibility control */ +#ifdef A2_VISCTL +#define ARGON2_PUBLIC __attribute__((visibility("default"))) +#else +#define ARGON2_PUBLIC +#endif + +/* + * Argon2 input parameter restrictions + */ + +/* Minimum and maximum number of lanes (degree of parallelism) */ +#define ARGON2_MIN_LANES UINT32_C(1) +#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF) + +/* Minimum and maximum number of threads */ +#define ARGON2_MIN_THREADS UINT32_C(1) +#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF) + +/* Number of synchronization points between lanes per pass */ +#define ARGON2_SYNC_POINTS UINT32_C(4) + +/* Minimum and maximum digest size in bytes */ +#define ARGON2_MIN_OUTLEN UINT32_C(4) +#define ARGON2_MAX_OUTLEN UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */ +#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */ + +#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b)) +/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */ +#define ARGON2_MAX_MEMORY_BITS \ + ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1)) +#define ARGON2_MAX_MEMORY \ + ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS) + +/* Minimum and maximum number of passes */ +#define ARGON2_MIN_TIME UINT32_C(1) +#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum password length in bytes */ +#define ARGON2_MIN_PWD_LENGTH UINT32_C(0) +#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum associated data length in bytes */ +#define ARGON2_MIN_AD_LENGTH UINT32_C(0) +#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum salt length in bytes */ +#define ARGON2_MIN_SALT_LENGTH UINT32_C(8) +#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum key length in bytes */ +#define ARGON2_MIN_SECRET UINT32_C(0) +#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) + +#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) +#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) +#define ARGON2_FLAG_CLEAR_MEMORY (UINT32_C(1) << 2) +#define ARGON2_DEFAULT_FLAGS (ARGON2_FLAG_CLEAR_MEMORY) + +/* Error codes */ +typedef enum Argon2_ErrorCodes { + ARGON2_OK = 0, + + ARGON2_OUTPUT_PTR_NULL = -1, + + ARGON2_OUTPUT_TOO_SHORT = -2, + ARGON2_OUTPUT_TOO_LONG = -3, + + ARGON2_PWD_TOO_SHORT = -4, + ARGON2_PWD_TOO_LONG = -5, + + ARGON2_SALT_TOO_SHORT = -6, + ARGON2_SALT_TOO_LONG = -7, + + ARGON2_AD_TOO_SHORT = -8, + ARGON2_AD_TOO_LONG = -9, + + ARGON2_SECRET_TOO_SHORT = -10, + ARGON2_SECRET_TOO_LONG = -11, + + ARGON2_TIME_TOO_SMALL = -12, + ARGON2_TIME_TOO_LARGE = -13, + + ARGON2_MEMORY_TOO_LITTLE = -14, + ARGON2_MEMORY_TOO_MUCH = -15, + + ARGON2_LANES_TOO_FEW = -16, + ARGON2_LANES_TOO_MANY = -17, + + ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */ + ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */ + ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */ + ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */ + + ARGON2_MEMORY_ALLOCATION_ERROR = -22, + + ARGON2_FREE_MEMORY_CBK_NULL = -23, + ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24, + + ARGON2_INCORRECT_PARAMETER = -25, + ARGON2_INCORRECT_TYPE = -26, + + ARGON2_OUT_PTR_MISMATCH = -27, + + ARGON2_THREADS_TOO_FEW = -28, + ARGON2_THREADS_TOO_MANY = -29, + + ARGON2_MISSING_ARGS = -30, + + ARGON2_ENCODING_FAIL = -31, + + ARGON2_DECODING_FAIL = -32, + + ARGON2_THREAD_FAIL = -33, + + ARGON2_DECODING_LENGTH_FAIL = -34, + + ARGON2_VERIFY_MISMATCH = -35 +} argon2_error_codes; + +/* Memory allocator types --- for external allocation */ +typedef int (*allocate_fptr)(uint8_t **memory, size_t bytes_to_allocate); +typedef void (*deallocate_fptr)(uint8_t *memory, size_t bytes_to_allocate); + +/* Argon2 external data structures */ + +/* + ***** + * Context: structure to hold Argon2 inputs: + * output array and its length, + * password and its length, + * salt and its length, + * secret and its length, + * associated data and its length, + * number of passes, amount of used memory (in KBytes, can be rounded up a bit) + * number of parallel threads that will be run. + * All the parameters above affect the output hash value. + * Additionally, two function pointers can be provided to allocate and + * deallocate the memory (if NULL, memory will be allocated internally). + * Also, three flags indicate whether to erase password, secret as soon as they + * are pre-hashed (and thus not needed anymore), and the entire memory + ***** + * Simplest situation: you have output array out[8], password is stored in + * pwd[32], salt is stored in salt[16], you do not have keys nor associated + * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with + * 4 parallel lanes. + * You want to erase the password, but you're OK with last pass not being + * erased. You want to use the default memory allocator. + * Then you initialize: + Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false) + */ +typedef struct Argon2_Context { + uint8_t *out; /* output array */ + uint32_t outlen; /* digest length */ + + uint8_t *pwd; /* password array */ + uint32_t pwdlen; /* password length */ + + uint8_t *salt; /* salt array */ + uint32_t saltlen; /* salt length */ + + uint8_t *secret; /* key array */ + uint32_t secretlen; /* key length */ + + uint8_t *ad; /* associated data array */ + uint32_t adlen; /* associated data length */ + + uint32_t t_cost; /* number of passes */ + uint32_t m_cost; /* amount of memory requested (KB) */ + uint32_t lanes; /* number of lanes */ + uint32_t threads; /* maximum number of threads */ + + uint32_t version; /* version number */ + + allocate_fptr allocate_cbk; /* pointer to memory allocator */ + deallocate_fptr free_cbk; /* pointer to memory deallocator */ + + uint32_t flags; /* array of bool options */ +} argon2_context; + +/* Argon2 primitive type */ +typedef enum Argon2_type { Argon2_d = 0, Argon2_i = 1 } argon2_type; + +/* Version of the algorithm */ +typedef enum Argon2_version { + ARGON2_VERSION_10 = 0x10, + ARGON2_VERSION_13 = 0x13, + ARGON2_VERSION_NUMBER = ARGON2_VERSION_13 +} argon2_version; + +/* + * Function that performs memory-hard hashing with certain degree of parallelism + * @param context Pointer to the Argon2 internal structure + * @return Error code if smth is wrong, ARGON2_OK otherwise + */ +ARGON2_PUBLIC int argon2_ctx(argon2_context *context, argon2_type type); + +/** + * Hashes a password with Argon2i, producing an encoded hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hashlen Desired length of the hash in bytes + * @param encoded Buffer where to write the encoded hash + * @param encodedlen Size of the buffer (thus max size of the encoded hash) + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +/** + * Hashes a password with Argon2i, producing a raw hash by allocating memory at + * @hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hash Buffer where to write the raw hash - updated by the function + * @param hashlen Desired length of the hash in bytes + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +ARGON2_PUBLIC int argon2d_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +ARGON2_PUBLIC int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type, + const uint32_t version); + +/** + * Verifies a password against an encoded string + * Encoded string is restricted as in validate_inputs() + * @param encoded String encoding parameters, salt, hash + * @param pwd Pointer to password + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd, + const size_t pwdlen, argon2_type type); + +/** + * Argon2d: Version of Argon2 that picks memory blocks depending + * on the password and salt. Only for side-channel-free + * environment!! + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2d_ctx(argon2_context *context); + +/** + * Argon2i: Version of Argon2 that picks memory blocks + * independent on the password and salt. Good for side-channels, + * but worse w.r.t. tradeoff attacks if only one pass is used. + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2i_ctx(argon2_context *context); + +/** + * Verify if a given password is correct for Argon2d hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2d_verify_ctx(argon2_context *context, const char *hash); + +/** + * Verify if a given password is correct for Argon2i hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash, + argon2_type type); + +/** + * Get the associated error message for given error code + * @return The error message associated with the given error code + */ +ARGON2_PUBLIC const char *argon2_error_message(int error_code); + +/** + * Returns the encoded hash length for the given input parameters + * @param t_cost Number of iterations + * @param m_cost Memory usage in kibibytes + * @param parallelism Number of threads; used to compute lanes + * @param saltlen Salt size in bytes + * @param hashlen Hash size in bytes + * @return The encoded hash length in bytes + */ +ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, + uint32_t parallelism, uint32_t saltlen, + uint32_t hashlen); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/ext/standard/argon2lib/blake2/blake2-impl.h b/ext/standard/argon2lib/blake2/blake2-impl.h new file mode 100644 index 00000000000..115a192db6f --- /dev/null +++ b/ext/standard/argon2lib/blake2/blake2-impl.h @@ -0,0 +1,143 @@ +#ifndef PORTABLE_BLAKE2_IMPL_H +#define PORTABLE_BLAKE2_IMPL_H + +#include +#include + +#if defined(_MSC_VER) +#define BLAKE2_INLINE __inline +#elif defined(__GNUC__) || defined(__clang__) +#define BLAKE2_INLINE __inline__ +#else +#define BLAKE2_INLINE +#endif + +/* Argon2 Team - Begin Code */ +/* + Not an exhaustive list, but should cover the majority of modern platforms + Additionally, the code will always be correct---this is only a performance + tweak. +*/ +#if (defined(__BYTE_ORDER__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ + defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \ + defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_ARM) +#define NATIVE_LITTLE_ENDIAN +#endif +/* Argon2 Team - End Code */ + +static BLAKE2_INLINE uint32_t load32(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = (const uint8_t *)src; + uint32_t w = *p++; + w |= (uint32_t)(*p++) << 8; + w |= (uint32_t)(*p++) << 16; + w |= (uint32_t)(*p++) << 24; + return w; +#endif +} + +static BLAKE2_INLINE uint64_t load64(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + w |= (uint64_t)(*p++) << 48; + w |= (uint64_t)(*p++) << 56; + return w; +#endif +} + +static BLAKE2_INLINE void store32(void *dst, uint32_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static BLAKE2_INLINE void store64(void *dst, uint64_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static BLAKE2_INLINE uint64_t load48(const void *src) { + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + return w; +} + +static BLAKE2_INLINE void store48(void *dst, uint64_t w) { + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +} + +static BLAKE2_INLINE uint32_t rotr32(const uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); +} + +/* prevents compiler optimizing out memset() */ +static BLAKE2_INLINE void burn(void *v, size_t n) { + static void *(*const volatile memset_v)(void *, int, size_t) = &memset; + memset_v(v, 0, n); +} + +#endif diff --git a/ext/standard/argon2lib/blake2/blake2.h b/ext/standard/argon2lib/blake2/blake2.h new file mode 100644 index 00000000000..d28d9a7900b --- /dev/null +++ b/ext/standard/argon2lib/blake2/blake2.h @@ -0,0 +1,74 @@ +#ifndef PORTABLE_BLAKE2_H +#define PORTABLE_BLAKE2_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +#pragma pack(push, 1) +typedef struct __blake2b_param { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint64_t node_offset; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +} blake2b_param; +#pragma pack(pop) + +typedef struct __blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + unsigned buflen; + unsigned outlen; + uint8_t last_node; +} blake2b_state; + +/* Ensure param structs have not been wrongly padded */ +/* Poor man's static_assert */ +enum { + blake2_size_check_0 = 1 / !!(CHAR_BIT == 8), + blake2_size_check_2 = + 1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT) +}; + +/* Streaming API */ +int blake2b_init(blake2b_state *S, size_t outlen); +int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, + size_t keylen); +int blake2b_init_param(blake2b_state *S, const blake2b_param *P); +int blake2b_update(blake2b_state *S, const void *in, size_t inlen); +int blake2b_final(blake2b_state *S, void *out, size_t outlen); + +/* Simple API */ +int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen); + +/* Argon2 Team - Begin Code */ +int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); +/* Argon2 Team - End Code */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/ext/standard/argon2lib/blake2/blake2b.c b/ext/standard/argon2lib/blake2/blake2b.c new file mode 100644 index 00000000000..28dec868d97 --- /dev/null +++ b/ext/standard/argon2lib/blake2/blake2b.c @@ -0,0 +1,372 @@ +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint64_t blake2b_IV[8] = { + UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179)}; + +static const unsigned int blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, +}; + +static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) { + S->f[1] = (uint64_t)-1; +} + +static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) { + if (S->last_node) { + blake2b_set_lastnode(S); + } + S->f[0] = (uint64_t)-1; +} + +static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S, + uint64_t inc) { + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) { + burn(S, sizeof(*S)); /* wipe */ + blake2b_set_lastblock(S); /* invalidate for further use */ +} + +static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) { + memset(S, 0, sizeof(*S)); + memcpy(S->h, blake2b_IV, sizeof(S->h)); +} + +int blake2b_init_param(blake2b_state *S, const blake2b_param *P) { + const unsigned char *p = (const unsigned char *)P; + unsigned int i; + + if (NULL == P || NULL == S) { + return -1; + } + + blake2b_init0(S); + /* IV XOR Parameter Block */ + for (i = 0; i < 8; ++i) { + S->h[i] ^= load64(&p[i * sizeof(S->h[i])]); + } + S->outlen = P->digest_length; + return 0; +} + +/* Sequential blake2b initialization */ +int blake2b_init(blake2b_state *S, size_t outlen) { + blake2b_param P; + + if (S == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + /* Setup Parameter Block for unkeyed BLAKE2 */ + P.digest_length = (uint8_t)outlen; + P.key_length = 0; + P.fanout = 1; + P.depth = 1; + P.leaf_length = 0; + P.node_offset = 0; + P.node_depth = 0; + P.inner_length = 0; + memset(P.reserved, 0, sizeof(P.reserved)); + memset(P.salt, 0, sizeof(P.salt)); + memset(P.personal, 0, sizeof(P.personal)); + + return blake2b_init_param(S, &P); +} + +int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, + size_t keylen) { + blake2b_param P; + + if (S == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + /* Setup Parameter Block for keyed BLAKE2 */ + P.digest_length = (uint8_t)outlen; + P.key_length = (uint8_t)keylen; + P.fanout = 1; + P.depth = 1; + P.leaf_length = 0; + P.node_offset = 0; + P.node_depth = 0; + P.inner_length = 0; + memset(P.reserved, 0, sizeof(P.reserved)); + memset(P.salt, 0, sizeof(P.salt)); + memset(P.personal, 0, sizeof(P.personal)); + + if (blake2b_init_param(S, &P) < 0) { + blake2b_invalidate_state(S); + return -1; + } + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_update(S, block, BLAKE2B_BLOCKBYTES); + burn(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ + } + return 0; +} + +static void blake2b_compress(blake2b_state *S, const uint8_t *block) { + uint64_t m[16]; + uint64_t v[16]; + unsigned int i, r; + + for (i = 0; i < 16; ++i) { + m[i] = load64(block + i * sizeof(m[i])); + } + + for (i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while ((void)0, 0) + + for (r = 0; r < 12; ++r) { + ROUND(r); + } + + for (i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } + +#undef G +#undef ROUND +} + +int blake2b_update(blake2b_state *S, const void *in, size_t inlen) { + const uint8_t *pin = (const uint8_t *)in; + + if (inlen == 0) { + return 0; + } + + /* Sanity check */ + if (S == NULL || in == NULL) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) { + /* Complete current block */ + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + memcpy(&S->buf[left], pin, fill); + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf); + S->buflen = 0; + inlen -= fill; + pin += fill; + /* Avoid buffer copies when possible */ + while (inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, pin); + inlen -= BLAKE2B_BLOCKBYTES; + pin += BLAKE2B_BLOCKBYTES; + } + } + memcpy(&S->buf[S->buflen], pin, inlen); + S->buflen += (unsigned int)inlen; + return 0; +} + +int blake2b_final(blake2b_state *S, void *out, size_t outlen) { + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + unsigned int i; + + /* Sanity checks */ + if (S == NULL || out == NULL || outlen < S->outlen) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + blake2b_increment_counter(S, S->buflen); + blake2b_set_lastblock(S); + memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf); + + for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ + store64(buffer + sizeof(S->h[i]) * i, S->h[i]); + } + + memcpy(out, buffer, S->outlen); + burn(buffer, sizeof(buffer)); + burn(S->buf, sizeof(S->buf)); + burn(S->h, sizeof(S->h)); + return 0; +} + +int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen) { + blake2b_state S; + int ret = -1; + + /* Verify parameters */ + if (NULL == in && inlen > 0) { + goto fail; + } + + if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) { + goto fail; + } + + if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) { + goto fail; + } + + if (keylen > 0) { + if (blake2b_init_key(&S, outlen, key, keylen) < 0) { + goto fail; + } + } else { + if (blake2b_init(&S, outlen) < 0) { + goto fail; + } + } + + if (blake2b_update(&S, in, inlen) < 0) { + goto fail; + } + ret = blake2b_final(&S, out, outlen); + +fail: + burn(&S, sizeof(S)); + return ret; +} + +/* Argon2 Team - Begin Code */ +int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) { + uint8_t *out = (uint8_t *)pout; + blake2b_state blake_state; + uint8_t outlen_bytes[sizeof(uint32_t)] = {0}; + int ret = -1; + + if (outlen > UINT32_MAX) { + goto fail; + } + + /* Ensure little-endian byte order! */ + store32(outlen_bytes, (uint32_t)outlen); + +#define TRY(statement) \ + do { \ + ret = statement; \ + if (ret < 0) { \ + goto fail; \ + } \ + } while ((void)0, 0) + + if (outlen <= BLAKE2B_OUTBYTES) { + TRY(blake2b_init(&blake_state, outlen)); + TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(blake2b_update(&blake_state, in, inlen)); + TRY(blake2b_final(&blake_state, out, outlen)); + } else { + uint32_t toproduce; + uint8_t out_buffer[BLAKE2B_OUTBYTES]; + uint8_t in_buffer[BLAKE2B_OUTBYTES]; + TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES)); + TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(blake2b_update(&blake_state, in, inlen)); + TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2; + + while (toproduce > BLAKE2B_OUTBYTES) { + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, + BLAKE2B_OUTBYTES, NULL, 0)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce -= BLAKE2B_OUTBYTES / 2; + } + + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, + 0)); + memcpy(out, out_buffer, toproduce); + } +fail: + burn(&blake_state, sizeof(blake_state)); + return ret; +#undef TRY +} +/* Argon2 Team - End Code */ diff --git a/ext/standard/argon2lib/blake2/blamka-round-opt.h b/ext/standard/argon2lib/blake2/blamka-round-opt.h new file mode 100644 index 00000000000..44845a54516 --- /dev/null +++ b/ext/standard/argon2lib/blake2/blamka-round-opt.h @@ -0,0 +1,163 @@ +#ifndef BLAKE_ROUND_MKA_OPT_H +#define BLAKE_ROUND_MKA_OPT_H + +#include "blake2-impl.h" + +#include +#if defined(__SSSE3__) +#include /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */ +#endif + +#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__)) +#include +#endif + +#if !defined(__XOP__) +#if defined(__SSSE3__) +#define r16 \ + (_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9)) +#define r24 \ + (_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10)) +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) \ + ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \ + : (-(c) == 24) \ + ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) \ + ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) \ + ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ + _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ + _mm_slli_epi64((x), 64 - (-(c)))) +#else /* defined(__SSE2__) */ +#define _mm_roti_epi64(r, c) \ + _mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c)))) +#endif +#else +#endif + +static BLAKE2_INLINE __m128i fBlaMka(__m128i x, __m128i y) { + const __m128i z = _mm_mul_epu32(x, y); + return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z)); +} + +#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = fBlaMka(A0, B0); \ + A1 = fBlaMka(A1, B1); \ + \ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ + \ + D0 = _mm_roti_epi64(D0, -32); \ + D1 = _mm_roti_epi64(D1, -32); \ + \ + C0 = fBlaMka(C0, D0); \ + C1 = fBlaMka(C1, D1); \ + \ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ + \ + B0 = _mm_roti_epi64(B0, -24); \ + B1 = _mm_roti_epi64(B1, -24); \ + } while ((void)0, 0) + +#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = fBlaMka(A0, B0); \ + A1 = fBlaMka(A1, B1); \ + \ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ + \ + D0 = _mm_roti_epi64(D0, -16); \ + D1 = _mm_roti_epi64(D1, -16); \ + \ + C0 = fBlaMka(C0, D0); \ + C1 = fBlaMka(C1, D1); \ + \ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ + \ + B0 = _mm_roti_epi64(B0, -63); \ + B1 = _mm_roti_epi64(B1, -63); \ + } while ((void)0, 0) + +#if defined(__SSSE3__) +#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = _mm_alignr_epi8(B1, B0, 8); \ + __m128i t1 = _mm_alignr_epi8(B0, B1, 8); \ + B0 = t0; \ + B1 = t1; \ + \ + t0 = C0; \ + C0 = C1; \ + C1 = t0; \ + \ + t0 = _mm_alignr_epi8(D1, D0, 8); \ + t1 = _mm_alignr_epi8(D0, D1, 8); \ + D0 = t1; \ + D1 = t0; \ + } while ((void)0, 0) + +#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = _mm_alignr_epi8(B0, B1, 8); \ + __m128i t1 = _mm_alignr_epi8(B1, B0, 8); \ + B0 = t0; \ + B1 = t1; \ + \ + t0 = C0; \ + C0 = C1; \ + C1 = t0; \ + \ + t0 = _mm_alignr_epi8(D0, D1, 8); \ + t1 = _mm_alignr_epi8(D1, D0, 8); \ + D0 = t1; \ + D1 = t0; \ + } while ((void)0, 0) +#else /* SSE2 */ +#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = D0; \ + __m128i t1 = B0; \ + D0 = C0; \ + C0 = C1; \ + C1 = D0; \ + D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0)); \ + D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1)); \ + B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1)); \ + B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1)); \ + } while ((void)0, 0) + +#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0, t1; \ + t0 = C0; \ + C0 = C1; \ + C1 = t0; \ + t0 = B0; \ + t1 = D0; \ + B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0)); \ + B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1)); \ + D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1)); \ + D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1)); \ + } while ((void)0, 0) +#endif + +#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void)0, 0) + +#endif diff --git a/ext/standard/argon2lib/blake2/blamka-round-ref.h b/ext/standard/argon2lib/blake2/blamka-round-ref.h new file mode 100644 index 00000000000..f497e10c2fe --- /dev/null +++ b/ext/standard/argon2lib/blake2/blamka-round-ref.h @@ -0,0 +1,39 @@ +#ifndef BLAKE_ROUND_MKA_H +#define BLAKE_ROUND_MKA_H + +#include "blake2.h" +#include "blake2-impl.h" + +/*designed by the Lyra PHC team */ +static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) { + const uint64_t m = UINT64_C(0xFFFFFFFF); + const uint64_t xy = (x & m) * (y & m); + return x + y + 2 * xy; +} + +#define G(a, b, c, d) \ + do { \ + a = fBlaMka(a, b); \ + d = rotr64(d ^ a, 32); \ + c = fBlaMka(c, d); \ + b = rotr64(b ^ c, 24); \ + a = fBlaMka(a, b); \ + d = rotr64(d ^ a, 16); \ + c = fBlaMka(c, d); \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \ + v12, v13, v14, v15) \ + do { \ + G(v0, v4, v8, v12); \ + G(v1, v5, v9, v13); \ + G(v2, v6, v10, v14); \ + G(v3, v7, v11, v15); \ + G(v0, v5, v10, v15); \ + G(v1, v6, v11, v12); \ + G(v2, v7, v8, v13); \ + G(v3, v4, v9, v14); \ + } while ((void)0, 0) + +#endif diff --git a/ext/standard/argon2lib/core.c b/ext/standard/argon2lib/core.c new file mode 100644 index 00000000000..278d36c8cb7 --- /dev/null +++ b/ext/standard/argon2lib/core.c @@ -0,0 +1,607 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +/*For memory wiping*/ +#ifdef _MSC_VER +#include +#include /* For SecureZeroMemory */ +#endif +#if defined __STDC_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 +#endif +#define VC_GE_2005(version) (version >= 1400) + +#include +#include +#include +#include + +#include "core.h" +#include "thread.h" +#include "blake2/blake2.h" +#include "blake2/blake2-impl.h" + +#ifdef GENKAT +#include "genkat.h" +#endif + +#if defined(__clang__) +#if __has_attribute(optnone) +#define NOT_OPTIMIZED __attribute__((optnone)) +#endif +#elif defined(__GNUC__) +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION >= 40400 +#define NOT_OPTIMIZED __attribute__((optimize("O0"))) +#endif +#endif +#ifndef NOT_OPTIMIZED +#define NOT_OPTIMIZED +#endif + +/***************Instance and Position constructors**********/ +void init_block_value(block *b, uint8_t in) { memset(b->v, in, sizeof(b->v)); } + +void copy_block(block *dst, const block *src) { + memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK); +} + +void xor_block(block *dst, const block *src) { + int i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] ^= src->v[i]; + } +} + +static void load_block(block *dst, const void *input) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] = load64((const uint8_t *)input + i * sizeof(dst->v[i])); + } +} + +static void store_block(void *output, const block *src) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); + } +} + +/***************Memory allocators*****************/ +int allocate_memory(block **memory, uint32_t m_cost) { + if (memory != NULL) { + size_t memory_size = sizeof(block) * m_cost; + if (m_cost != 0 && + memory_size / m_cost != + sizeof(block)) { /*1. Check for multiplication overflow*/ + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + *memory = (block *)malloc(memory_size); /*2. Try to allocate*/ + + if (!*memory) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + return ARGON2_OK; + } else { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } +} + +void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) { +#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER) + SecureZeroMemory(v, n); +#elif defined memset_s + memset_s(v, n, 0, n); +#elif defined(__OpenBSD__) + explicit_bzero(v, n); +#else + static void *(*const volatile memset_sec)(void *, int, size_t) = &memset; + memset_sec(v, 0, n); +#endif +} + +/*********Memory functions*/ + +void clear_memory(argon2_instance_t *instance, int clear) { + if (instance->memory != NULL && clear) { + secure_wipe_memory(instance->memory, + sizeof(block) * instance->memory_blocks); + } +} + +void free_memory(block *memory) { free(memory); } + +void finalize(const argon2_context *context, argon2_instance_t *instance) { + if (context != NULL && instance != NULL) { + block blockhash; + uint32_t l; + + copy_block(&blockhash, instance->memory + instance->lane_length - 1); + + /* XOR the last blocks */ + for (l = 1; l < instance->lanes; ++l) { + uint32_t last_block_in_lane = + l * instance->lane_length + (instance->lane_length - 1); + xor_block(&blockhash, instance->memory + last_block_in_lane); + } + + /* Hash the result */ + { + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + store_block(blockhash_bytes, &blockhash); + blake2b_long(context->out, context->outlen, blockhash_bytes, + ARGON2_BLOCK_SIZE); + secure_wipe_memory(blockhash.v, + ARGON2_BLOCK_SIZE); /* clear blockhash */ + secure_wipe_memory(blockhash_bytes, + ARGON2_BLOCK_SIZE); /* clear blockhash_bytes */ + } + +#ifdef GENKAT + print_tag(context->out, context->outlen); +#endif + + /* Clear memory */ + clear_memory(instance, context->flags & ARGON2_FLAG_CLEAR_PASSWORD); + + /* Deallocate the memory */ + if (NULL != context->free_cbk) { + context->free_cbk((uint8_t *)instance->memory, + instance->memory_blocks * sizeof(block)); + } else { + free_memory(instance->memory); + } + } +} + +uint32_t index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane) { + /* + * Pass 0: + * This lane : all already finished segments plus already constructed + * blocks in this segment + * Other lanes : all already finished segments + * Pass 1+: + * This lane : (SYNC_POINTS - 1) last segments plus already constructed + * blocks in this segment + * Other lanes : (SYNC_POINTS - 1) last segments + */ + uint32_t reference_area_size; + uint64_t relative_position; + uint32_t start_position, absolute_position; + + if (0 == position->pass) { + /* First pass */ + if (0 == position->slice) { + /* First slice */ + reference_area_size = + position->index - 1; /* all but the previous */ + } else { + if (same_lane) { + /* The same lane => add current segment */ + reference_area_size = + position->slice * instance->segment_length + + position->index - 1; + } else { + reference_area_size = + position->slice * instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + } else { + /* Second pass */ + if (same_lane) { + reference_area_size = instance->lane_length - + instance->segment_length + position->index - + 1; + } else { + reference_area_size = instance->lane_length - + instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + + /* 1.2.4. Mapping pseudo_rand to 0.. and produce + * relative position */ + relative_position = pseudo_rand; + relative_position = relative_position * relative_position >> 32; + relative_position = reference_area_size - 1 - + (reference_area_size * relative_position >> 32); + + /* 1.2.5 Computing starting position */ + start_position = 0; + + if (0 != position->pass) { + start_position = (position->slice == ARGON2_SYNC_POINTS - 1) + ? 0 + : (position->slice + 1) * instance->segment_length; + } + + /* 1.2.6. Computing absolute position */ + absolute_position = (start_position + relative_position) % + instance->lane_length; /* absolute position */ + return absolute_position; +} + +#ifdef _WIN32 +static unsigned __stdcall fill_segment_thr(void *thread_data) +#else +static void *fill_segment_thr(void *thread_data) +#endif +{ + argon2_thread_data *my_data = (argon2_thread_data *)thread_data; + fill_segment(my_data->instance_ptr, my_data->pos); + argon2_thread_exit(); + return 0; +} + +int fill_memory_blocks(argon2_instance_t *instance) { + uint32_t r, s; + argon2_thread_handle_t *thread = NULL; + argon2_thread_data *thr_data = NULL; + + if (instance == NULL || instance->lanes == 0) { + return ARGON2_THREAD_FAIL; + } + + /* 1. Allocating space for threads */ + thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t)); + if (thread == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + thr_data = calloc(instance->lanes, sizeof(argon2_thread_data)); + if (thr_data == NULL) { + free(thread); + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + for (r = 0; r < instance->passes; ++r) { + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + int rc; + uint32_t l; + + /* 2. Calling threads */ + for (l = 0; l < instance->lanes; ++l) { + argon2_position_t position; + + /* 2.1 Join a thread if limit is exceeded */ + if (l >= instance->threads) { + rc = argon2_thread_join(thread[l - instance->threads]); + if (rc) { + free(thr_data); + free(thread); + return ARGON2_THREAD_FAIL; + } + } + + /* 2.2 Create thread */ + position.pass = r; + position.lane = l; + position.slice = (uint8_t)s; + position.index = 0; + thr_data[l].instance_ptr = + instance; /* preparing the thread input */ + memcpy(&(thr_data[l].pos), &position, + sizeof(argon2_position_t)); + rc = argon2_thread_create(&thread[l], &fill_segment_thr, + (void *)&thr_data[l]); + if (rc) { + free(thr_data); + free(thread); + return ARGON2_THREAD_FAIL; + } + + /* fill_segment(instance, position); */ + /*Non-thread equivalent of the lines above */ + } + + /* 3. Joining remaining threads */ + for (l = instance->lanes - instance->threads; l < instance->lanes; + ++l) { + rc = argon2_thread_join(thread[l]); + if (rc) { + return ARGON2_THREAD_FAIL; + } + } + } + +#ifdef GENKAT + internal_kat(instance, r); /* Print all memory blocks */ +#endif + } + + if (thread != NULL) { + free(thread); + } + if (thr_data != NULL) { + free(thr_data); + } + return ARGON2_OK; +} + +int validate_inputs(const argon2_context *context) { + if (NULL == context) { + return ARGON2_INCORRECT_PARAMETER; + } + + if (NULL == context->out) { + return ARGON2_OUTPUT_PTR_NULL; + } + + /* Validate output length */ + if (ARGON2_MIN_OUTLEN > context->outlen) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + if (ARGON2_MAX_OUTLEN < context->outlen) { + return ARGON2_OUTPUT_TOO_LONG; + } + + /* Validate password length */ + if (NULL == context->pwd) { + if (0 != context->pwdlen) { + return ARGON2_PWD_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) { + return ARGON2_PWD_TOO_SHORT; + } + + if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) { + return ARGON2_PWD_TOO_LONG; + } + } + + /* Validate salt length */ + if (NULL == context->salt) { + if (0 != context->saltlen) { + return ARGON2_SALT_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_SALT_LENGTH > context->saltlen) { + return ARGON2_SALT_TOO_SHORT; + } + + if (ARGON2_MAX_SALT_LENGTH < context->saltlen) { + return ARGON2_SALT_TOO_LONG; + } + } + + /* Validate secret length */ + if (NULL == context->secret) { + if (0 != context->secretlen) { + return ARGON2_SECRET_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_SECRET > context->secretlen) { + return ARGON2_SECRET_TOO_SHORT; + } + + if (ARGON2_MAX_SECRET < context->secretlen) { + return ARGON2_SECRET_TOO_LONG; + } + } + + /* Validate associated data */ + if (NULL == context->ad) { + if (0 != context->adlen) { + return ARGON2_AD_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_AD_LENGTH > context->adlen) { + return ARGON2_AD_TOO_SHORT; + } + + if (ARGON2_MAX_AD_LENGTH < context->adlen) { + return ARGON2_AD_TOO_LONG; + } + } + + /* Validate memory cost */ + if (ARGON2_MIN_MEMORY > context->m_cost) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + if (ARGON2_MAX_MEMORY < context->m_cost) { + return ARGON2_MEMORY_TOO_MUCH; + } + + if (context->m_cost < 8 * context->lanes) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + /* Validate time cost */ + if (ARGON2_MIN_TIME > context->t_cost) { + return ARGON2_TIME_TOO_SMALL; + } + + if (ARGON2_MAX_TIME < context->t_cost) { + return ARGON2_TIME_TOO_LARGE; + } + + /* Validate lanes */ + if (ARGON2_MIN_LANES > context->lanes) { + return ARGON2_LANES_TOO_FEW; + } + + if (ARGON2_MAX_LANES < context->lanes) { + return ARGON2_LANES_TOO_MANY; + } + + /* Validate threads */ + if (ARGON2_MIN_THREADS > context->threads) { + return ARGON2_THREADS_TOO_FEW; + } + + if (ARGON2_MAX_THREADS < context->threads) { + return ARGON2_THREADS_TOO_MANY; + } + + if (NULL != context->allocate_cbk && NULL == context->free_cbk) { + return ARGON2_FREE_MEMORY_CBK_NULL; + } + + if (NULL == context->allocate_cbk && NULL != context->free_cbk) { + return ARGON2_ALLOCATE_MEMORY_CBK_NULL; + } + + return ARGON2_OK; +} + +void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) { + uint32_t l; + /* Make the first and second block in each lane as G(H0||i||0) or + G(H0||i||1) */ + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + for (l = 0; l < instance->lanes; ++l) { + + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0); + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->memory[l * instance->lane_length + 0], + blockhash_bytes); + + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->memory[l * instance->lane_length + 1], + blockhash_bytes); + } + secure_wipe_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); +} + +void initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type) { + blake2b_state BlakeHash; + uint8_t value[sizeof(uint32_t)]; + + if (NULL == context || NULL == blockhash) { + return; + } + + blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH); + + store32(&value, context->lanes); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->outlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->m_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->t_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->version); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, (uint32_t)type); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->pwdlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->pwd != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->pwd, + context->pwdlen); + + if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { + secure_wipe_memory(context->pwd, context->pwdlen); + context->pwdlen = 0; + } + } + + store32(&value, context->saltlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->salt != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->salt, + context->saltlen); + } + + store32(&value, context->secretlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->secret != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->secret, + context->secretlen); + + if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { + secure_wipe_memory(context->secret, context->secretlen); + context->secretlen = 0; + } + } + + store32(&value, context->adlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->ad != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->ad, + context->adlen); + } + + blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH); +} + +int initialize(argon2_instance_t *instance, argon2_context *context) { + uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; + int result = ARGON2_OK; + + if (instance == NULL || context == NULL) + return ARGON2_INCORRECT_PARAMETER; + + /* 1. Memory allocation */ + + if (NULL != context->allocate_cbk) { + uint8_t *p; + result = context->allocate_cbk(&p, instance->memory_blocks * + ARGON2_BLOCK_SIZE); + if (ARGON2_OK != result) { + return result; + } + memcpy(&(instance->memory), p, sizeof(instance->memory)); + } else { + result = allocate_memory(&(instance->memory), instance->memory_blocks); + if (ARGON2_OK != result) { + return result; + } + } + + /* 2. Initial hashing */ + /* H_0 + 8 extra bytes to produce the first blocks */ + /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */ + /* Hashing all inputs */ + initial_hash(blockhash, context, instance->type); + /* Zeroing 8 extra bytes */ + secure_wipe_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, + ARGON2_PREHASH_SEED_LENGTH - + ARGON2_PREHASH_DIGEST_LENGTH); + +#ifdef GENKAT + initial_kat(blockhash, context, instance->type); +#endif + + /* 3. Creating first blocks, we always have at least two blocks in a slice + */ + fill_first_blocks(blockhash, instance); + /* Clearing the hash */ + secure_wipe_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH); + + return ARGON2_OK; +} diff --git a/ext/standard/argon2lib/core.h b/ext/standard/argon2lib/core.h new file mode 100644 index 00000000000..e1e70faf857 --- /dev/null +++ b/ext/standard/argon2lib/core.h @@ -0,0 +1,219 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#ifndef ARGON2_CORE_H +#define ARGON2_CORE_H + +#include "argon2.h" + +#if defined(_MSC_VER) +#define ALIGN(n) __declspec(align(16)) +#elif defined(__GNUC__) || defined(__clang) +#define ALIGN(x) __attribute__((__aligned__(x))) +#else +#define ALIGN(x) +#endif + +#define CONST_CAST(x) (x)(uintptr_t) + +/*************************Argon2 internal + * constants**************************************************/ + +enum argon2_core_constants { + /* Memory block size in bytes */ + ARGON2_BLOCK_SIZE = 1024, + ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8, + ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16, + + /* Number of pseudo-random values generated by one call to Blake in Argon2i + to + generate reference block positions */ + ARGON2_ADDRESSES_IN_BLOCK = 128, + + /* Pre-hashing digest length and its extension*/ + ARGON2_PREHASH_DIGEST_LENGTH = 64, + ARGON2_PREHASH_SEED_LENGTH = 72 +}; + +/*************************Argon2 internal data + * types**************************************************/ + +/* + * Structure for the (1KB) memory block implemented as 128 64-bit words. + * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no + * bounds checking). + */ +typedef struct block_ { uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block; + +/*****************Functions that work with the block******************/ + +/* Initialize each byte of the block with @in */ +void init_block_value(block *b, uint8_t in); + +/* Copy block @src to block @dst */ +void copy_block(block *dst, const block *src); + +/* XOR @src onto @dst bytewise */ +void xor_block(block *dst, const block *src); + +/* + * Argon2 instance: memory pointer, number of passes, amount of memory, type, + * and derived values. + * Used to evaluate the number and location of blocks to construct in each + * thread + */ +typedef struct Argon2_instance_t { + block *memory; /* Memory pointer */ + uint32_t version; + uint32_t passes; /* Number of passes */ + uint32_t memory_blocks; /* Number of blocks in memory */ + uint32_t segment_length; + uint32_t lane_length; + uint32_t lanes; + uint32_t threads; + argon2_type type; + int print_internals; /* whether to print the memory blocks */ +} argon2_instance_t; + +/* + * Argon2 position: where we construct the block right now. Used to distribute + * work between threads. + */ +typedef struct Argon2_position_t { + uint32_t pass; + uint32_t lane; + uint8_t slice; + uint32_t index; +} argon2_position_t; + +/*Struct that holds the inputs for thread handling FillSegment*/ +typedef struct Argon2_thread_data { + argon2_instance_t *instance_ptr; + argon2_position_t pos; +} argon2_thread_data; + +/*************************Argon2 core + * functions**************************************************/ + +/* Allocates memory to the given pointer + * @param memory pointer to the pointer to the memory + * @param m_cost number of blocks to allocate in the memory + * @return ARGON2_OK if @memory is a valid pointer and memory is allocated + */ +int allocate_memory(block **memory, uint32_t m_cost); + +/* Function that securely cleans the memory + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +void secure_wipe_memory(void *v, size_t n); + +/* Clears memory + * @param instance pointer to the current instance + * @param clear_memory indicates if we clear the memory with zeros. + */ +void clear_memory(argon2_instance_t *instance, int clear); + +/* Deallocates memory + * @param memory pointer to the blocks + */ +void free_memory(block *memory); + +/* + * Computes absolute position of reference block in the lane following a skewed + * distribution and using a pseudo-random value as input + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rand 32-bit pseudo-random value used to determine the position + * @param same_lane Indicates if the block will be taken from the current lane. + * If so we can reference the current segment + * @pre All pointers must be valid + */ +uint32_t index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane); + +/* + * Function that validates all inputs against predefined restrictions and return + * an error code + * @param context Pointer to current Argon2 context + * @return ARGON2_OK if everything is all right, otherwise one of error codes + * (all defined in + */ +int validate_inputs(const argon2_context *context); + +/* + * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears + * password and secret if needed + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param blockhash Buffer for pre-hashing digest + * @param type Argon2 type + * @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes + * allocated + */ +void initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type); + +/* + * Function creates first 2 blocks per lane + * @param instance Pointer to the current instance + * @param blockhash Pointer to the pre-hashing digest + * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values + */ +void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance); + +/* + * Function allocates memory, hashes the inputs with Blake, and creates first + * two blocks. Returns the pointer to the main memory with 2 blocks per lane + * initialized + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param instance Current Argon2 instance + * @return Zero if successful, -1 if memory failed to allocate. @context->state + * will be modified if successful. + */ +int initialize(argon2_instance_t *instance, argon2_context *context); + +/* + * XORing the last block of each lane, hashing it, making the tag. Deallocates + * the memory. + * @param context Pointer to current Argon2 context (use only the out parameters + * from it) + * @param instance Pointer to current instance of Argon2 + * @pre instance->state must point to necessary amount of memory + * @pre context->out must point to outlen bytes of memory + * @pre if context->free_cbk is not NULL, it should point to a function that + * deallocates memory + */ +void finalize(const argon2_context *context, argon2_instance_t *instance); + +/* + * Function that fills the segment using previous segments also from other + * threads + * @param instance Pointer to the current instance + * @param position Current position + * @pre all block pointers must be valid + */ +void fill_segment(const argon2_instance_t *instance, + argon2_position_t position); + +/* + * Function that fills the entire memory t_cost times based on the first two + * blocks in each lane + * @param instance Pointer to the current instance + * @return ARGON2_OK if successful, @context->state + */ +int fill_memory_blocks(argon2_instance_t *instance); + +#endif diff --git a/ext/standard/argon2lib/encoding.c b/ext/standard/argon2lib/encoding.c new file mode 100644 index 00000000000..a0cafd72c53 --- /dev/null +++ b/ext/standard/argon2lib/encoding.c @@ -0,0 +1,426 @@ +#include +#include +#include +#include +#include "encoding.h" +#include "core.h" + +/* + * Example code for a decoder and encoder of "hash strings", with Argon2 + * parameters. + * + * This code comprises three sections: + * + * -- The first section contains generic Base64 encoding and decoding + * functions. It is conceptually applicable to any hash function + * implementation that uses Base64 to encode and decode parameters, + * salts and outputs. It could be made into a library, provided that + * the relevant functions are made public (non-static) and be given + * reasonable names to avoid collisions with other functions. + * + * -- The second section is specific to Argon2. It encodes and decodes + * the parameters, salts and outputs. It does not compute the hash + * itself. + * + * -- The third section is test code, with a main() function. With + * this section, the whole file compiles as a stand-alone program + * that exercises the encoding and decoding functions with some + * test vectors. + * + * The code was originally written by Thomas Pornin , + * to whom comments and remarks may be sent. It is released under what + * should amount to Public Domain or its closest equivalent; the + * following mantra is supposed to incarnate that fact with all the + * proper legal rituals: + * + * --------------------------------------------------------------------- + * This file is provided under the terms of Creative Commons CC0 1.0 + * Public Domain Dedication. To the extent possible under law, the + * author (Thomas Pornin) has waived all copyright and related or + * neighboring rights to this file. This work is published from: Canada. + * --------------------------------------------------------------------- + * + * Copyright (c) 2015 Thomas Pornin + */ + +/* ==================================================================== */ +/* + * Common code; could be shared between different hash functions. + * + * Note: the Base64 functions below assume that uppercase letters (resp. + * lowercase letters) have consecutive numerical codes, that fit on 8 + * bits. All modern systems use ASCII-compatible charsets, where these + * properties are true. If you are stuck with a dinosaur of a system + * that still defaults to EBCDIC then you already have much bigger + * interoperability issues to deal with. + */ + +/* + * Some macros for constant-time comparisons. These work over values in + * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". + */ +#define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF) +#define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF) +#define GE(x, y) (GT(y, x) ^ 0xFF) +#define LT(x, y) GT(y, x) +#define LE(x, y) GE(y, x) + +/* + * Convert value x (0..63) to corresponding Base64 character. + */ +static int b64_byte_to_char(unsigned x) { + return (LT(x, 26) & (x + 'A')) | + (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | + (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') | + (EQ(x, 63) & '/'); +} + +/* + * Convert character c to the corresponding 6-bit value. If character c + * is not a Base64 character, then 0xFF (255) is returned. + */ +static unsigned b64_char_to_byte(int c) { + unsigned x; + + x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | + (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | + (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) | + (EQ(c, '/') & 63); + return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); +} + +/* + * Convert some bytes to Base64. 'dst_len' is the length (in characters) + * of the output buffer 'dst'; if that buffer is not large enough to + * receive the result (including the terminating 0), then (size_t)-1 + * is returned. Otherwise, the zero-terminated Base64 string is written + * in the buffer, and the output length (counted WITHOUT the terminating + * zero) is returned. + */ +static size_t to_base64(char *dst, size_t dst_len, const void *src, + size_t src_len) { + size_t olen; + const unsigned char *buf; + unsigned acc, acc_len; + + olen = (src_len / 3) << 2; + switch (src_len % 3) { + case 2: + olen++; + /* fall through */ + case 1: + olen += 2; + break; + } + if (dst_len <= olen) { + return (size_t)-1; + } + acc = 0; + acc_len = 0; + buf = (const unsigned char *)src; + while (src_len-- > 0) { + acc = (acc << 8) + (*buf++); + acc_len += 8; + while (acc_len >= 6) { + acc_len -= 6; + *dst++ = (char)b64_byte_to_char((acc >> acc_len) & 0x3F); + } + } + if (acc_len > 0) { + *dst++ = (char)b64_byte_to_char((acc << (6 - acc_len)) & 0x3F); + } + *dst++ = 0; + return olen; +} + +/* + * Decode Base64 chars into bytes. The '*dst_len' value must initially + * contain the length of the output buffer '*dst'; when the decoding + * ends, the actual number of decoded bytes is written back in + * '*dst_len'. + * + * Decoding stops when a non-Base64 character is encountered, or when + * the output buffer capacity is exceeded. If an error occurred (output + * buffer is too small, invalid last characters leading to unprocessed + * buffered bits), then NULL is returned; otherwise, the returned value + * points to the first non-Base64 character in the source stream, which + * may be the terminating zero. + */ +static const char *from_base64(void *dst, size_t *dst_len, const char *src) { + size_t len; + unsigned char *buf; + unsigned acc, acc_len; + + buf = (unsigned char *)dst; + len = 0; + acc = 0; + acc_len = 0; + for (;;) { + unsigned d; + + d = b64_char_to_byte(*src); + if (d == 0xFF) { + break; + } + src++; + acc = (acc << 6) + d; + acc_len += 6; + if (acc_len >= 8) { + acc_len -= 8; + if ((len++) >= *dst_len) { + return NULL; + } + *buf++ = (acc >> acc_len) & 0xFF; + } + } + + /* + * If the input length is equal to 1 modulo 4 (which is + * invalid), then there will remain 6 unprocessed bits; + * otherwise, only 0, 2 or 4 bits are buffered. The buffered + * bits must also all be zero. + */ + if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) { + return NULL; + } + *dst_len = len; + return src; +} + +/* + * Decode decimal integer from 'str'; the value is written in '*v'. + * Returned value is a pointer to the next non-decimal character in the + * string. If there is no digit at all, or the value encoding is not + * minimal (extra leading zeros), or the value does not fit in an + * 'unsigned long', then NULL is returned. + */ +static const char *decode_decimal(const char *str, unsigned long *v) { + const char *orig; + unsigned long acc; + + acc = 0; + for (orig = str;; str++) { + int c; + + c = *str; + if (c < '0' || c > '9') { + break; + } + c -= '0'; + if (acc > (ULONG_MAX / 10)) { + return NULL; + } + acc *= 10; + if ((unsigned long)c > (ULONG_MAX - acc)) { + return NULL; + } + acc += (unsigned long)c; + } + if (str == orig || (*orig == '0' && str != (orig + 1))) { + return NULL; + } + *v = acc; + return str; +} + +/* ==================================================================== */ +/* + * Code specific to Argon2. + * + * The code below applies the following format: + * + * $argon2[$v=]$m=,t=,p=[,keyid=][,data=][$[$]] + * + * where is either 'd' or 'i', is a decimal integer (positive, fits in + * an 'unsigned long'), and is Base64-encoded data (no '=' padding + * characters, no newline or whitespace). + * The "keyid" is a binary identifier for a key (up to 8 bytes); + * "data" is associated data (up to 32 bytes). When the 'keyid' + * (resp. the 'data') is empty, then it is ommitted from the output. + * + * The last two binary chunks (encoded in Base64) are, in that order, + * the salt and the output. Both are optional, but you cannot have an + * output without a salt. The binary salt length is between 8 and 48 bytes. + * The output length is always exactly 32 bytes. + */ + +int decode_string(argon2_context *ctx, const char *str, argon2_type type) { + +/* check for prefix */ +#define CC(prefix) \ + do { \ + size_t cc_len = strlen(prefix); \ + if (strncmp(str, prefix, cc_len) != 0) { \ + return ARGON2_DECODING_FAIL; \ + } \ + str += cc_len; \ + } while ((void)0, 0) + +/* prefix checking with supplied code */ +#define CC_opt(prefix, code) \ + do { \ + size_t cc_len = strlen(prefix); \ + if (strncmp(str, prefix, cc_len) == 0) { \ + str += cc_len; \ + { code; } \ + } \ + } while ((void)0, 0) + +/* Decoding prefix into decimal */ +#define DECIMAL(x) \ + do { \ + unsigned long dec_x; \ + str = decode_decimal(str, &dec_x); \ + if (str == NULL) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (x) = dec_x; \ + } while ((void)0, 0) + +#define BIN(buf, max_len, len) \ + do { \ + size_t bin_len = (max_len); \ + str = from_base64(buf, &bin_len, str); \ + if (str == NULL || bin_len > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (len) = (uint32_t)bin_len; \ + } while ((void)0, 0) + + size_t maxadlen = ctx->adlen; + size_t maxsaltlen = ctx->saltlen; + size_t maxoutlen = ctx->outlen; + int validation_result; + + ctx->adlen = 0; + ctx->saltlen = 0; + ctx->outlen = 0; + ctx->pwdlen = 0; + + if (type == Argon2_i) + CC("$argon2i"); + else if (type == Argon2_d) + CC("$argon2d"); + else + return ARGON2_INCORRECT_TYPE; + ctx->version = ARGON2_VERSION_10; + /* Reading the version number if the default is suppressed */ + CC_opt("$v=", DECIMAL(ctx->version)); + CC("$m="); + DECIMAL(ctx->m_cost); + CC(",t="); + DECIMAL(ctx->t_cost); + CC(",p="); + DECIMAL(ctx->lanes); + ctx->threads = ctx->lanes; + + CC_opt(",data=", BIN(ctx->ad, maxadlen, ctx->adlen)); + if (*str == 0) { + return ARGON2_OK; + } + CC("$"); + BIN(ctx->salt, maxsaltlen, ctx->saltlen); + if (*str == 0) { + return ARGON2_OK; + } + CC("$"); + BIN(ctx->out, maxoutlen, ctx->outlen); + validation_result = validate_inputs(ctx); + if (validation_result != ARGON2_OK) { + return validation_result; + } + if (*str == 0) { + return ARGON2_OK; + } else { + return ARGON2_DECODING_FAIL; + } +#undef CC +#undef CC_opt +#undef DECIMAL +#undef BIN +} + +int encode_string(char *dst, size_t dst_len, argon2_context *ctx, + argon2_type type) { +#define SS(str) \ + do { \ + size_t pp_len = strlen(str); \ + if (pp_len >= dst_len) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + memcpy(dst, str, pp_len + 1); \ + dst += pp_len; \ + dst_len -= pp_len; \ + } while ((void)0, 0) + +#define SX(x) \ + do { \ + char tmp[30]; \ + sprintf(tmp, "%lu", (unsigned long)(x)); \ + SS(tmp); \ + } while ((void)0, 0) + +#define SB(buf, len) \ + do { \ + size_t sb_len = to_base64(dst, dst_len, buf, len); \ + if (sb_len == (size_t)-1) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + dst += sb_len; \ + dst_len -= sb_len; \ + } while ((void)0, 0) + + if (type == Argon2_i) + SS("$argon2i$v="); + else if (type == Argon2_d) + SS("$argon2d$v="); + else + return ARGON2_ENCODING_FAIL; + + if (validate_inputs(ctx) != ARGON2_OK) { + return validate_inputs(ctx); + } + SX(ctx->version); + SS("$m="); + SX(ctx->m_cost); + SS(",t="); + SX(ctx->t_cost); + SS(",p="); + SX(ctx->lanes); + + if (ctx->adlen > 0) { + SS(",data="); + SB(ctx->ad, ctx->adlen); + } + + if (ctx->saltlen == 0) + return ARGON2_OK; + + SS("$"); + SB(ctx->salt, ctx->saltlen); + + if (ctx->outlen == 0) + return ARGON2_OK; + + SS("$"); + SB(ctx->out, ctx->outlen); + return ARGON2_OK; + +#undef SS +#undef SX +#undef SB +} + +size_t b64len(uint32_t len) { + return (((size_t)len + 2) / 3) * 4; +} + +size_t numlen(uint32_t num) { + size_t len = 1; + while (num >= 10) { + ++len; + num = num / 10; + } + return len; +} + diff --git a/ext/standard/argon2lib/encoding.h b/ext/standard/argon2lib/encoding.h new file mode 100644 index 00000000000..8671f6b3d62 --- /dev/null +++ b/ext/standard/argon2lib/encoding.h @@ -0,0 +1,40 @@ +#ifndef ENCODING_H +#define ENCODING_H +#include "argon2.h" + +#define ARGON2_MAX_DECODED_LANES UINT32_C(255) +#define ARGON2_MIN_DECODED_SALT_LEN UINT32_C(8) +#define ARGON2_MIN_DECODED_OUT_LEN UINT32_C(12) + +/* +* encode an Argon2 hash string into the provided buffer. 'dst_len' +* contains the size, in characters, of the 'dst' buffer; if 'dst_len' +* is less than the number of required characters (including the +* terminating 0), then this function returns ARGON2_ENCODING_ERROR. +* +* if ctx->outlen is 0, then the hash string will be a salt string +* (no output). if ctx->saltlen is also 0, then the string will be a +* parameter-only string (no salt and no output). +* +* on success, ARGON2_OK is returned. +* +* No other parameters are checked +*/ +int encode_string(char *dst, size_t dst_len, argon2_context *ctx, + argon2_type type); + +/* +* Decodes an Argon2 hash string into the provided structure 'ctx'. +* The fields ctx.saltlen, ctx.adlen, ctx.outlen set the maximal salt, ad, out +* length values that are allowed; invalid input string causes an error. +* Returned value is ARGON2_OK on success, other ARGON2_ codes on error. +*/ +int decode_string(argon2_context *ctx, const char *str, argon2_type type); + +/* Returns the length of the encoded byte stream with length len */ +size_t b64len(uint32_t len); + +/* Returns the length of the encoded number num */ +size_t numlen(uint32_t num); + +#endif diff --git a/ext/standard/argon2lib/opt.c b/ext/standard/argon2lib/opt.c new file mode 100644 index 00000000000..2ba467d5d67 --- /dev/null +++ b/ext/standard/argon2lib/opt.c @@ -0,0 +1,220 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include + +#include "argon2.h" +#include "opt.h" + +#include "blake2/blake2.h" +#include "blake2/blamka-round-opt.h" + +void fill_block(__m128i *state, const uint8_t *ref_block, uint8_t *next_block) { + __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + block_XY[i] = state[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *)(&ref_block[16 * i]))); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], + state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], + state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], + state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], + state[8 * 6 + i], state[8 * 7 + i]); + } + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128(state[i], block_XY[i]); + _mm_storeu_si128((__m128i *)(&next_block[16 * i]), state[i]); + } +} + +void fill_block_with_xor(__m128i *state, const uint8_t *ref_block, + uint8_t *next_block) { + __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *)(&ref_block[16 * i]))); + block_XY[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *)(&next_block[16 * i]))); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], + state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], + state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], + state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], + state[8 * 6 + i], state[8 * 7 + i]); + } + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128(state[i], block_XY[i]); + _mm_storeu_si128((__m128i *)(&next_block[16 * i]), state[i]); + } +} + +void generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, + uint64_t *pseudo_rands) { + block address_block, input_block, tmp_block; + uint32_t i; + + init_block_value(&address_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + /*Temporary zero-initialized blocks*/ + __m128i zero_block[ARGON2_OWORDS_IN_BLOCK]; + __m128i zero2_block[ARGON2_OWORDS_IN_BLOCK]; + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + init_block_value(&address_block, 0); + init_block_value(&tmp_block, 0); + /*Increasing index counter*/ + input_block.v[6]++; + /*First iteration of G*/ + fill_block_with_xor(zero_block, (uint8_t *)&input_block.v, + (uint8_t *)&tmp_block.v); + /*Second iteration of G*/ + fill_block_with_xor(zero2_block, (uint8_t *)&tmp_block.v, + (uint8_t *)&address_block.v); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void fill_segment(const argon2_instance_t *instance, + argon2_position_t position) { + block *ref_block = NULL, *curr_block = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m128i state[64]; + int data_independent_addressing; + + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + + if (instance == NULL) { + return; + } + + data_independent_addressing = (instance->type == Argon2_i); + + pseudo_rands = + (uint64_t *)malloc(sizeof(uint64_t) * instance->segment_length); + if (pseudo_rands == NULL) { + return; + } + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + pseudo_rand = pseudo_rands[i]; + } else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + if (ARGON2_VERSION_10 == instance->version) { + /* version 1.2.1 and earlier: overwrite, not XOR */ + fill_block(state, (uint8_t *)ref_block->v, + (uint8_t *)curr_block->v); + } else { + if(0 == position.pass) { + fill_block(state, (uint8_t *)ref_block->v, + (uint8_t *)curr_block->v); + } else { + fill_block_with_xor(state, (uint8_t *)ref_block->v, + (uint8_t *)curr_block->v); + } + } + } + + free(pseudo_rands); +} diff --git a/ext/standard/argon2lib/opt.h b/ext/standard/argon2lib/opt.h new file mode 100644 index 00000000000..49660c2984f --- /dev/null +++ b/ext/standard/argon2lib/opt.h @@ -0,0 +1,52 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#ifndef ARGON2_OPT_H +#define ARGON2_OPT_H + +#include "core.h" +#include + +/* + * Function fills a new memory block by XORing the new block over the old one. Memory must be initialized. + * After finishing, @state is identical to @next_block + * @param state Pointer to the just produced block. Content will be updated(!) + * @param ref_block Pointer to the reference block + * @param next_block Pointer to the block to be XORed over. May coincide with @ref_block + * @pre all block pointers must be valid + */ +void fill_block_with_xor(__m128i *state, const uint8_t *ref_block, uint8_t *next_block); + +/* LEGACY CODE: version 1.2.1 and earlier +* Function fills a new memory block by overwriting @next_block. +* @param state Pointer to the just produced block. Content will be updated(!) +* @param ref_block Pointer to the reference block +* @param next_block Pointer to the block to be XORed over. May coincide with @ref_block +* @pre all block pointers must be valid +*/ +void fill_block(__m128i *state, const uint8_t *ref_block, uint8_t *next_block); + + +/* + * Generate pseudo-random values to reference blocks in the segment and puts + * them into the array + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rands Pointer to the array of 64-bit values + * @pre pseudo_rands must point to @a instance->segment_length allocated values + */ +void generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, + uint64_t *pseudo_rands); + +#endif /* ARGON2_OPT_H */ diff --git a/ext/standard/argon2lib/ref.c b/ext/standard/argon2lib/ref.c new file mode 100644 index 00000000000..9ee610128d9 --- /dev/null +++ b/ext/standard/argon2lib/ref.c @@ -0,0 +1,228 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include + +#include "argon2.h" +#include "ref.h" + +#include "blake2/blamka-round-ref.h" +#include "blake2/blake2-impl.h" +#include "blake2/blake2.h" + + +void fill_block(const block *prev_block, const block *ref_block, + block *next_block) { + block blockR, block_tmp; + unsigned i; + + copy_block(&blockR, ref_block); + xor_block(&blockR, prev_block); + copy_block(&block_tmp, &blockR); + /*Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block */ + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + copy_block(next_block, &block_tmp); + xor_block(next_block, &blockR); +} + + +void fill_block_with_xor(const block *prev_block, const block *ref_block, + block *next_block) { + block blockR, block_tmp; + unsigned i; + + copy_block(&blockR, ref_block); + xor_block(&blockR, prev_block); + copy_block(&block_tmp, &blockR); + xor_block(&block_tmp, next_block); /*Saving the next block contents for XOR over*/ + /*Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block + next_block*/ + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + copy_block(next_block, &block_tmp); + xor_block(next_block, &blockR); +} + +void generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, + uint64_t *pseudo_rands) { + block zero_block, input_block, address_block,tmp_block; + uint32_t i; + + init_block_value(&zero_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + input_block.v[6]++; + init_block_value(&tmp_block, 0); + init_block_value(&address_block, 0); + fill_block_with_xor(&zero_block, &input_block, &tmp_block); + fill_block_with_xor(&zero_block, &tmp_block, &address_block); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void fill_segment(const argon2_instance_t *instance, + argon2_position_t position) { + block *ref_block = NULL, *curr_block = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index; + uint32_t i; + int data_independent_addressing; + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + + if (instance == NULL) { + return; + } + + data_independent_addressing = (instance->type == Argon2_i); + + pseudo_rands = + (uint64_t *)malloc(sizeof(uint64_t) * (instance->segment_length)); + + if (pseudo_rands == NULL) { + return; + } + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + pseudo_rand = pseudo_rands[i]; + } else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + if (ARGON2_VERSION_10 == instance->version) { + /* version 1.2.1 and earlier: overwrite, not XOR */ + fill_block(instance->memory + prev_offset, ref_block, curr_block); + } else { + if(0 == position.pass) { + fill_block(instance->memory + prev_offset, ref_block, + curr_block); + } else { + fill_block_with_xor(instance->memory + prev_offset, ref_block, + curr_block); + } + } + } + + free(pseudo_rands); +} diff --git a/ext/standard/argon2lib/ref.h b/ext/standard/argon2lib/ref.h new file mode 100644 index 00000000000..8d06b2a8f91 --- /dev/null +++ b/ext/standard/argon2lib/ref.h @@ -0,0 +1,51 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#ifndef ARGON2_REF_H +#define ARGON2_REF_H + +#include "core.h" + +/* + * Function fills a new memory block by XORing over @next_block. @next_block must be initialized + * @param prev_block Pointer to the previous block + * @param ref_block Pointer to the reference block + * @param next_block Pointer to the block to be constructed + * @pre all block pointers must be valid + */ +void fill_block_with_xor(const block *prev_block, const block *ref_block, + block *next_block); + +/* LEGACY CODE: version 1.2.1 and earlier +* Function fills a new memory block by overwriting @next_block. +* @param prev_block Pointer to the previous block +* @param ref_block Pointer to the reference block +* @param next_block Pointer to the block to be constructed +* @pre all block pointers must be valid +*/ +void fill_block(const block *prev_block, const block *ref_block, + block *next_block); + +/* + * Generate pseudo-random values to reference blocks in the segment and puts + * them into the array + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rands Pointer to the array of 64-bit values + * @pre pseudo_rands must point to @a instance->segment_length allocated values + */ +void generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, + uint64_t *pseudo_rands); + +#endif /* ARGON2_REF_H */ diff --git a/ext/standard/argon2lib/thread.c b/ext/standard/argon2lib/thread.c new file mode 100644 index 00000000000..412261f12ca --- /dev/null +++ b/ext/standard/argon2lib/thread.c @@ -0,0 +1,36 @@ +#include "thread.h" +#if defined(_WIN32) +#include +#endif + +int argon2_thread_create(argon2_thread_handle_t *handle, + argon2_thread_func_t func, void *args) { + if (NULL == handle || func == NULL) { + return -1; + } +#if defined(_WIN32) + *handle = _beginthreadex(NULL, 0, func, args, 0, NULL); + return *handle != 0 ? 0 : -1; +#else + return pthread_create(handle, NULL, func, args); +#endif +} + +int argon2_thread_join(argon2_thread_handle_t handle) { +#if defined(_WIN32) + if (WaitForSingleObject((HANDLE)handle, INFINITE) == WAIT_OBJECT_0) { + return CloseHandle((HANDLE)handle) != 0 ? 0 : -1; + } + return -1; +#else + return pthread_join(handle, NULL); +#endif +} + +void argon2_thread_exit(void) { +#if defined(_WIN32) + _endthreadex(0); +#else + pthread_exit(NULL); +#endif +} diff --git a/ext/standard/argon2lib/thread.h b/ext/standard/argon2lib/thread.h new file mode 100644 index 00000000000..57c4ce56225 --- /dev/null +++ b/ext/standard/argon2lib/thread.h @@ -0,0 +1,46 @@ +#ifndef ARGON2_THREAD_H +#define ARGON2_THREAD_H +/* + Here we implement an abstraction layer for the simpĺe requirements + of the Argon2 code. We only require 3 primitives---thread creation, + joining, and termination---so full emulation of the pthreads API + is unwarranted. Currently we wrap pthreads and Win32 threads. + + The API defines 2 types: the function pointer type, + argon2_thread_func_t, + and the type of the thread handle---argon2_thread_handle_t. +*/ +#if defined(_WIN32) +#include +typedef unsigned(__stdcall *argon2_thread_func_t)(void *); +typedef uintptr_t argon2_thread_handle_t; +#else +#include +typedef void *(*argon2_thread_func_t)(void *); +typedef pthread_t argon2_thread_handle_t; +#endif + +/* Creates a thread + * @param handle pointer to a thread handle, which is the output of this + * function. Must not be NULL. + * @param func A function pointer for the thread's entry point. Must not be + * NULL. + * @param args Pointer that is passed as an argument to @func. May be NULL. + * @return 0 if @handle and @func are valid pointers and a thread is successfuly + * created. + */ +int argon2_thread_create(argon2_thread_handle_t *handle, + argon2_thread_func_t func, void *args); + +/* Waits for a thread to terminate + * @param handle Handle to a thread created with argon2_thread_create. + * @return 0 if @handle is a valid handle, and joining completed successfully. +*/ +int argon2_thread_join(argon2_thread_handle_t handle); + +/* Terminate the current thread. Must be run inside a thread created by + * argon2_thread_create. +*/ +void argon2_thread_exit(void); + +#endif diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 26eb0563217..f37d34928b2 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -550,6 +550,13 @@ dnl Check for getrandom on newer Linux kernels dnl AC_CHECK_DECLS([getrandom]) +dnl +dnl Check for argon2 +dnl +AC_MSG_RESULT([Using bundled Argon2 library]) + +LIBS="$LIBS -lpthread" + dnl dnl Setup extension sources dnl @@ -564,8 +571,10 @@ PHP_NEW_EXTENSION(standard, array.c base64.c basic_functions.c browscap.c crc32. http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ filters.c proc_open.c streamsfuncs.c http.c password.c \ - random.c,,, + random.c argon2lib/argon2.c argon2lib/core.c argon2lib/blake2/blake2b.c \ + argon2lib/thread.c argon2lib/encoding.c argon2lib/ref.c,,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_MAKEFILE_FRAGMENT PHP_INSTALL_HEADERS([ext/standard/]) +PHP_INSTALL_HEADERS([ext/standard/argon2lib]) diff --git a/ext/standard/password.c b/ext/standard/password.c index 4da1682056a..ca223dcc3e0 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -13,6 +13,7 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Anthony Ferrara | + | Charles R. Portwood II | +----------------------------------------------------------------------+ */ @@ -30,6 +31,7 @@ #include "zend_interfaces.h" #include "info.h" #include "php_random.h" +#include "argon2lib/argon2.h" #if PHP_WIN32 #include "win32/winutil.h" @@ -41,12 +43,12 @@ PHP_MINIT_FUNCTION(password) /* {{{ */ REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT", PHP_PASSWORD_BCRYPT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_ARGON2I", PHP_PASSWORD_ARGON2I, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_ARGON2D", PHP_PASSWORD_ARGON2D, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2", PHP_PASSWORD_ARGON2, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT_DEFAULT_COST", PHP_PASSWORD_BCRYPT_COST, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_MEMORY_COST", PHP_PASSWORD_ARGON2_MEMORY_COST, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_TIME_COST", PHP_PASSWORD_ARGON2_TIME_COST, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_LANES", PHP_PASSWORD_ARGON2_LANES, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_THREADS", PHP_PASSWORD_ARGON2_THREADS, CONST_CS | CONST_PERSISTENT); return SUCCESS; } @@ -157,6 +159,8 @@ static int php_password_make_salt(size_t length, char *ret) /* {{{ */ } /* }}} */ +/* {{{ proto array password_get_info(string $hash) +Retrieves information about a given hash */ PHP_FUNCTION(password_get_info) { php_password_algo algo; @@ -184,14 +188,15 @@ PHP_FUNCTION(password_get_info) case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { + zend_long v = 0; zend_long m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; zend_long t_cost = PHP_PASSWORD_ARGON2_TIME_COST; - zend_long lanes = PHP_PASSWORD_ARGON2_LANES; + zend_long threads = PHP_PASSWORD_ARGON2_THREADS; - sscanf(hash, "$%*[argon2id]$v=%*ld$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &m_cost, &t_cost, &lanes); + sscanf(hash, "$%*[argon2id]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &m_cost, &t_cost, &threads); add_assoc_long(&options, "m_cost", m_cost); add_assoc_long(&options, "t_cost", t_cost); - add_assoc_long(&options, "lanes", lanes); + add_assoc_long(&options, "threads", threads); } break; case PHP_PASSWORD_UNKNOWN: @@ -205,7 +210,10 @@ PHP_FUNCTION(password_get_info) add_assoc_string(return_value, "algoName", algo_name); add_assoc_zval(return_value, "options", &options); } +/** }}} */ +/* {{{ proto boolean password_needs_rehash(string $hash, integer $algo, array $options) +Determines if a given hash requires re-hashing based upon parameters */ PHP_FUNCTION(password_needs_rehash) { zend_long new_algo = 0; @@ -243,9 +251,10 @@ PHP_FUNCTION(password_needs_rehash) case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { + zend_long v = 0; zend_long new_m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST, m_cost = 0; zend_long new_t_cost = PHP_PASSWORD_ARGON2_TIME_COST, t_cost = 0; - zend_long new_lanes = PHP_PASSWORD_ARGON2_LANES, lanes = 0; + zend_long new_threads = PHP_PASSWORD_ARGON2_THREADS, threads = 0; if (options && (option_buffer = zend_hash_str_find(options, "m_cost", sizeof("m_cost")-1)) != NULL) { new_m_cost = zval_get_long(option_buffer); @@ -255,13 +264,13 @@ PHP_FUNCTION(password_needs_rehash) new_t_cost = zval_get_long(option_buffer); } - if (options && (option_buffer = zend_hash_str_find(options, "lanes", sizeof("lanes")-1)) != NULL) { - new_lanes = zval_get_long(option_buffer); + if (options && (option_buffer = zend_hash_str_find(options, "threads", sizeof("threads")-1)) != NULL) { + new_threads = zval_get_long(option_buffer); } - sscanf(hash, "$%*[argon2id]$v=%*ld$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &m_cost, &t_cost, &lanes); + sscanf(hash, "$%*[argon2id]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &m_cost, &t_cost, &threads); - if (new_t_cost != t_cost || new_m_cost != m_cost || new_lanes != lanes) { + if (new_t_cost != t_cost || new_m_cost != m_cost || new_threads != threads) { RETURN_TRUE; } } @@ -272,8 +281,9 @@ PHP_FUNCTION(password_needs_rehash) } RETURN_FALSE; } +/* }}} */ -/* {{{ proto boolean password_make_salt(string password, string hash) +/* {{{ proto boolean password_verify(string password, string hash) Verify a hash created using crypt() or password_hash() */ PHP_FUNCTION(password_verify) { @@ -300,29 +310,44 @@ PHP_FUNCTION(password_verify) zend_string_free(ret); RETURN_FALSE; } + + /* We're using this method instead of == in order to provide + * resistance towards timing attacks. This is a constant time + * equality check that will always check every byte of both + * values. */ + for (i = 0; i < hash_len; i++) { + status |= (ZSTR_VAL(ret)[i] ^ hash[i]); + } + + zend_string_free(ret); + + RETURN_BOOL(status == 0); } case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { - // @todo: Implement argon2_verify via import + argon2_type type = Argon2_i; + + if (strstr(hash, "argon2d")) { + type = Argon2_d; + } else if (strstr(hash, "argon2i")) { + type = Argon2_i; + } + + status = argon2_verify(hash, password, password_len, type); + + if (status == ARGON2_OK) { + RETURN_TRUE; + } + + RETURN_FALSE; } case PHP_PASSWORD_UNKNOWN: default: RETURN_FALSE; } - /* We're using this method instead of == in order to provide - * resistance towards timing attacks. This is a constant time - * equality check that will always check every byte of both - * values. */ - for (i = 0; i < hash_len; i++) { - status |= (ZSTR_VAL(ret)[i] ^ hash[i]); - } - - zend_string_free(ret); - - RETURN_BOOL(status == 0); - + RETURN_FALSE; } /* }}} */ @@ -339,6 +364,12 @@ PHP_FUNCTION(password_hash) zval *option_buffer; zend_string *result; + // Argon2 Options + size_t t_cost = PHP_PASSWORD_ARGON2_TIME_COST; + size_t m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; + size_t threads = PHP_PASSWORD_ARGON2_THREADS; + argon2_type type = Argon2_i; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|H", &password, &password_len, &algo, &options) == FAILURE) { return; } @@ -365,7 +396,40 @@ PHP_FUNCTION(password_hash) case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { - // @todo: Implement Argon2_hash with options + if (options && (option_buffer = zend_hash_str_find(options, "m_cost", sizeof("m_cost")-1)) != NULL) { + m_cost = zval_get_long(option_buffer); + } + + if (m_cost > ARGON2_MAX_MEMORY || m_cost < ARGON2_MIN_MEMORY) { + php_error_docref(NULL, E_WARNING, "Memory cost is outside of allowed memory range", m_cost); + RETURN_NULL(); + } + + if (options && (option_buffer = zend_hash_str_find(options, "t_cost", sizeof("t_cost")-1)) != NULL) { + t_cost = zval_get_long(option_buffer); + } + + if (t_cost > ARGON2_MAX_TIME || t_cost < ARGON2_MIN_TIME) { + php_error_docref(NULL, E_WARNING, "Time cost is outside of allowed time range", t_cost); + RETURN_NULL(); + } + + if (options && (option_buffer = zend_hash_str_find(options, "threads", sizeof("threads")-1)) != NULL) { + threads = zval_get_long(option_buffer); + } + + if (threads > ARGON2_MAX_LANES || threads == 0) { + php_error_docref(NULL, E_WARNING, "Invalid numeric input for threads", threads); + RETURN_NULL(); + } + + if (algo == PHP_PASSWORD_ARGON2D) { + type = Argon2_d; + } else if (algo == PHP_PASSWORD_ARGON2I) { + type = Argon2_i; + } + + required_salt_len = 16; } break; case PHP_PASSWORD_UNKNOWN: @@ -463,7 +527,52 @@ PHP_FUNCTION(password_hash) case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { - // @todo: Implement Argon2_hash with options + char *out; + char *encoded; + + size_t out_len = 32; + size_t encoded_len; + int result = 0; + + encoded_len = argon2_encodedlen( + t_cost, + m_cost, + threads, + (uint32_t)salt_len, + out_len + ); + + encoded = emalloc(encoded_len + 1); + out = emalloc(out_len + 1); + + result = argon2_hash( + t_cost, + m_cost, + threads, + password, + password_len, + salt, + salt_len, + out, + out_len, + encoded, + encoded_len, + type, + ARGON2_VERSION_NUMBER + ); + + zend_string *ret = zend_string_init(encoded, encoded_len, 0); + + efree(out); + efree(salt); + efree(encoded); + + if (result != ARGON2_OK) { + php_error_docref(NULL, E_WARNING, argon2_error_message(result)); + RETURN_FALSE; + } + + RETURN_STR(ret); } default: RETURN_FALSE; diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index 4c6e1133919..7c3c8821d90 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -13,6 +13,7 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Anthony Ferrara | + | Charles R. Portwood II | +----------------------------------------------------------------------+ */ @@ -28,17 +29,17 @@ PHP_FUNCTION(password_get_info); PHP_MINIT_FUNCTION(password); -#define PHP_PASSWORD_DEFAULT PHP_PASSWORD_ARGON2I +#define PHP_PASSWORD_ARGON2 PHP_PASSWORD_ARGON2I +#define PHP_PASSWORD_DEFAULT PHP_PASSWORD_ARGON2 #define PHP_PASSWORD_BCRYPT_COST 10 #define PHP_PASSWORD_ARGON2_MEMORY_COST 1<<16 #define PHP_PASSWORD_ARGON2_TIME_COST 3 -#define PHP_PASSWORD_ARGON2_LANES 1 +#define PHP_PASSWORD_ARGON2_THREADS 1 typedef enum { PHP_PASSWORD_UNKNOWN, PHP_PASSWORD_BCRYPT, - PHP_PASSWORD_ARGON2, PHP_PASSWORD_ARGON2I, PHP_PASSWORD_ARGON2D } php_password_algo; diff --git a/ext/standard/tests/password/password_get_info.phpt b/ext/standard/tests/password/password_get_info.phpt index 4c8dc04ff80..bbe207dd60d 100644 --- a/ext/standard/tests/password/password_get_info.phpt +++ b/ext/standard/tests/password/password_get_info.phpt @@ -11,6 +11,8 @@ var_dump(password_get_info('$2y$11$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vj var_dump(password_get_info('$2y$11$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100')); // Test Non-Bcrypt var_dump(password_get_info('$1$rasmusle$rISCgZzpwk3UhDidwXvin0')); +// Test Argon2 +//var_dump(password_get_info('$argon2i$v=19$m=65536,t=3,p=1$SWhIcG5MT21Pc01PbWdVZw$WagZELICsz7jlqOR2YzoEVTWb2oOX1tYdnhZYXxptbU')); echo "OK!"; ?> @@ -55,4 +57,19 @@ array(3) { array(0) { } } +array(3) { + ["algo"]=> + int(2) + ["algoName"]=> + string(7) "argon2i" + ["options"]=> + array(3) { + ["m_cost"]=> + int(65536) + ["t_cost"]=> + int(3) + ["threads"]=> + int(1) + } +} OK! From 0a1274f2b12ad7e200932b9950876ea19125e210 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Sat, 9 Jul 2016 13:18:45 -0500 Subject: [PATCH 04/18] Adding test cases for Argon2i and Argon2d Added Windows config.w32 changes Updated constants in php_password.h --- ext/standard/config.w32 | 5 +- ext/standard/password.c | 62 +++++++++---------- ext/standard/php_password.h | 4 +- .../tests/password/password_get_info.phpt | 24 +++++-- .../tests/password/password_hash.phpt | 20 +++++- .../tests/password/password_hash_error.phpt | 16 +++++ .../tests/password/password_needs_rehash.phpt | 8 ++- .../tests/password/password_verify.phpt | 13 +++- 8 files changed, 110 insertions(+), 42 deletions(-) diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index adff3d8c878..431dd3e4847 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -20,10 +20,13 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \ url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ user_filters.c uuencode.c filters.c proc_open.c password.c \ - streamsfuncs.c http.c flock_compat.c random.c", false /* never shared */, + streamsfuncs.c http.c flock_compat.c random.c \ + argon2lib/argon2.c argon2lib/core.c argon2lib/blake2/blake2b.c \ + argon2lib/thread.c argon2lib/encoding.c argon2lib/ref.c", false /* never shared */, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); PHP_INSTALL_HEADERS("", "ext/standard"); if (PHP_MBREGEX != "no") { CHECK_HEADER_ADD_INCLUDE("oniguruma.h", "CFLAGS_STANDARD", PHP_MBREGEX + ";ext\\mbstring\\oniguruma") } PHP_INSTALL_HEADERS("", "ext/standard"); +PHP_INSTALL_HEADERS([ext/standard/argon2lib]) diff --git a/ext/standard/password.c b/ext/standard/password.c index ca223dcc3e0..f312df80301 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -71,12 +71,12 @@ static char* php_password_get_algo_name(const php_password_algo algo) static php_password_algo php_password_determine_algo(const char *hash, const size_t len) { - if (hash[0] == '$' && strstr(hash, "argon2i")) { + if (len > 3 && hash[0] == '$' && hash[1] == '2' && hash[2] == 'y' && len == 60) { + return PHP_PASSWORD_BCRYPT; + } else if (hash[0] == '$' && strstr(hash, "argon2i")) { return PHP_PASSWORD_ARGON2I; } else if (hash[0] == '$' && strstr(hash, "argon2d")) { return PHP_PASSWORD_ARGON2D; - } else if (len > 3 && hash[0] == '$' && hash[1] == '2' && hash[2] == 'y' && len == 60) { - return PHP_PASSWORD_BCRYPT; } return PHP_PASSWORD_UNKNOWN; @@ -300,7 +300,29 @@ PHP_FUNCTION(password_verify) algo = php_password_determine_algo(hash, (size_t) hash_len); switch(algo) { + case PHP_PASSWORD_ARGON2I: + case PHP_PASSWORD_ARGON2D: + { + argon2_type type = Argon2_i; + + if (strstr(hash, "argon2d")) { + type = Argon2_d; + } else if (strstr(hash, "argon2i")) { + type = Argon2_i; + } + + status = argon2_verify(hash, password, password_len, type); + + if (status == ARGON2_OK) { + RETURN_TRUE; + } + + RETURN_FALSE; + } + break; case PHP_PASSWORD_BCRYPT: + case PHP_PASSWORD_UNKNOWN: + default: { if ((ret = php_crypt(password, (int)password_len, hash, (int)hash_len, 1)) == NULL) { RETURN_FALSE; @@ -323,28 +345,6 @@ PHP_FUNCTION(password_verify) RETURN_BOOL(status == 0); } - case PHP_PASSWORD_ARGON2I: - case PHP_PASSWORD_ARGON2D: - { - argon2_type type = Argon2_i; - - if (strstr(hash, "argon2d")) { - type = Argon2_d; - } else if (strstr(hash, "argon2i")) { - type = Argon2_i; - } - - status = argon2_verify(hash, password, password_len, type); - - if (status == ARGON2_OK) { - RETURN_TRUE; - } - - RETURN_FALSE; - } - case PHP_PASSWORD_UNKNOWN: - default: - RETURN_FALSE; } RETURN_FALSE; @@ -362,7 +362,6 @@ PHP_FUNCTION(password_hash) size_t salt_len = 0, required_salt_len = 0, hash_format_len; HashTable *options = 0; zval *option_buffer; - zend_string *result; // Argon2 Options size_t t_cost = PHP_PASSWORD_ARGON2_TIME_COST; @@ -419,7 +418,7 @@ PHP_FUNCTION(password_hash) } if (threads > ARGON2_MAX_LANES || threads == 0) { - php_error_docref(NULL, E_WARNING, "Invalid numeric input for threads", threads); + php_error_docref(NULL, E_WARNING, "Invalid number of threads", threads); RETURN_NULL(); } @@ -499,6 +498,7 @@ PHP_FUNCTION(password_hash) switch (algo) { case PHP_PASSWORD_BCRYPT: { + zend_string *result; salt[salt_len] = 0; hash = safe_emalloc(salt_len + hash_format_len, 1, 1); @@ -532,7 +532,7 @@ PHP_FUNCTION(password_hash) size_t out_len = 32; size_t encoded_len; - int result = 0; + int status = 0; encoded_len = argon2_encodedlen( t_cost, @@ -545,7 +545,7 @@ PHP_FUNCTION(password_hash) encoded = emalloc(encoded_len + 1); out = emalloc(out_len + 1); - result = argon2_hash( + status = argon2_hash( t_cost, m_cost, threads, @@ -567,8 +567,8 @@ PHP_FUNCTION(password_hash) efree(salt); efree(encoded); - if (result != ARGON2_OK) { - php_error_docref(NULL, E_WARNING, argon2_error_message(result)); + if (status != ARGON2_OK) { + php_error_docref(NULL, E_WARNING, argon2_error_message(status)); RETURN_FALSE; } diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index 7c3c8821d90..c71996dbf17 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -40,8 +40,8 @@ PHP_MINIT_FUNCTION(password); typedef enum { PHP_PASSWORD_UNKNOWN, PHP_PASSWORD_BCRYPT, - PHP_PASSWORD_ARGON2I, - PHP_PASSWORD_ARGON2D + PHP_PASSWORD_ARGON2D, + PHP_PASSWORD_ARGON2I } php_password_algo; #endif diff --git a/ext/standard/tests/password/password_get_info.phpt b/ext/standard/tests/password/password_get_info.phpt index bbe207dd60d..3e8b665ba27 100644 --- a/ext/standard/tests/password/password_get_info.phpt +++ b/ext/standard/tests/password/password_get_info.phpt @@ -11,9 +11,10 @@ var_dump(password_get_info('$2y$11$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vj var_dump(password_get_info('$2y$11$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100')); // Test Non-Bcrypt var_dump(password_get_info('$1$rasmusle$rISCgZzpwk3UhDidwXvin0')); -// Test Argon2 -//var_dump(password_get_info('$argon2i$v=19$m=65536,t=3,p=1$SWhIcG5MT21Pc01PbWdVZw$WagZELICsz7jlqOR2YzoEVTWb2oOX1tYdnhZYXxptbU')); - +// Test Argon2i +var_dump(password_get_info('$argon2i$v=19$m=65536,t=3,p=1$SWhIcG5MT21Pc01PbWdVZw$WagZELICsz7jlqOR2YzoEVTWb2oOX1tYdnhZYXxptbU')); +// Test Argon2d +var_dump(password_get_info('$argon2d$v=19$m=32768,t=2,p=1$YWpxd0VYRW9MLmp6VjFPZw$pWV5IsbBfjEK5c0bHzvAo0FsDNHUyM4p6j8vf2cxzb8')); echo "OK!"; ?> --EXPECT-- @@ -59,7 +60,7 @@ array(3) { } array(3) { ["algo"]=> - int(2) + int(3) ["algoName"]=> string(7) "argon2i" ["options"]=> @@ -72,4 +73,19 @@ array(3) { int(1) } } +array(3) { + ["algo"]=> + int(2) + ["algoName"]=> + string(7) "argon2d" + ["options"]=> + array(3) { + ["m_cost"]=> + int(32768) + ["t_cost"]=> + int(2) + ["threads"]=> + int(1) + } +} OK! diff --git a/ext/standard/tests/password/password_hash.phpt b/ext/standard/tests/password/password_hash.phpt index ebb27292ea2..665ead92caa 100644 --- a/ext/standard/tests/password/password_hash.phpt +++ b/ext/standard/tests/password/password_hash.phpt @@ -10,9 +10,27 @@ $hash = password_hash("foo", PASSWORD_BCRYPT); var_dump($hash === crypt("foo", $hash)); +$hash = password_hash('foo', PASSWORD_ARGON2); +var_dump(strlen($hash)); +var_dump(password_verify('foo', $hash)); + +$hash = password_hash('foo', PASSWORD_ARGON2I); +var_dump(strlen($hash)); +var_dump(password_verify('foo', $hash)); + +$hash = password_hash('foo', PASSWORD_ARGON2D); +var_dump(strlen($hash)); +var_dump(password_verify('foo', $hash)); + echo "OK!"; ?> --EXPECT-- int(60) bool(true) -OK! \ No newline at end of file +int(99) +bool(true) +int(99) +bool(true) +int(99) +bool(true) +OK! diff --git a/ext/standard/tests/password/password_hash_error.phpt b/ext/standard/tests/password/password_hash_error.phpt index 8dc954649db..9207fb76efa 100644 --- a/ext/standard/tests/password/password_hash_error.phpt +++ b/ext/standard/tests/password/password_hash_error.phpt @@ -21,6 +21,12 @@ var_dump(password_hash("123", PASSWORD_BCRYPT, array("salt" => array()))); /* Non-string salt, checking for memory leaks */ var_dump(password_hash('123', PASSWORD_BCRYPT, array('salt' => 1234))); +var_dump(password_hash('test', PASSWORD_ARGON2, ['m_cost' => 0])); + +var_dump(password_hash('test', PASSWORD_ARGON2, ['t_cost' => 0])); + +var_dump(password_hash('test', PASSWORD_ARGON2, ['threads' => 0])); + ?> --EXPECTF-- Warning: password_hash() expects at least 2 parameters, 0 given in %s on line %d @@ -50,3 +56,13 @@ Deprecated: password_hash(): Use of the 'salt' option to password_hash is deprec Warning: password_hash(): Provided salt is too short: 4 expecting 22 in %s on line %d NULL + +Warning: password_hash(): Memory cost is outside of allowed memory range in %s on line %d +NULL + +Warning: password_hash(): Time cost is outside of allowed time range in %s on line %d +NULL + +Warning: password_hash(): Invalid number of threads in %s on line %d +NULL + diff --git a/ext/standard/tests/password/password_needs_rehash.phpt b/ext/standard/tests/password/password_needs_rehash.phpt index 8efd0add8f3..b38c1dde20a 100644 --- a/ext/standard/tests/password/password_needs_rehash.phpt +++ b/ext/standard/tests/password/password_needs_rehash.phpt @@ -29,8 +29,9 @@ var_dump(password_needs_rehash('$2y$'.$cost.'$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.o // Should Issue Needs Rehash, Since Foo is cast to 0... var_dump(password_needs_rehash('$2y$10$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100y', PASSWORD_BCRYPT, array('cost' => 'foo'))); - - +var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['m_cost' => 1<<17])); +var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['t_cost' => 2])); +var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['threads' => 2])); echo "OK!"; ?> --EXPECT-- @@ -42,4 +43,7 @@ bool(true) bool(true) bool(false) bool(true) +bool(true) +bool(true) +bool(true) OK! diff --git a/ext/standard/tests/password/password_verify.phpt b/ext/standard/tests/password/password_verify.phpt index a196763c136..0e85413a352 100644 --- a/ext/standard/tests/password/password_verify.phpt +++ b/ext/standard/tests/password/password_verify.phpt @@ -18,6 +18,13 @@ var_dump(password_verify("rasmuslerdorf", "rl.3StKT.4T8M")); var_dump(password_verify("foo", "$1")); +var_dump(password_verify('test', '$argon2d$v=19$m=32768,t=2,p=1$YWpxd0VYRW9MLmp6VjFPZw$pWV5IsbBfjEK5c0bHzvAo0FsDNHUyM4p6j8vf2cxzb8')); + +var_dump(password_verify('argon2', '$argon2d$v=19$m=32768,t=2,p=1$YWpxd0VYRW9MLmp6VjFPZw$pWV5IsbBfjEK5c0bHzvAo0FsDNHUyM4p6j8vf2cxzb8')); + +var_dump(password_verify('test', '$argon2i$v=19$m=65536,t=3,p=1$OEVjWWs2Z3YvWlNZQ0ZmNw$JKin7ahjmh8JYvMyFcXri0Ss/Uvd3uYpD7MG6C/5Cy0')); + +var_dump(password_verify('argon2', '$argon2i$v=19$m=65536,t=3,p=1$OEVjWWs2Z3YvWlNZQ0ZmNw$JKin7ahjmh8JYvMyFcXri0Ss/Uvd3uYpD7MG6C/5Cy0')); echo "OK!"; ?> --EXPECT-- @@ -28,4 +35,8 @@ bool(true) bool(false) bool(true) bool(false) -OK! +bool(true) +bool(false) +bool(true) +bool(false) +OK! \ No newline at end of file From deba2b4572ffe9530a65e225a028536e353dde7b Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Sat, 9 Jul 2016 13:23:58 -0500 Subject: [PATCH 05/18] Fixing spacing in php_password.h --- ext/standard/php_password.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index c71996dbf17..7e546b76570 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -38,8 +38,8 @@ PHP_MINIT_FUNCTION(password); #define PHP_PASSWORD_ARGON2_THREADS 1 typedef enum { - PHP_PASSWORD_UNKNOWN, - PHP_PASSWORD_BCRYPT, + PHP_PASSWORD_UNKNOWN, + PHP_PASSWORD_BCRYPT, PHP_PASSWORD_ARGON2D, PHP_PASSWORD_ARGON2I } php_password_algo; From 1bc381848add707db42671b3c33e1082aa3e7f93 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Sun, 10 Jul 2016 08:16:55 -0500 Subject: [PATCH 06/18] Reverting PASSWORD_DEFAULT to PASSWORD_BCRYPT Indicating constants as defaults Minor coding standards change --- ext/standard/password.c | 10 +++++----- ext/standard/php_password.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/standard/password.c b/ext/standard/password.c index f312df80301..ab967ee7c4b 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -46,9 +46,9 @@ PHP_MINIT_FUNCTION(password) /* {{{ */ REGISTER_LONG_CONSTANT("PASSWORD_ARGON2", PHP_PASSWORD_ARGON2, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT_DEFAULT_COST", PHP_PASSWORD_BCRYPT_COST, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_MEMORY_COST", PHP_PASSWORD_ARGON2_MEMORY_COST, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_TIME_COST", PHP_PASSWORD_ARGON2_TIME_COST, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_THREADS", PHP_PASSWORD_ARGON2_THREADS, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_MEMORY_COST", PHP_PASSWORD_ARGON2_MEMORY_COST, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_TIME_COST", PHP_PASSWORD_ARGON2_TIME_COST, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_THREADS", PHP_PASSWORD_ARGON2_THREADS, CONST_CS | CONST_PERSISTENT); return SUCCESS; } @@ -212,7 +212,7 @@ PHP_FUNCTION(password_get_info) } /** }}} */ -/* {{{ proto boolean password_needs_rehash(string $hash, integer $algo, array $options) +/* {{{ proto boolean password_needs_rehash(string $hash, integer $algo[, array $options]) Determines if a given hash requires re-hashing based upon parameters */ PHP_FUNCTION(password_needs_rehash) { @@ -351,7 +351,7 @@ PHP_FUNCTION(password_verify) } /* }}} */ -/* {{{ proto string password_hash(string password, int algo, array options = array()) +/* {{{ proto string password_hash(string password, int algo[, array options = array()]) Hash a password */ PHP_FUNCTION(password_hash) { diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index 7e546b76570..e3104f7dbd3 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -30,7 +30,7 @@ PHP_FUNCTION(password_get_info); PHP_MINIT_FUNCTION(password); #define PHP_PASSWORD_ARGON2 PHP_PASSWORD_ARGON2I -#define PHP_PASSWORD_DEFAULT PHP_PASSWORD_ARGON2 +#define PHP_PASSWORD_DEFAULT PHP_PASSWORD_BCRYPT #define PHP_PASSWORD_BCRYPT_COST 10 #define PHP_PASSWORD_ARGON2_MEMORY_COST 1<<16 From bcfccdd9f4ec6c5b0897fcba20de05bcbeaa9ac6 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Mon, 11 Jul 2016 16:31:31 -0500 Subject: [PATCH 07/18] Removing argon2 library files in favor of --with-argon2[=DIR] - Configure flag now accepts --with-argon2 for dynamic linking with libargon2. Argon2 will be enabled in password_* only if this flag is passed. - --with-argon2 config flag allows user passed directory for linking - Added Argon2 specific tests to ensure existing tests do not fail when argon2 is disable --- ext/standard/argon2lib/argon2.c | 398 ------------ ext/standard/argon2lib/argon2.h | 372 ----------- ext/standard/argon2lib/blake2/blake2-impl.h | 143 ----- ext/standard/argon2lib/blake2/blake2.h | 74 --- ext/standard/argon2lib/blake2/blake2b.c | 372 ----------- .../argon2lib/blake2/blamka-round-opt.h | 163 ----- .../argon2lib/blake2/blamka-round-ref.h | 39 -- ext/standard/argon2lib/core.c | 607 ------------------ ext/standard/argon2lib/core.h | 219 ------- ext/standard/argon2lib/encoding.c | 426 ------------ ext/standard/argon2lib/encoding.h | 40 -- ext/standard/argon2lib/opt.c | 220 ------- ext/standard/argon2lib/opt.h | 52 -- ext/standard/argon2lib/ref.c | 228 ------- ext/standard/argon2lib/ref.h | 51 -- ext/standard/argon2lib/thread.c | 36 -- ext/standard/argon2lib/thread.h | 46 -- ext/standard/config.m4 | 37 +- ext/standard/config.w32 | 5 +- ext/standard/password.c | 36 +- ext/standard/php_password.h | 8 +- .../tests/password/password_get_info.phpt | 34 - .../password/password_get_info_argon2.phpt | 45 ++ .../tests/password/password_hash.phpt | 18 - .../tests/password/password_hash_argon2.phpt | 26 + .../tests/password/password_hash_error.phpt | 16 - .../password/password_hash_error_argon2.phpt | 20 + .../tests/password/password_needs_rehash.phpt | 7 - .../password_needs_rehash_argon2.phpt | 17 + .../tests/password/password_verify.phpt | 11 - .../password/password_verify_argon2.phpt | 24 + 31 files changed, 201 insertions(+), 3589 deletions(-) delete mode 100644 ext/standard/argon2lib/argon2.c delete mode 100644 ext/standard/argon2lib/argon2.h delete mode 100644 ext/standard/argon2lib/blake2/blake2-impl.h delete mode 100644 ext/standard/argon2lib/blake2/blake2.h delete mode 100644 ext/standard/argon2lib/blake2/blake2b.c delete mode 100644 ext/standard/argon2lib/blake2/blamka-round-opt.h delete mode 100644 ext/standard/argon2lib/blake2/blamka-round-ref.h delete mode 100644 ext/standard/argon2lib/core.c delete mode 100644 ext/standard/argon2lib/core.h delete mode 100644 ext/standard/argon2lib/encoding.c delete mode 100644 ext/standard/argon2lib/encoding.h delete mode 100644 ext/standard/argon2lib/opt.c delete mode 100644 ext/standard/argon2lib/opt.h delete mode 100644 ext/standard/argon2lib/ref.c delete mode 100644 ext/standard/argon2lib/ref.h delete mode 100644 ext/standard/argon2lib/thread.c delete mode 100644 ext/standard/argon2lib/thread.h create mode 100644 ext/standard/tests/password/password_get_info_argon2.phpt create mode 100644 ext/standard/tests/password/password_hash_argon2.phpt create mode 100644 ext/standard/tests/password/password_hash_error_argon2.phpt create mode 100644 ext/standard/tests/password/password_needs_rehash_argon2.phpt create mode 100644 ext/standard/tests/password/password_verify_argon2.phpt diff --git a/ext/standard/argon2lib/argon2.c b/ext/standard/argon2lib/argon2.c deleted file mode 100644 index 4f4f6d4249c..00000000000 --- a/ext/standard/argon2lib/argon2.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Argon2 source code package - * - * Written by Daniel Dinu and Dmitry Khovratovich, 2015 - * - * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with - * this software. If not, see - * . - */ - -#include -#include -#include - -#include "argon2.h" -#include "encoding.h" -#include "core.h" - - -int argon2_ctx(argon2_context *context, argon2_type type) { - /* 1. Validate all inputs */ - int result = validate_inputs(context); - uint32_t memory_blocks, segment_length; - argon2_instance_t instance; - - if (ARGON2_OK != result) { - return result; - } - - if (Argon2_d != type && Argon2_i != type) { - return ARGON2_INCORRECT_TYPE; - } - - /* 2. Align memory size */ - /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */ - memory_blocks = context->m_cost; - - if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) { - memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes; - } - - segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS); - /* Ensure that all segments have equal length */ - memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS); - - instance.version = context->version; - instance.memory = NULL; - instance.passes = context->t_cost; - instance.memory_blocks = memory_blocks; - instance.segment_length = segment_length; - instance.lane_length = segment_length * ARGON2_SYNC_POINTS; - instance.lanes = context->lanes; - instance.threads = context->threads; - instance.type = type; - - /* 3. Initialization: Hashing inputs, allocating memory, filling first - * blocks - */ - result = initialize(&instance, context); - - if (ARGON2_OK != result) { - return result; - } - - /* 4. Filling memory */ - result = fill_memory_blocks(&instance); - - if (ARGON2_OK != result) { - return result; - } - /* 5. Finalization */ - finalize(context, &instance); - - return ARGON2_OK; -} - -int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, const size_t saltlen, - void *hash, const size_t hashlen, char *encoded, - const size_t encodedlen, argon2_type type, - const uint32_t version){ - - argon2_context context; - int result; - uint8_t *out; - - if (hashlen > ARGON2_MAX_OUTLEN) { - return ARGON2_OUTPUT_TOO_LONG; - } - - if (hashlen < ARGON2_MIN_OUTLEN) { - return ARGON2_OUTPUT_TOO_SHORT; - } - - out = malloc(hashlen); - if (!out) { - return ARGON2_MEMORY_ALLOCATION_ERROR; - } - - context.out = (uint8_t *)out; - context.outlen = (uint32_t)hashlen; - context.pwd = CONST_CAST(uint8_t *)pwd; - context.pwdlen = (uint32_t)pwdlen; - context.salt = CONST_CAST(uint8_t *)salt; - context.saltlen = (uint32_t)saltlen; - 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; - - result = argon2_ctx(&context, type); - - if (result != ARGON2_OK) { - secure_wipe_memory(out, hashlen); - free(out); - return result; - } - - /* if raw hash requested, write it */ - if (hash) { - memcpy(hash, out, hashlen); - } - - /* if encoding requested, write it */ - if (encoded && encodedlen) { - if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) { - secure_wipe_memory(out, hashlen); /* wipe buffers if error */ - secure_wipe_memory(encoded, encodedlen); - free(out); - return ARGON2_ENCODING_FAIL; - } - } - secure_wipe_memory(out, hashlen); - free(out); - - return ARGON2_OK; -} - -int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, - const size_t saltlen, const size_t hashlen, - char *encoded, const size_t encodedlen) { - - return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, - NULL, hashlen, encoded, encodedlen, Argon2_i, - ARGON2_VERSION_NUMBER); -} - -int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, - const size_t saltlen, void *hash, const size_t hashlen) { - - return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, - hash, hashlen, NULL, 0, Argon2_i, ARGON2_VERSION_NUMBER); -} - -int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, - const size_t saltlen, const size_t hashlen, - char *encoded, const size_t encodedlen) { - - return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, - NULL, hashlen, encoded, encodedlen, Argon2_d, - ARGON2_VERSION_NUMBER); -} - -int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, - const size_t saltlen, void *hash, const size_t hashlen) { - - return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, - hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER); -} - -static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) { - size_t i; - uint8_t d = 0U; - - for (i = 0U; i < len; i++) { - d |= b1[i] ^ b2[i]; - } - return (int)((1 & ((d - 1) >> 8)) - 1); -} - -int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, - argon2_type type) { - - argon2_context ctx; - uint8_t *out; - int ret; - int decode_result; - uint32_t encoded_len; - size_t encoded_len_tmp; - - if(encoded == NULL) { - return ARGON2_DECODING_FAIL; - } - - encoded_len_tmp = strlen(encoded); - /* max values, to be updated in decode_string */ - if (UINT32_MAX < encoded_len_tmp) { - return ARGON2_DECODING_FAIL; - } - - encoded_len = (uint32_t)encoded_len_tmp; - ctx.adlen = encoded_len; - ctx.saltlen = encoded_len; - ctx.outlen = encoded_len; - ctx.allocate_cbk = NULL; - ctx.free_cbk = NULL; - ctx.secret = NULL; - ctx.secretlen = 0; - ctx.pwdlen = 0; - ctx.pwd = NULL; - ctx.ad = malloc(ctx.adlen); - ctx.salt = malloc(ctx.saltlen); - ctx.out = malloc(ctx.outlen); - if (!ctx.out || !ctx.salt || !ctx.ad) { - free(ctx.ad); - free(ctx.salt); - free(ctx.out); - return ARGON2_MEMORY_ALLOCATION_ERROR; - } - out = malloc(ctx.outlen); - if (!out) { - free(ctx.ad); - free(ctx.salt); - free(ctx.out); - return ARGON2_MEMORY_ALLOCATION_ERROR; - } - decode_result = decode_string(&ctx, encoded, type); - if (decode_result != ARGON2_OK) { - free(ctx.ad); - free(ctx.salt); - free(ctx.out); - free(out); - return decode_result; - } - - ret = argon2_hash(ctx.t_cost, ctx.m_cost, ctx.threads, pwd, pwdlen, - ctx.salt, ctx.saltlen, out, ctx.outlen, NULL, 0, type, - ctx.version); - - free(ctx.ad); - free(ctx.salt); - - if (ret == ARGON2_OK && argon2_compare(out, ctx.out, ctx.outlen)) { - ret = ARGON2_VERIFY_MISMATCH; - } - free(out); - free(ctx.out); - - return ret; -} - -int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) { - - return argon2_verify(encoded, pwd, pwdlen, Argon2_i); -} - -int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) { - - return argon2_verify(encoded, pwd, pwdlen, Argon2_d); -} - -int argon2d_ctx(argon2_context *context) { - return argon2_ctx(context, Argon2_d); -} - -int argon2i_ctx(argon2_context *context) { - return argon2_ctx(context, Argon2_i); -} - -int argon2_verify_ctx(argon2_context *context, const char *hash, - argon2_type type) { - int result; - if (0 == context->outlen || NULL == hash) { - return ARGON2_OUT_PTR_MISMATCH; - } - - result = argon2_ctx(context, type); - - if (ARGON2_OK != result) { - return result; - } - - return 0 == memcmp(hash, context->out, context->outlen); -} - -int argon2d_verify_ctx(argon2_context *context, const char *hash) { - return argon2_verify_ctx(context, hash, Argon2_d); -} - -int argon2i_verify_ctx(argon2_context *context, const char *hash) { - return argon2_verify_ctx(context, hash, Argon2_i); -} - -const char *argon2_error_message(int error_code) { - switch (error_code) { - case ARGON2_OK: - return "OK"; - case ARGON2_OUTPUT_PTR_NULL: - return "Output pointer is NULL"; - case ARGON2_OUTPUT_TOO_SHORT: - return "Output is too short"; - case ARGON2_OUTPUT_TOO_LONG: - return "Output is too long"; - case ARGON2_PWD_TOO_SHORT: - return "Password is too short"; - case ARGON2_PWD_TOO_LONG: - return "Password is too long"; - case ARGON2_SALT_TOO_SHORT: - return "Salt is too short"; - case ARGON2_SALT_TOO_LONG: - return "Salt is too long"; - case ARGON2_AD_TOO_SHORT: - return "Associated data is too short"; - case ARGON2_AD_TOO_LONG: - return "Associated data is too long"; - case ARGON2_SECRET_TOO_SHORT: - return "Secret is too short"; - case ARGON2_SECRET_TOO_LONG: - return "Secret is too long"; - case ARGON2_TIME_TOO_SMALL: - return "Time cost is too small"; - case ARGON2_TIME_TOO_LARGE: - return "Time cost is too large"; - case ARGON2_MEMORY_TOO_LITTLE: - return "Memory cost is too small"; - case ARGON2_MEMORY_TOO_MUCH: - return "Memory cost is too large"; - case ARGON2_LANES_TOO_FEW: - return "Too few lanes"; - case ARGON2_LANES_TOO_MANY: - return "Too many lanes"; - case ARGON2_PWD_PTR_MISMATCH: - return "Password pointer is NULL, but password length is not 0"; - case ARGON2_SALT_PTR_MISMATCH: - return "Salt pointer is NULL, but salt length is not 0"; - case ARGON2_SECRET_PTR_MISMATCH: - return "Secret pointer is NULL, but secret length is not 0"; - case ARGON2_AD_PTR_MISMATCH: - return "Associated data pointer is NULL, but ad length is not 0"; - case ARGON2_MEMORY_ALLOCATION_ERROR: - return "Memory allocation error"; - case ARGON2_FREE_MEMORY_CBK_NULL: - return "The free memory callback is NULL"; - case ARGON2_ALLOCATE_MEMORY_CBK_NULL: - return "The allocate memory callback is NULL"; - case ARGON2_INCORRECT_PARAMETER: - return "Argon2_Context context is NULL"; - case ARGON2_INCORRECT_TYPE: - return "There is no such version of Argon2"; - case ARGON2_OUT_PTR_MISMATCH: - return "Output pointer mismatch"; - case ARGON2_THREADS_TOO_FEW: - return "Not enough threads"; - case ARGON2_THREADS_TOO_MANY: - return "Too many threads"; - case ARGON2_MISSING_ARGS: - return "Missing arguments"; - case ARGON2_ENCODING_FAIL: - return "Encoding failed"; - case ARGON2_DECODING_FAIL: - return "Decoding failed"; - case ARGON2_THREAD_FAIL: - return "Threading failure"; - case ARGON2_DECODING_LENGTH_FAIL: - return "Some of encoded parameters are too long or too short"; - case ARGON2_VERIFY_MISMATCH: - return "The password does not match the supplied hash"; - default: - return "Unknown error code"; - } -} - -size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism, - uint32_t saltlen, uint32_t hashlen) { - return strlen("$argon2x$v=$m=,t=,p=$$") + numlen(t_cost) + numlen(m_cost) - + numlen(parallelism) + b64len(saltlen) + b64len(hashlen) - + numlen(ARGON2_VERSION_NUMBER); -} diff --git a/ext/standard/argon2lib/argon2.h b/ext/standard/argon2lib/argon2.h deleted file mode 100644 index d4c7d5b499d..00000000000 --- a/ext/standard/argon2lib/argon2.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Argon2 source code package - * - * Written by Daniel Dinu and Dmitry Khovratovich, 2015 - * - * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. - * - * You should have received a copy of the CC0 Public Domain Dedication - * along with this software. If not, see - * . - */ - -#ifndef ARGON2_H -#define ARGON2_H - -#include -#include -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -/* Symbols visibility control */ -#ifdef A2_VISCTL -#define ARGON2_PUBLIC __attribute__((visibility("default"))) -#else -#define ARGON2_PUBLIC -#endif - -/* - * Argon2 input parameter restrictions - */ - -/* Minimum and maximum number of lanes (degree of parallelism) */ -#define ARGON2_MIN_LANES UINT32_C(1) -#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF) - -/* Minimum and maximum number of threads */ -#define ARGON2_MIN_THREADS UINT32_C(1) -#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF) - -/* Number of synchronization points between lanes per pass */ -#define ARGON2_SYNC_POINTS UINT32_C(4) - -/* Minimum and maximum digest size in bytes */ -#define ARGON2_MIN_OUTLEN UINT32_C(4) -#define ARGON2_MAX_OUTLEN UINT32_C(0xFFFFFFFF) - -/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */ -#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */ - -#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b)) -/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */ -#define ARGON2_MAX_MEMORY_BITS \ - ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1)) -#define ARGON2_MAX_MEMORY \ - ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS) - -/* Minimum and maximum number of passes */ -#define ARGON2_MIN_TIME UINT32_C(1) -#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF) - -/* Minimum and maximum password length in bytes */ -#define ARGON2_MIN_PWD_LENGTH UINT32_C(0) -#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF) - -/* Minimum and maximum associated data length in bytes */ -#define ARGON2_MIN_AD_LENGTH UINT32_C(0) -#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF) - -/* Minimum and maximum salt length in bytes */ -#define ARGON2_MIN_SALT_LENGTH UINT32_C(8) -#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF) - -/* Minimum and maximum key length in bytes */ -#define ARGON2_MIN_SECRET UINT32_C(0) -#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) - -#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) -#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) -#define ARGON2_FLAG_CLEAR_MEMORY (UINT32_C(1) << 2) -#define ARGON2_DEFAULT_FLAGS (ARGON2_FLAG_CLEAR_MEMORY) - -/* Error codes */ -typedef enum Argon2_ErrorCodes { - ARGON2_OK = 0, - - ARGON2_OUTPUT_PTR_NULL = -1, - - ARGON2_OUTPUT_TOO_SHORT = -2, - ARGON2_OUTPUT_TOO_LONG = -3, - - ARGON2_PWD_TOO_SHORT = -4, - ARGON2_PWD_TOO_LONG = -5, - - ARGON2_SALT_TOO_SHORT = -6, - ARGON2_SALT_TOO_LONG = -7, - - ARGON2_AD_TOO_SHORT = -8, - ARGON2_AD_TOO_LONG = -9, - - ARGON2_SECRET_TOO_SHORT = -10, - ARGON2_SECRET_TOO_LONG = -11, - - ARGON2_TIME_TOO_SMALL = -12, - ARGON2_TIME_TOO_LARGE = -13, - - ARGON2_MEMORY_TOO_LITTLE = -14, - ARGON2_MEMORY_TOO_MUCH = -15, - - ARGON2_LANES_TOO_FEW = -16, - ARGON2_LANES_TOO_MANY = -17, - - ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */ - ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */ - ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */ - ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */ - - ARGON2_MEMORY_ALLOCATION_ERROR = -22, - - ARGON2_FREE_MEMORY_CBK_NULL = -23, - ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24, - - ARGON2_INCORRECT_PARAMETER = -25, - ARGON2_INCORRECT_TYPE = -26, - - ARGON2_OUT_PTR_MISMATCH = -27, - - ARGON2_THREADS_TOO_FEW = -28, - ARGON2_THREADS_TOO_MANY = -29, - - ARGON2_MISSING_ARGS = -30, - - ARGON2_ENCODING_FAIL = -31, - - ARGON2_DECODING_FAIL = -32, - - ARGON2_THREAD_FAIL = -33, - - ARGON2_DECODING_LENGTH_FAIL = -34, - - ARGON2_VERIFY_MISMATCH = -35 -} argon2_error_codes; - -/* Memory allocator types --- for external allocation */ -typedef int (*allocate_fptr)(uint8_t **memory, size_t bytes_to_allocate); -typedef void (*deallocate_fptr)(uint8_t *memory, size_t bytes_to_allocate); - -/* Argon2 external data structures */ - -/* - ***** - * Context: structure to hold Argon2 inputs: - * output array and its length, - * password and its length, - * salt and its length, - * secret and its length, - * associated data and its length, - * number of passes, amount of used memory (in KBytes, can be rounded up a bit) - * number of parallel threads that will be run. - * All the parameters above affect the output hash value. - * Additionally, two function pointers can be provided to allocate and - * deallocate the memory (if NULL, memory will be allocated internally). - * Also, three flags indicate whether to erase password, secret as soon as they - * are pre-hashed (and thus not needed anymore), and the entire memory - ***** - * Simplest situation: you have output array out[8], password is stored in - * pwd[32], salt is stored in salt[16], you do not have keys nor associated - * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with - * 4 parallel lanes. - * You want to erase the password, but you're OK with last pass not being - * erased. You want to use the default memory allocator. - * Then you initialize: - Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false) - */ -typedef struct Argon2_Context { - uint8_t *out; /* output array */ - uint32_t outlen; /* digest length */ - - uint8_t *pwd; /* password array */ - uint32_t pwdlen; /* password length */ - - uint8_t *salt; /* salt array */ - uint32_t saltlen; /* salt length */ - - uint8_t *secret; /* key array */ - uint32_t secretlen; /* key length */ - - uint8_t *ad; /* associated data array */ - uint32_t adlen; /* associated data length */ - - uint32_t t_cost; /* number of passes */ - uint32_t m_cost; /* amount of memory requested (KB) */ - uint32_t lanes; /* number of lanes */ - uint32_t threads; /* maximum number of threads */ - - uint32_t version; /* version number */ - - allocate_fptr allocate_cbk; /* pointer to memory allocator */ - deallocate_fptr free_cbk; /* pointer to memory deallocator */ - - uint32_t flags; /* array of bool options */ -} argon2_context; - -/* Argon2 primitive type */ -typedef enum Argon2_type { Argon2_d = 0, Argon2_i = 1 } argon2_type; - -/* Version of the algorithm */ -typedef enum Argon2_version { - ARGON2_VERSION_10 = 0x10, - ARGON2_VERSION_13 = 0x13, - ARGON2_VERSION_NUMBER = ARGON2_VERSION_13 -} argon2_version; - -/* - * Function that performs memory-hard hashing with certain degree of parallelism - * @param context Pointer to the Argon2 internal structure - * @return Error code if smth is wrong, ARGON2_OK otherwise - */ -ARGON2_PUBLIC int argon2_ctx(argon2_context *context, argon2_type type); - -/** - * Hashes a password with Argon2i, producing an encoded hash - * @param t_cost Number of iterations - * @param m_cost Sets memory usage to m_cost kibibytes - * @param parallelism Number of threads and compute lanes - * @param pwd Pointer to password - * @param pwdlen Password size in bytes - * @param salt Pointer to salt - * @param saltlen Salt size in bytes - * @param hashlen Desired length of the hash in bytes - * @param encoded Buffer where to write the encoded hash - * @param encodedlen Size of the buffer (thus max size of the encoded hash) - * @pre Different parallelism levels will give different results - * @pre Returns ARGON2_OK if successful - */ -ARGON2_PUBLIC int argon2i_hash_encoded(const uint32_t t_cost, - const uint32_t m_cost, - const uint32_t parallelism, - const void *pwd, const size_t pwdlen, - const void *salt, const size_t saltlen, - const size_t hashlen, char *encoded, - const size_t encodedlen); - -/** - * Hashes a password with Argon2i, producing a raw hash by allocating memory at - * @hash - * @param t_cost Number of iterations - * @param m_cost Sets memory usage to m_cost kibibytes - * @param parallelism Number of threads and compute lanes - * @param pwd Pointer to password - * @param pwdlen Password size in bytes - * @param salt Pointer to salt - * @param saltlen Salt size in bytes - * @param hash Buffer where to write the raw hash - updated by the function - * @param hashlen Desired length of the hash in bytes - * @pre Different parallelism levels will give different results - * @pre Returns ARGON2_OK if successful - */ -ARGON2_PUBLIC int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, - const size_t saltlen, void *hash, - const size_t hashlen); - -ARGON2_PUBLIC int argon2d_hash_encoded(const uint32_t t_cost, - const uint32_t m_cost, - const uint32_t parallelism, - const void *pwd, const size_t pwdlen, - const void *salt, const size_t saltlen, - const size_t hashlen, char *encoded, - const size_t encodedlen); - -ARGON2_PUBLIC int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, - const size_t saltlen, void *hash, - const size_t hashlen); - -/* generic function underlying the above ones */ -ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, - const size_t saltlen, void *hash, - const size_t hashlen, char *encoded, - const size_t encodedlen, argon2_type type, - const uint32_t version); - -/** - * Verifies a password against an encoded string - * Encoded string is restricted as in validate_inputs() - * @param encoded String encoding parameters, salt, hash - * @param pwd Pointer to password - * @pre Returns ARGON2_OK if successful - */ -ARGON2_PUBLIC int argon2i_verify(const char *encoded, const void *pwd, - const size_t pwdlen); - -ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd, - const size_t pwdlen); - -/* generic function underlying the above ones */ -ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd, - const size_t pwdlen, argon2_type type); - -/** - * Argon2d: Version of Argon2 that picks memory blocks depending - * on the password and salt. Only for side-channel-free - * environment!! - ***** - * @param context Pointer to current Argon2 context - * @return Zero if successful, a non zero error code otherwise - */ -ARGON2_PUBLIC int argon2d_ctx(argon2_context *context); - -/** - * Argon2i: Version of Argon2 that picks memory blocks - * independent on the password and salt. Good for side-channels, - * but worse w.r.t. tradeoff attacks if only one pass is used. - ***** - * @param context Pointer to current Argon2 context - * @return Zero if successful, a non zero error code otherwise - */ -ARGON2_PUBLIC int argon2i_ctx(argon2_context *context); - -/** - * Verify if a given password is correct for Argon2d hashing - * @param context Pointer to current Argon2 context - * @param hash The password hash to verify. The length of the hash is - * specified by the context outlen member - * @return Zero if successful, a non zero error code otherwise - */ -ARGON2_PUBLIC int argon2d_verify_ctx(argon2_context *context, const char *hash); - -/** - * Verify if a given password is correct for Argon2i hashing - * @param context Pointer to current Argon2 context - * @param hash The password hash to verify. The length of the hash is - * specified by the context outlen member - * @return Zero if successful, a non zero error code otherwise - */ -ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash); - -/* generic function underlying the above ones */ -ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash, - argon2_type type); - -/** - * Get the associated error message for given error code - * @return The error message associated with the given error code - */ -ARGON2_PUBLIC const char *argon2_error_message(int error_code); - -/** - * Returns the encoded hash length for the given input parameters - * @param t_cost Number of iterations - * @param m_cost Memory usage in kibibytes - * @param parallelism Number of threads; used to compute lanes - * @param saltlen Salt size in bytes - * @param hashlen Hash size in bytes - * @return The encoded hash length in bytes - */ -ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, - uint32_t parallelism, uint32_t saltlen, - uint32_t hashlen); - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/ext/standard/argon2lib/blake2/blake2-impl.h b/ext/standard/argon2lib/blake2/blake2-impl.h deleted file mode 100644 index 115a192db6f..00000000000 --- a/ext/standard/argon2lib/blake2/blake2-impl.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef PORTABLE_BLAKE2_IMPL_H -#define PORTABLE_BLAKE2_IMPL_H - -#include -#include - -#if defined(_MSC_VER) -#define BLAKE2_INLINE __inline -#elif defined(__GNUC__) || defined(__clang__) -#define BLAKE2_INLINE __inline__ -#else -#define BLAKE2_INLINE -#endif - -/* Argon2 Team - Begin Code */ -/* - Not an exhaustive list, but should cover the majority of modern platforms - Additionally, the code will always be correct---this is only a performance - tweak. -*/ -#if (defined(__BYTE_ORDER__) && \ - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ - defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ - defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \ - defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \ - defined(_M_ARM) -#define NATIVE_LITTLE_ENDIAN -#endif -/* Argon2 Team - End Code */ - -static BLAKE2_INLINE uint32_t load32(const void *src) { -#if defined(NATIVE_LITTLE_ENDIAN) - uint32_t w; - memcpy(&w, src, sizeof w); - return w; -#else - const uint8_t *p = (const uint8_t *)src; - uint32_t w = *p++; - w |= (uint32_t)(*p++) << 8; - w |= (uint32_t)(*p++) << 16; - w |= (uint32_t)(*p++) << 24; - return w; -#endif -} - -static BLAKE2_INLINE uint64_t load64(const void *src) { -#if defined(NATIVE_LITTLE_ENDIAN) - uint64_t w; - memcpy(&w, src, sizeof w); - return w; -#else - const uint8_t *p = (const uint8_t *)src; - uint64_t w = *p++; - w |= (uint64_t)(*p++) << 8; - w |= (uint64_t)(*p++) << 16; - w |= (uint64_t)(*p++) << 24; - w |= (uint64_t)(*p++) << 32; - w |= (uint64_t)(*p++) << 40; - w |= (uint64_t)(*p++) << 48; - w |= (uint64_t)(*p++) << 56; - return w; -#endif -} - -static BLAKE2_INLINE void store32(void *dst, uint32_t w) { -#if defined(NATIVE_LITTLE_ENDIAN) - memcpy(dst, &w, sizeof w); -#else - uint8_t *p = (uint8_t *)dst; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; -#endif -} - -static BLAKE2_INLINE void store64(void *dst, uint64_t w) { -#if defined(NATIVE_LITTLE_ENDIAN) - memcpy(dst, &w, sizeof w); -#else - uint8_t *p = (uint8_t *)dst; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; -#endif -} - -static BLAKE2_INLINE uint64_t load48(const void *src) { - const uint8_t *p = (const uint8_t *)src; - uint64_t w = *p++; - w |= (uint64_t)(*p++) << 8; - w |= (uint64_t)(*p++) << 16; - w |= (uint64_t)(*p++) << 24; - w |= (uint64_t)(*p++) << 32; - w |= (uint64_t)(*p++) << 40; - return w; -} - -static BLAKE2_INLINE void store48(void *dst, uint64_t w) { - uint8_t *p = (uint8_t *)dst; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; - w >>= 8; - *p++ = (uint8_t)w; -} - -static BLAKE2_INLINE uint32_t rotr32(const uint32_t w, const unsigned c) { - return (w >> c) | (w << (32 - c)); -} - -static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) { - return (w >> c) | (w << (64 - c)); -} - -/* prevents compiler optimizing out memset() */ -static BLAKE2_INLINE void burn(void *v, size_t n) { - static void *(*const volatile memset_v)(void *, int, size_t) = &memset; - memset_v(v, 0, n); -} - -#endif diff --git a/ext/standard/argon2lib/blake2/blake2.h b/ext/standard/argon2lib/blake2/blake2.h deleted file mode 100644 index d28d9a7900b..00000000000 --- a/ext/standard/argon2lib/blake2/blake2.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef PORTABLE_BLAKE2_H -#define PORTABLE_BLAKE2_H - -#include -#include -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -enum blake2b_constant { - BLAKE2B_BLOCKBYTES = 128, - BLAKE2B_OUTBYTES = 64, - BLAKE2B_KEYBYTES = 64, - BLAKE2B_SALTBYTES = 16, - BLAKE2B_PERSONALBYTES = 16 -}; - -#pragma pack(push, 1) -typedef struct __blake2b_param { - uint8_t digest_length; /* 1 */ - uint8_t key_length; /* 2 */ - uint8_t fanout; /* 3 */ - uint8_t depth; /* 4 */ - uint32_t leaf_length; /* 8 */ - uint64_t node_offset; /* 16 */ - uint8_t node_depth; /* 17 */ - uint8_t inner_length; /* 18 */ - uint8_t reserved[14]; /* 32 */ - uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ - uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ -} blake2b_param; -#pragma pack(pop) - -typedef struct __blake2b_state { - uint64_t h[8]; - uint64_t t[2]; - uint64_t f[2]; - uint8_t buf[BLAKE2B_BLOCKBYTES]; - unsigned buflen; - unsigned outlen; - uint8_t last_node; -} blake2b_state; - -/* Ensure param structs have not been wrongly padded */ -/* Poor man's static_assert */ -enum { - blake2_size_check_0 = 1 / !!(CHAR_BIT == 8), - blake2_size_check_2 = - 1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT) -}; - -/* Streaming API */ -int blake2b_init(blake2b_state *S, size_t outlen); -int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, - size_t keylen); -int blake2b_init_param(blake2b_state *S, const blake2b_param *P); -int blake2b_update(blake2b_state *S, const void *in, size_t inlen); -int blake2b_final(blake2b_state *S, void *out, size_t outlen); - -/* Simple API */ -int blake2b(void *out, size_t outlen, const void *in, size_t inlen, - const void *key, size_t keylen); - -/* Argon2 Team - Begin Code */ -int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); -/* Argon2 Team - End Code */ - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/ext/standard/argon2lib/blake2/blake2b.c b/ext/standard/argon2lib/blake2/blake2b.c deleted file mode 100644 index 28dec868d97..00000000000 --- a/ext/standard/argon2lib/blake2/blake2b.c +++ /dev/null @@ -1,372 +0,0 @@ -#include -#include -#include - -#include "blake2.h" -#include "blake2-impl.h" - -static const uint64_t blake2b_IV[8] = { - UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), - UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), - UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), - UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179)}; - -static const unsigned int blake2b_sigma[12][16] = { - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, - {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, - {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, - {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, - {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, - {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, - {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, - {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, - {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, -}; - -static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) { - S->f[1] = (uint64_t)-1; -} - -static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) { - if (S->last_node) { - blake2b_set_lastnode(S); - } - S->f[0] = (uint64_t)-1; -} - -static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S, - uint64_t inc) { - S->t[0] += inc; - S->t[1] += (S->t[0] < inc); -} - -static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) { - burn(S, sizeof(*S)); /* wipe */ - blake2b_set_lastblock(S); /* invalidate for further use */ -} - -static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) { - memset(S, 0, sizeof(*S)); - memcpy(S->h, blake2b_IV, sizeof(S->h)); -} - -int blake2b_init_param(blake2b_state *S, const blake2b_param *P) { - const unsigned char *p = (const unsigned char *)P; - unsigned int i; - - if (NULL == P || NULL == S) { - return -1; - } - - blake2b_init0(S); - /* IV XOR Parameter Block */ - for (i = 0; i < 8; ++i) { - S->h[i] ^= load64(&p[i * sizeof(S->h[i])]); - } - S->outlen = P->digest_length; - return 0; -} - -/* Sequential blake2b initialization */ -int blake2b_init(blake2b_state *S, size_t outlen) { - blake2b_param P; - - if (S == NULL) { - return -1; - } - - if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { - blake2b_invalidate_state(S); - return -1; - } - - /* Setup Parameter Block for unkeyed BLAKE2 */ - P.digest_length = (uint8_t)outlen; - P.key_length = 0; - P.fanout = 1; - P.depth = 1; - P.leaf_length = 0; - P.node_offset = 0; - P.node_depth = 0; - P.inner_length = 0; - memset(P.reserved, 0, sizeof(P.reserved)); - memset(P.salt, 0, sizeof(P.salt)); - memset(P.personal, 0, sizeof(P.personal)); - - return blake2b_init_param(S, &P); -} - -int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, - size_t keylen) { - blake2b_param P; - - if (S == NULL) { - return -1; - } - - if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { - blake2b_invalidate_state(S); - return -1; - } - - if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) { - blake2b_invalidate_state(S); - return -1; - } - - /* Setup Parameter Block for keyed BLAKE2 */ - P.digest_length = (uint8_t)outlen; - P.key_length = (uint8_t)keylen; - P.fanout = 1; - P.depth = 1; - P.leaf_length = 0; - P.node_offset = 0; - P.node_depth = 0; - P.inner_length = 0; - memset(P.reserved, 0, sizeof(P.reserved)); - memset(P.salt, 0, sizeof(P.salt)); - memset(P.personal, 0, sizeof(P.personal)); - - if (blake2b_init_param(S, &P) < 0) { - blake2b_invalidate_state(S); - return -1; - } - - { - uint8_t block[BLAKE2B_BLOCKBYTES]; - memset(block, 0, BLAKE2B_BLOCKBYTES); - memcpy(block, key, keylen); - blake2b_update(S, block, BLAKE2B_BLOCKBYTES); - burn(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ - } - return 0; -} - -static void blake2b_compress(blake2b_state *S, const uint8_t *block) { - uint64_t m[16]; - uint64_t v[16]; - unsigned int i, r; - - for (i = 0; i < 16; ++i) { - m[i] = load64(block + i * sizeof(m[i])); - } - - for (i = 0; i < 8; ++i) { - v[i] = S->h[i]; - } - - v[8] = blake2b_IV[0]; - v[9] = blake2b_IV[1]; - v[10] = blake2b_IV[2]; - v[11] = blake2b_IV[3]; - v[12] = blake2b_IV[4] ^ S->t[0]; - v[13] = blake2b_IV[5] ^ S->t[1]; - v[14] = blake2b_IV[6] ^ S->f[0]; - v[15] = blake2b_IV[7] ^ S->f[1]; - -#define G(r, i, a, b, c, d) \ - do { \ - a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ - d = rotr64(d ^ a, 32); \ - c = c + d; \ - b = rotr64(b ^ c, 24); \ - a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ - d = rotr64(d ^ a, 16); \ - c = c + d; \ - b = rotr64(b ^ c, 63); \ - } while ((void)0, 0) - -#define ROUND(r) \ - do { \ - G(r, 0, v[0], v[4], v[8], v[12]); \ - G(r, 1, v[1], v[5], v[9], v[13]); \ - G(r, 2, v[2], v[6], v[10], v[14]); \ - G(r, 3, v[3], v[7], v[11], v[15]); \ - G(r, 4, v[0], v[5], v[10], v[15]); \ - G(r, 5, v[1], v[6], v[11], v[12]); \ - G(r, 6, v[2], v[7], v[8], v[13]); \ - G(r, 7, v[3], v[4], v[9], v[14]); \ - } while ((void)0, 0) - - for (r = 0; r < 12; ++r) { - ROUND(r); - } - - for (i = 0; i < 8; ++i) { - S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; - } - -#undef G -#undef ROUND -} - -int blake2b_update(blake2b_state *S, const void *in, size_t inlen) { - const uint8_t *pin = (const uint8_t *)in; - - if (inlen == 0) { - return 0; - } - - /* Sanity check */ - if (S == NULL || in == NULL) { - return -1; - } - - /* Is this a reused state? */ - if (S->f[0] != 0) { - return -1; - } - - if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) { - /* Complete current block */ - size_t left = S->buflen; - size_t fill = BLAKE2B_BLOCKBYTES - left; - memcpy(&S->buf[left], pin, fill); - blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); - blake2b_compress(S, S->buf); - S->buflen = 0; - inlen -= fill; - pin += fill; - /* Avoid buffer copies when possible */ - while (inlen > BLAKE2B_BLOCKBYTES) { - blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); - blake2b_compress(S, pin); - inlen -= BLAKE2B_BLOCKBYTES; - pin += BLAKE2B_BLOCKBYTES; - } - } - memcpy(&S->buf[S->buflen], pin, inlen); - S->buflen += (unsigned int)inlen; - return 0; -} - -int blake2b_final(blake2b_state *S, void *out, size_t outlen) { - uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; - unsigned int i; - - /* Sanity checks */ - if (S == NULL || out == NULL || outlen < S->outlen) { - return -1; - } - - /* Is this a reused state? */ - if (S->f[0] != 0) { - return -1; - } - - blake2b_increment_counter(S, S->buflen); - blake2b_set_lastblock(S); - memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ - blake2b_compress(S, S->buf); - - for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ - store64(buffer + sizeof(S->h[i]) * i, S->h[i]); - } - - memcpy(out, buffer, S->outlen); - burn(buffer, sizeof(buffer)); - burn(S->buf, sizeof(S->buf)); - burn(S->h, sizeof(S->h)); - return 0; -} - -int blake2b(void *out, size_t outlen, const void *in, size_t inlen, - const void *key, size_t keylen) { - blake2b_state S; - int ret = -1; - - /* Verify parameters */ - if (NULL == in && inlen > 0) { - goto fail; - } - - if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) { - goto fail; - } - - if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) { - goto fail; - } - - if (keylen > 0) { - if (blake2b_init_key(&S, outlen, key, keylen) < 0) { - goto fail; - } - } else { - if (blake2b_init(&S, outlen) < 0) { - goto fail; - } - } - - if (blake2b_update(&S, in, inlen) < 0) { - goto fail; - } - ret = blake2b_final(&S, out, outlen); - -fail: - burn(&S, sizeof(S)); - return ret; -} - -/* Argon2 Team - Begin Code */ -int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) { - uint8_t *out = (uint8_t *)pout; - blake2b_state blake_state; - uint8_t outlen_bytes[sizeof(uint32_t)] = {0}; - int ret = -1; - - if (outlen > UINT32_MAX) { - goto fail; - } - - /* Ensure little-endian byte order! */ - store32(outlen_bytes, (uint32_t)outlen); - -#define TRY(statement) \ - do { \ - ret = statement; \ - if (ret < 0) { \ - goto fail; \ - } \ - } while ((void)0, 0) - - if (outlen <= BLAKE2B_OUTBYTES) { - TRY(blake2b_init(&blake_state, outlen)); - TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); - TRY(blake2b_update(&blake_state, in, inlen)); - TRY(blake2b_final(&blake_state, out, outlen)); - } else { - uint32_t toproduce; - uint8_t out_buffer[BLAKE2B_OUTBYTES]; - uint8_t in_buffer[BLAKE2B_OUTBYTES]; - TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES)); - TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); - TRY(blake2b_update(&blake_state, in, inlen)); - TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES)); - memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); - out += BLAKE2B_OUTBYTES / 2; - toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2; - - while (toproduce > BLAKE2B_OUTBYTES) { - memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); - TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, - BLAKE2B_OUTBYTES, NULL, 0)); - memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); - out += BLAKE2B_OUTBYTES / 2; - toproduce -= BLAKE2B_OUTBYTES / 2; - } - - memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); - TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, - 0)); - memcpy(out, out_buffer, toproduce); - } -fail: - burn(&blake_state, sizeof(blake_state)); - return ret; -#undef TRY -} -/* Argon2 Team - End Code */ diff --git a/ext/standard/argon2lib/blake2/blamka-round-opt.h b/ext/standard/argon2lib/blake2/blamka-round-opt.h deleted file mode 100644 index 44845a54516..00000000000 --- a/ext/standard/argon2lib/blake2/blamka-round-opt.h +++ /dev/null @@ -1,163 +0,0 @@ -#ifndef BLAKE_ROUND_MKA_OPT_H -#define BLAKE_ROUND_MKA_OPT_H - -#include "blake2-impl.h" - -#include -#if defined(__SSSE3__) -#include /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */ -#endif - -#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__)) -#include -#endif - -#if !defined(__XOP__) -#if defined(__SSSE3__) -#define r16 \ - (_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9)) -#define r24 \ - (_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10)) -#define _mm_roti_epi64(x, c) \ - (-(c) == 32) \ - ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \ - : (-(c) == 24) \ - ? _mm_shuffle_epi8((x), r24) \ - : (-(c) == 16) \ - ? _mm_shuffle_epi8((x), r16) \ - : (-(c) == 63) \ - ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ - _mm_add_epi64((x), (x))) \ - : _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ - _mm_slli_epi64((x), 64 - (-(c)))) -#else /* defined(__SSE2__) */ -#define _mm_roti_epi64(r, c) \ - _mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c)))) -#endif -#else -#endif - -static BLAKE2_INLINE __m128i fBlaMka(__m128i x, __m128i y) { - const __m128i z = _mm_mul_epu32(x, y); - return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z)); -} - -#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ - do { \ - A0 = fBlaMka(A0, B0); \ - A1 = fBlaMka(A1, B1); \ - \ - D0 = _mm_xor_si128(D0, A0); \ - D1 = _mm_xor_si128(D1, A1); \ - \ - D0 = _mm_roti_epi64(D0, -32); \ - D1 = _mm_roti_epi64(D1, -32); \ - \ - C0 = fBlaMka(C0, D0); \ - C1 = fBlaMka(C1, D1); \ - \ - B0 = _mm_xor_si128(B0, C0); \ - B1 = _mm_xor_si128(B1, C1); \ - \ - B0 = _mm_roti_epi64(B0, -24); \ - B1 = _mm_roti_epi64(B1, -24); \ - } while ((void)0, 0) - -#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ - do { \ - A0 = fBlaMka(A0, B0); \ - A1 = fBlaMka(A1, B1); \ - \ - D0 = _mm_xor_si128(D0, A0); \ - D1 = _mm_xor_si128(D1, A1); \ - \ - D0 = _mm_roti_epi64(D0, -16); \ - D1 = _mm_roti_epi64(D1, -16); \ - \ - C0 = fBlaMka(C0, D0); \ - C1 = fBlaMka(C1, D1); \ - \ - B0 = _mm_xor_si128(B0, C0); \ - B1 = _mm_xor_si128(B1, C1); \ - \ - B0 = _mm_roti_epi64(B0, -63); \ - B1 = _mm_roti_epi64(B1, -63); \ - } while ((void)0, 0) - -#if defined(__SSSE3__) -#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ - do { \ - __m128i t0 = _mm_alignr_epi8(B1, B0, 8); \ - __m128i t1 = _mm_alignr_epi8(B0, B1, 8); \ - B0 = t0; \ - B1 = t1; \ - \ - t0 = C0; \ - C0 = C1; \ - C1 = t0; \ - \ - t0 = _mm_alignr_epi8(D1, D0, 8); \ - t1 = _mm_alignr_epi8(D0, D1, 8); \ - D0 = t1; \ - D1 = t0; \ - } while ((void)0, 0) - -#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ - do { \ - __m128i t0 = _mm_alignr_epi8(B0, B1, 8); \ - __m128i t1 = _mm_alignr_epi8(B1, B0, 8); \ - B0 = t0; \ - B1 = t1; \ - \ - t0 = C0; \ - C0 = C1; \ - C1 = t0; \ - \ - t0 = _mm_alignr_epi8(D0, D1, 8); \ - t1 = _mm_alignr_epi8(D1, D0, 8); \ - D0 = t1; \ - D1 = t0; \ - } while ((void)0, 0) -#else /* SSE2 */ -#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ - do { \ - __m128i t0 = D0; \ - __m128i t1 = B0; \ - D0 = C0; \ - C0 = C1; \ - C1 = D0; \ - D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0)); \ - D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1)); \ - B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1)); \ - B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1)); \ - } while ((void)0, 0) - -#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ - do { \ - __m128i t0, t1; \ - t0 = C0; \ - C0 = C1; \ - C1 = t0; \ - t0 = B0; \ - t1 = D0; \ - B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0)); \ - B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1)); \ - D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1)); \ - D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1)); \ - } while ((void)0, 0) -#endif - -#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \ - do { \ - G1(A0, B0, C0, D0, A1, B1, C1, D1); \ - G2(A0, B0, C0, D0, A1, B1, C1, D1); \ - \ - DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ - \ - G1(A0, B0, C0, D0, A1, B1, C1, D1); \ - G2(A0, B0, C0, D0, A1, B1, C1, D1); \ - \ - UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ - } while ((void)0, 0) - -#endif diff --git a/ext/standard/argon2lib/blake2/blamka-round-ref.h b/ext/standard/argon2lib/blake2/blamka-round-ref.h deleted file mode 100644 index f497e10c2fe..00000000000 --- a/ext/standard/argon2lib/blake2/blamka-round-ref.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef BLAKE_ROUND_MKA_H -#define BLAKE_ROUND_MKA_H - -#include "blake2.h" -#include "blake2-impl.h" - -/*designed by the Lyra PHC team */ -static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) { - const uint64_t m = UINT64_C(0xFFFFFFFF); - const uint64_t xy = (x & m) * (y & m); - return x + y + 2 * xy; -} - -#define G(a, b, c, d) \ - do { \ - a = fBlaMka(a, b); \ - d = rotr64(d ^ a, 32); \ - c = fBlaMka(c, d); \ - b = rotr64(b ^ c, 24); \ - a = fBlaMka(a, b); \ - d = rotr64(d ^ a, 16); \ - c = fBlaMka(c, d); \ - b = rotr64(b ^ c, 63); \ - } while ((void)0, 0) - -#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \ - v12, v13, v14, v15) \ - do { \ - G(v0, v4, v8, v12); \ - G(v1, v5, v9, v13); \ - G(v2, v6, v10, v14); \ - G(v3, v7, v11, v15); \ - G(v0, v5, v10, v15); \ - G(v1, v6, v11, v12); \ - G(v2, v7, v8, v13); \ - G(v3, v4, v9, v14); \ - } while ((void)0, 0) - -#endif diff --git a/ext/standard/argon2lib/core.c b/ext/standard/argon2lib/core.c deleted file mode 100644 index 278d36c8cb7..00000000000 --- a/ext/standard/argon2lib/core.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Argon2 source code package - * - * Written by Daniel Dinu and Dmitry Khovratovich, 2015 - * - * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with - * this software. If not, see - * . - */ - -/*For memory wiping*/ -#ifdef _MSC_VER -#include -#include /* For SecureZeroMemory */ -#endif -#if defined __STDC_LIB_EXT1__ -#define __STDC_WANT_LIB_EXT1__ 1 -#endif -#define VC_GE_2005(version) (version >= 1400) - -#include -#include -#include -#include - -#include "core.h" -#include "thread.h" -#include "blake2/blake2.h" -#include "blake2/blake2-impl.h" - -#ifdef GENKAT -#include "genkat.h" -#endif - -#if defined(__clang__) -#if __has_attribute(optnone) -#define NOT_OPTIMIZED __attribute__((optnone)) -#endif -#elif defined(__GNUC__) -#define GCC_VERSION \ - (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#if GCC_VERSION >= 40400 -#define NOT_OPTIMIZED __attribute__((optimize("O0"))) -#endif -#endif -#ifndef NOT_OPTIMIZED -#define NOT_OPTIMIZED -#endif - -/***************Instance and Position constructors**********/ -void init_block_value(block *b, uint8_t in) { memset(b->v, in, sizeof(b->v)); } - -void copy_block(block *dst, const block *src) { - memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK); -} - -void xor_block(block *dst, const block *src) { - int i; - for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { - dst->v[i] ^= src->v[i]; - } -} - -static void load_block(block *dst, const void *input) { - unsigned i; - for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { - dst->v[i] = load64((const uint8_t *)input + i * sizeof(dst->v[i])); - } -} - -static void store_block(void *output, const block *src) { - unsigned i; - for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { - store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); - } -} - -/***************Memory allocators*****************/ -int allocate_memory(block **memory, uint32_t m_cost) { - if (memory != NULL) { - size_t memory_size = sizeof(block) * m_cost; - if (m_cost != 0 && - memory_size / m_cost != - sizeof(block)) { /*1. Check for multiplication overflow*/ - return ARGON2_MEMORY_ALLOCATION_ERROR; - } - - *memory = (block *)malloc(memory_size); /*2. Try to allocate*/ - - if (!*memory) { - return ARGON2_MEMORY_ALLOCATION_ERROR; - } - return ARGON2_OK; - } else { - return ARGON2_MEMORY_ALLOCATION_ERROR; - } -} - -void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) { -#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER) - SecureZeroMemory(v, n); -#elif defined memset_s - memset_s(v, n, 0, n); -#elif defined(__OpenBSD__) - explicit_bzero(v, n); -#else - static void *(*const volatile memset_sec)(void *, int, size_t) = &memset; - memset_sec(v, 0, n); -#endif -} - -/*********Memory functions*/ - -void clear_memory(argon2_instance_t *instance, int clear) { - if (instance->memory != NULL && clear) { - secure_wipe_memory(instance->memory, - sizeof(block) * instance->memory_blocks); - } -} - -void free_memory(block *memory) { free(memory); } - -void finalize(const argon2_context *context, argon2_instance_t *instance) { - if (context != NULL && instance != NULL) { - block blockhash; - uint32_t l; - - copy_block(&blockhash, instance->memory + instance->lane_length - 1); - - /* XOR the last blocks */ - for (l = 1; l < instance->lanes; ++l) { - uint32_t last_block_in_lane = - l * instance->lane_length + (instance->lane_length - 1); - xor_block(&blockhash, instance->memory + last_block_in_lane); - } - - /* Hash the result */ - { - uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; - store_block(blockhash_bytes, &blockhash); - blake2b_long(context->out, context->outlen, blockhash_bytes, - ARGON2_BLOCK_SIZE); - secure_wipe_memory(blockhash.v, - ARGON2_BLOCK_SIZE); /* clear blockhash */ - secure_wipe_memory(blockhash_bytes, - ARGON2_BLOCK_SIZE); /* clear blockhash_bytes */ - } - -#ifdef GENKAT - print_tag(context->out, context->outlen); -#endif - - /* Clear memory */ - clear_memory(instance, context->flags & ARGON2_FLAG_CLEAR_PASSWORD); - - /* Deallocate the memory */ - if (NULL != context->free_cbk) { - context->free_cbk((uint8_t *)instance->memory, - instance->memory_blocks * sizeof(block)); - } else { - free_memory(instance->memory); - } - } -} - -uint32_t index_alpha(const argon2_instance_t *instance, - const argon2_position_t *position, uint32_t pseudo_rand, - int same_lane) { - /* - * Pass 0: - * This lane : all already finished segments plus already constructed - * blocks in this segment - * Other lanes : all already finished segments - * Pass 1+: - * This lane : (SYNC_POINTS - 1) last segments plus already constructed - * blocks in this segment - * Other lanes : (SYNC_POINTS - 1) last segments - */ - uint32_t reference_area_size; - uint64_t relative_position; - uint32_t start_position, absolute_position; - - if (0 == position->pass) { - /* First pass */ - if (0 == position->slice) { - /* First slice */ - reference_area_size = - position->index - 1; /* all but the previous */ - } else { - if (same_lane) { - /* The same lane => add current segment */ - reference_area_size = - position->slice * instance->segment_length + - position->index - 1; - } else { - reference_area_size = - position->slice * instance->segment_length + - ((position->index == 0) ? (-1) : 0); - } - } - } else { - /* Second pass */ - if (same_lane) { - reference_area_size = instance->lane_length - - instance->segment_length + position->index - - 1; - } else { - reference_area_size = instance->lane_length - - instance->segment_length + - ((position->index == 0) ? (-1) : 0); - } - } - - /* 1.2.4. Mapping pseudo_rand to 0.. and produce - * relative position */ - relative_position = pseudo_rand; - relative_position = relative_position * relative_position >> 32; - relative_position = reference_area_size - 1 - - (reference_area_size * relative_position >> 32); - - /* 1.2.5 Computing starting position */ - start_position = 0; - - if (0 != position->pass) { - start_position = (position->slice == ARGON2_SYNC_POINTS - 1) - ? 0 - : (position->slice + 1) * instance->segment_length; - } - - /* 1.2.6. Computing absolute position */ - absolute_position = (start_position + relative_position) % - instance->lane_length; /* absolute position */ - return absolute_position; -} - -#ifdef _WIN32 -static unsigned __stdcall fill_segment_thr(void *thread_data) -#else -static void *fill_segment_thr(void *thread_data) -#endif -{ - argon2_thread_data *my_data = (argon2_thread_data *)thread_data; - fill_segment(my_data->instance_ptr, my_data->pos); - argon2_thread_exit(); - return 0; -} - -int fill_memory_blocks(argon2_instance_t *instance) { - uint32_t r, s; - argon2_thread_handle_t *thread = NULL; - argon2_thread_data *thr_data = NULL; - - if (instance == NULL || instance->lanes == 0) { - return ARGON2_THREAD_FAIL; - } - - /* 1. Allocating space for threads */ - thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t)); - if (thread == NULL) { - return ARGON2_MEMORY_ALLOCATION_ERROR; - } - - thr_data = calloc(instance->lanes, sizeof(argon2_thread_data)); - if (thr_data == NULL) { - free(thread); - return ARGON2_MEMORY_ALLOCATION_ERROR; - } - - for (r = 0; r < instance->passes; ++r) { - for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { - int rc; - uint32_t l; - - /* 2. Calling threads */ - for (l = 0; l < instance->lanes; ++l) { - argon2_position_t position; - - /* 2.1 Join a thread if limit is exceeded */ - if (l >= instance->threads) { - rc = argon2_thread_join(thread[l - instance->threads]); - if (rc) { - free(thr_data); - free(thread); - return ARGON2_THREAD_FAIL; - } - } - - /* 2.2 Create thread */ - position.pass = r; - position.lane = l; - position.slice = (uint8_t)s; - position.index = 0; - thr_data[l].instance_ptr = - instance; /* preparing the thread input */ - memcpy(&(thr_data[l].pos), &position, - sizeof(argon2_position_t)); - rc = argon2_thread_create(&thread[l], &fill_segment_thr, - (void *)&thr_data[l]); - if (rc) { - free(thr_data); - free(thread); - return ARGON2_THREAD_FAIL; - } - - /* fill_segment(instance, position); */ - /*Non-thread equivalent of the lines above */ - } - - /* 3. Joining remaining threads */ - for (l = instance->lanes - instance->threads; l < instance->lanes; - ++l) { - rc = argon2_thread_join(thread[l]); - if (rc) { - return ARGON2_THREAD_FAIL; - } - } - } - -#ifdef GENKAT - internal_kat(instance, r); /* Print all memory blocks */ -#endif - } - - if (thread != NULL) { - free(thread); - } - if (thr_data != NULL) { - free(thr_data); - } - return ARGON2_OK; -} - -int validate_inputs(const argon2_context *context) { - if (NULL == context) { - return ARGON2_INCORRECT_PARAMETER; - } - - if (NULL == context->out) { - return ARGON2_OUTPUT_PTR_NULL; - } - - /* Validate output length */ - if (ARGON2_MIN_OUTLEN > context->outlen) { - return ARGON2_OUTPUT_TOO_SHORT; - } - - if (ARGON2_MAX_OUTLEN < context->outlen) { - return ARGON2_OUTPUT_TOO_LONG; - } - - /* Validate password length */ - if (NULL == context->pwd) { - if (0 != context->pwdlen) { - return ARGON2_PWD_PTR_MISMATCH; - } - } else { - if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) { - return ARGON2_PWD_TOO_SHORT; - } - - if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) { - return ARGON2_PWD_TOO_LONG; - } - } - - /* Validate salt length */ - if (NULL == context->salt) { - if (0 != context->saltlen) { - return ARGON2_SALT_PTR_MISMATCH; - } - } else { - if (ARGON2_MIN_SALT_LENGTH > context->saltlen) { - return ARGON2_SALT_TOO_SHORT; - } - - if (ARGON2_MAX_SALT_LENGTH < context->saltlen) { - return ARGON2_SALT_TOO_LONG; - } - } - - /* Validate secret length */ - if (NULL == context->secret) { - if (0 != context->secretlen) { - return ARGON2_SECRET_PTR_MISMATCH; - } - } else { - if (ARGON2_MIN_SECRET > context->secretlen) { - return ARGON2_SECRET_TOO_SHORT; - } - - if (ARGON2_MAX_SECRET < context->secretlen) { - return ARGON2_SECRET_TOO_LONG; - } - } - - /* Validate associated data */ - if (NULL == context->ad) { - if (0 != context->adlen) { - return ARGON2_AD_PTR_MISMATCH; - } - } else { - if (ARGON2_MIN_AD_LENGTH > context->adlen) { - return ARGON2_AD_TOO_SHORT; - } - - if (ARGON2_MAX_AD_LENGTH < context->adlen) { - return ARGON2_AD_TOO_LONG; - } - } - - /* Validate memory cost */ - if (ARGON2_MIN_MEMORY > context->m_cost) { - return ARGON2_MEMORY_TOO_LITTLE; - } - - if (ARGON2_MAX_MEMORY < context->m_cost) { - return ARGON2_MEMORY_TOO_MUCH; - } - - if (context->m_cost < 8 * context->lanes) { - return ARGON2_MEMORY_TOO_LITTLE; - } - - /* Validate time cost */ - if (ARGON2_MIN_TIME > context->t_cost) { - return ARGON2_TIME_TOO_SMALL; - } - - if (ARGON2_MAX_TIME < context->t_cost) { - return ARGON2_TIME_TOO_LARGE; - } - - /* Validate lanes */ - if (ARGON2_MIN_LANES > context->lanes) { - return ARGON2_LANES_TOO_FEW; - } - - if (ARGON2_MAX_LANES < context->lanes) { - return ARGON2_LANES_TOO_MANY; - } - - /* Validate threads */ - if (ARGON2_MIN_THREADS > context->threads) { - return ARGON2_THREADS_TOO_FEW; - } - - if (ARGON2_MAX_THREADS < context->threads) { - return ARGON2_THREADS_TOO_MANY; - } - - if (NULL != context->allocate_cbk && NULL == context->free_cbk) { - return ARGON2_FREE_MEMORY_CBK_NULL; - } - - if (NULL == context->allocate_cbk && NULL != context->free_cbk) { - return ARGON2_ALLOCATE_MEMORY_CBK_NULL; - } - - return ARGON2_OK; -} - -void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) { - uint32_t l; - /* Make the first and second block in each lane as G(H0||i||0) or - G(H0||i||1) */ - uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; - for (l = 0; l < instance->lanes; ++l) { - - store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0); - store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); - blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, - ARGON2_PREHASH_SEED_LENGTH); - load_block(&instance->memory[l * instance->lane_length + 0], - blockhash_bytes); - - store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1); - blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, - ARGON2_PREHASH_SEED_LENGTH); - load_block(&instance->memory[l * instance->lane_length + 1], - blockhash_bytes); - } - secure_wipe_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); -} - -void initial_hash(uint8_t *blockhash, argon2_context *context, - argon2_type type) { - blake2b_state BlakeHash; - uint8_t value[sizeof(uint32_t)]; - - if (NULL == context || NULL == blockhash) { - return; - } - - blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH); - - store32(&value, context->lanes); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - store32(&value, context->outlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - store32(&value, context->m_cost); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - store32(&value, context->t_cost); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - store32(&value, context->version); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - store32(&value, (uint32_t)type); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - store32(&value, context->pwdlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - if (context->pwd != NULL) { - blake2b_update(&BlakeHash, (const uint8_t *)context->pwd, - context->pwdlen); - - if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { - secure_wipe_memory(context->pwd, context->pwdlen); - context->pwdlen = 0; - } - } - - store32(&value, context->saltlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - if (context->salt != NULL) { - blake2b_update(&BlakeHash, (const uint8_t *)context->salt, - context->saltlen); - } - - store32(&value, context->secretlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - if (context->secret != NULL) { - blake2b_update(&BlakeHash, (const uint8_t *)context->secret, - context->secretlen); - - if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { - secure_wipe_memory(context->secret, context->secretlen); - context->secretlen = 0; - } - } - - store32(&value, context->adlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); - - if (context->ad != NULL) { - blake2b_update(&BlakeHash, (const uint8_t *)context->ad, - context->adlen); - } - - blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH); -} - -int initialize(argon2_instance_t *instance, argon2_context *context) { - uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; - int result = ARGON2_OK; - - if (instance == NULL || context == NULL) - return ARGON2_INCORRECT_PARAMETER; - - /* 1. Memory allocation */ - - if (NULL != context->allocate_cbk) { - uint8_t *p; - result = context->allocate_cbk(&p, instance->memory_blocks * - ARGON2_BLOCK_SIZE); - if (ARGON2_OK != result) { - return result; - } - memcpy(&(instance->memory), p, sizeof(instance->memory)); - } else { - result = allocate_memory(&(instance->memory), instance->memory_blocks); - if (ARGON2_OK != result) { - return result; - } - } - - /* 2. Initial hashing */ - /* H_0 + 8 extra bytes to produce the first blocks */ - /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */ - /* Hashing all inputs */ - initial_hash(blockhash, context, instance->type); - /* Zeroing 8 extra bytes */ - secure_wipe_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, - ARGON2_PREHASH_SEED_LENGTH - - ARGON2_PREHASH_DIGEST_LENGTH); - -#ifdef GENKAT - initial_kat(blockhash, context, instance->type); -#endif - - /* 3. Creating first blocks, we always have at least two blocks in a slice - */ - fill_first_blocks(blockhash, instance); - /* Clearing the hash */ - secure_wipe_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH); - - return ARGON2_OK; -} diff --git a/ext/standard/argon2lib/core.h b/ext/standard/argon2lib/core.h deleted file mode 100644 index e1e70faf857..00000000000 --- a/ext/standard/argon2lib/core.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Argon2 source code package - * - * Written by Daniel Dinu and Dmitry Khovratovich, 2015 - * - * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with - * this software. If not, see - * . - */ - -#ifndef ARGON2_CORE_H -#define ARGON2_CORE_H - -#include "argon2.h" - -#if defined(_MSC_VER) -#define ALIGN(n) __declspec(align(16)) -#elif defined(__GNUC__) || defined(__clang) -#define ALIGN(x) __attribute__((__aligned__(x))) -#else -#define ALIGN(x) -#endif - -#define CONST_CAST(x) (x)(uintptr_t) - -/*************************Argon2 internal - * constants**************************************************/ - -enum argon2_core_constants { - /* Memory block size in bytes */ - ARGON2_BLOCK_SIZE = 1024, - ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8, - ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16, - - /* Number of pseudo-random values generated by one call to Blake in Argon2i - to - generate reference block positions */ - ARGON2_ADDRESSES_IN_BLOCK = 128, - - /* Pre-hashing digest length and its extension*/ - ARGON2_PREHASH_DIGEST_LENGTH = 64, - ARGON2_PREHASH_SEED_LENGTH = 72 -}; - -/*************************Argon2 internal data - * types**************************************************/ - -/* - * Structure for the (1KB) memory block implemented as 128 64-bit words. - * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no - * bounds checking). - */ -typedef struct block_ { uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block; - -/*****************Functions that work with the block******************/ - -/* Initialize each byte of the block with @in */ -void init_block_value(block *b, uint8_t in); - -/* Copy block @src to block @dst */ -void copy_block(block *dst, const block *src); - -/* XOR @src onto @dst bytewise */ -void xor_block(block *dst, const block *src); - -/* - * Argon2 instance: memory pointer, number of passes, amount of memory, type, - * and derived values. - * Used to evaluate the number and location of blocks to construct in each - * thread - */ -typedef struct Argon2_instance_t { - block *memory; /* Memory pointer */ - uint32_t version; - uint32_t passes; /* Number of passes */ - uint32_t memory_blocks; /* Number of blocks in memory */ - uint32_t segment_length; - uint32_t lane_length; - uint32_t lanes; - uint32_t threads; - argon2_type type; - int print_internals; /* whether to print the memory blocks */ -} argon2_instance_t; - -/* - * Argon2 position: where we construct the block right now. Used to distribute - * work between threads. - */ -typedef struct Argon2_position_t { - uint32_t pass; - uint32_t lane; - uint8_t slice; - uint32_t index; -} argon2_position_t; - -/*Struct that holds the inputs for thread handling FillSegment*/ -typedef struct Argon2_thread_data { - argon2_instance_t *instance_ptr; - argon2_position_t pos; -} argon2_thread_data; - -/*************************Argon2 core - * functions**************************************************/ - -/* Allocates memory to the given pointer - * @param memory pointer to the pointer to the memory - * @param m_cost number of blocks to allocate in the memory - * @return ARGON2_OK if @memory is a valid pointer and memory is allocated - */ -int allocate_memory(block **memory, uint32_t m_cost); - -/* Function that securely cleans the memory - * @param mem Pointer to the memory - * @param s Memory size in bytes - */ -void secure_wipe_memory(void *v, size_t n); - -/* Clears memory - * @param instance pointer to the current instance - * @param clear_memory indicates if we clear the memory with zeros. - */ -void clear_memory(argon2_instance_t *instance, int clear); - -/* Deallocates memory - * @param memory pointer to the blocks - */ -void free_memory(block *memory); - -/* - * Computes absolute position of reference block in the lane following a skewed - * distribution and using a pseudo-random value as input - * @param instance Pointer to the current instance - * @param position Pointer to the current position - * @param pseudo_rand 32-bit pseudo-random value used to determine the position - * @param same_lane Indicates if the block will be taken from the current lane. - * If so we can reference the current segment - * @pre All pointers must be valid - */ -uint32_t index_alpha(const argon2_instance_t *instance, - const argon2_position_t *position, uint32_t pseudo_rand, - int same_lane); - -/* - * Function that validates all inputs against predefined restrictions and return - * an error code - * @param context Pointer to current Argon2 context - * @return ARGON2_OK if everything is all right, otherwise one of error codes - * (all defined in - */ -int validate_inputs(const argon2_context *context); - -/* - * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears - * password and secret if needed - * @param context Pointer to the Argon2 internal structure containing memory - * pointer, and parameters for time and space requirements. - * @param blockhash Buffer for pre-hashing digest - * @param type Argon2 type - * @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes - * allocated - */ -void initial_hash(uint8_t *blockhash, argon2_context *context, - argon2_type type); - -/* - * Function creates first 2 blocks per lane - * @param instance Pointer to the current instance - * @param blockhash Pointer to the pre-hashing digest - * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values - */ -void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance); - -/* - * Function allocates memory, hashes the inputs with Blake, and creates first - * two blocks. Returns the pointer to the main memory with 2 blocks per lane - * initialized - * @param context Pointer to the Argon2 internal structure containing memory - * pointer, and parameters for time and space requirements. - * @param instance Current Argon2 instance - * @return Zero if successful, -1 if memory failed to allocate. @context->state - * will be modified if successful. - */ -int initialize(argon2_instance_t *instance, argon2_context *context); - -/* - * XORing the last block of each lane, hashing it, making the tag. Deallocates - * the memory. - * @param context Pointer to current Argon2 context (use only the out parameters - * from it) - * @param instance Pointer to current instance of Argon2 - * @pre instance->state must point to necessary amount of memory - * @pre context->out must point to outlen bytes of memory - * @pre if context->free_cbk is not NULL, it should point to a function that - * deallocates memory - */ -void finalize(const argon2_context *context, argon2_instance_t *instance); - -/* - * Function that fills the segment using previous segments also from other - * threads - * @param instance Pointer to the current instance - * @param position Current position - * @pre all block pointers must be valid - */ -void fill_segment(const argon2_instance_t *instance, - argon2_position_t position); - -/* - * Function that fills the entire memory t_cost times based on the first two - * blocks in each lane - * @param instance Pointer to the current instance - * @return ARGON2_OK if successful, @context->state - */ -int fill_memory_blocks(argon2_instance_t *instance); - -#endif diff --git a/ext/standard/argon2lib/encoding.c b/ext/standard/argon2lib/encoding.c deleted file mode 100644 index a0cafd72c53..00000000000 --- a/ext/standard/argon2lib/encoding.c +++ /dev/null @@ -1,426 +0,0 @@ -#include -#include -#include -#include -#include "encoding.h" -#include "core.h" - -/* - * Example code for a decoder and encoder of "hash strings", with Argon2 - * parameters. - * - * This code comprises three sections: - * - * -- The first section contains generic Base64 encoding and decoding - * functions. It is conceptually applicable to any hash function - * implementation that uses Base64 to encode and decode parameters, - * salts and outputs. It could be made into a library, provided that - * the relevant functions are made public (non-static) and be given - * reasonable names to avoid collisions with other functions. - * - * -- The second section is specific to Argon2. It encodes and decodes - * the parameters, salts and outputs. It does not compute the hash - * itself. - * - * -- The third section is test code, with a main() function. With - * this section, the whole file compiles as a stand-alone program - * that exercises the encoding and decoding functions with some - * test vectors. - * - * The code was originally written by Thomas Pornin , - * to whom comments and remarks may be sent. It is released under what - * should amount to Public Domain or its closest equivalent; the - * following mantra is supposed to incarnate that fact with all the - * proper legal rituals: - * - * --------------------------------------------------------------------- - * This file is provided under the terms of Creative Commons CC0 1.0 - * Public Domain Dedication. To the extent possible under law, the - * author (Thomas Pornin) has waived all copyright and related or - * neighboring rights to this file. This work is published from: Canada. - * --------------------------------------------------------------------- - * - * Copyright (c) 2015 Thomas Pornin - */ - -/* ==================================================================== */ -/* - * Common code; could be shared between different hash functions. - * - * Note: the Base64 functions below assume that uppercase letters (resp. - * lowercase letters) have consecutive numerical codes, that fit on 8 - * bits. All modern systems use ASCII-compatible charsets, where these - * properties are true. If you are stuck with a dinosaur of a system - * that still defaults to EBCDIC then you already have much bigger - * interoperability issues to deal with. - */ - -/* - * Some macros for constant-time comparisons. These work over values in - * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". - */ -#define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF) -#define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF) -#define GE(x, y) (GT(y, x) ^ 0xFF) -#define LT(x, y) GT(y, x) -#define LE(x, y) GE(y, x) - -/* - * Convert value x (0..63) to corresponding Base64 character. - */ -static int b64_byte_to_char(unsigned x) { - return (LT(x, 26) & (x + 'A')) | - (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | - (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') | - (EQ(x, 63) & '/'); -} - -/* - * Convert character c to the corresponding 6-bit value. If character c - * is not a Base64 character, then 0xFF (255) is returned. - */ -static unsigned b64_char_to_byte(int c) { - unsigned x; - - x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | - (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | - (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) | - (EQ(c, '/') & 63); - return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); -} - -/* - * Convert some bytes to Base64. 'dst_len' is the length (in characters) - * of the output buffer 'dst'; if that buffer is not large enough to - * receive the result (including the terminating 0), then (size_t)-1 - * is returned. Otherwise, the zero-terminated Base64 string is written - * in the buffer, and the output length (counted WITHOUT the terminating - * zero) is returned. - */ -static size_t to_base64(char *dst, size_t dst_len, const void *src, - size_t src_len) { - size_t olen; - const unsigned char *buf; - unsigned acc, acc_len; - - olen = (src_len / 3) << 2; - switch (src_len % 3) { - case 2: - olen++; - /* fall through */ - case 1: - olen += 2; - break; - } - if (dst_len <= olen) { - return (size_t)-1; - } - acc = 0; - acc_len = 0; - buf = (const unsigned char *)src; - while (src_len-- > 0) { - acc = (acc << 8) + (*buf++); - acc_len += 8; - while (acc_len >= 6) { - acc_len -= 6; - *dst++ = (char)b64_byte_to_char((acc >> acc_len) & 0x3F); - } - } - if (acc_len > 0) { - *dst++ = (char)b64_byte_to_char((acc << (6 - acc_len)) & 0x3F); - } - *dst++ = 0; - return olen; -} - -/* - * Decode Base64 chars into bytes. The '*dst_len' value must initially - * contain the length of the output buffer '*dst'; when the decoding - * ends, the actual number of decoded bytes is written back in - * '*dst_len'. - * - * Decoding stops when a non-Base64 character is encountered, or when - * the output buffer capacity is exceeded. If an error occurred (output - * buffer is too small, invalid last characters leading to unprocessed - * buffered bits), then NULL is returned; otherwise, the returned value - * points to the first non-Base64 character in the source stream, which - * may be the terminating zero. - */ -static const char *from_base64(void *dst, size_t *dst_len, const char *src) { - size_t len; - unsigned char *buf; - unsigned acc, acc_len; - - buf = (unsigned char *)dst; - len = 0; - acc = 0; - acc_len = 0; - for (;;) { - unsigned d; - - d = b64_char_to_byte(*src); - if (d == 0xFF) { - break; - } - src++; - acc = (acc << 6) + d; - acc_len += 6; - if (acc_len >= 8) { - acc_len -= 8; - if ((len++) >= *dst_len) { - return NULL; - } - *buf++ = (acc >> acc_len) & 0xFF; - } - } - - /* - * If the input length is equal to 1 modulo 4 (which is - * invalid), then there will remain 6 unprocessed bits; - * otherwise, only 0, 2 or 4 bits are buffered. The buffered - * bits must also all be zero. - */ - if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) { - return NULL; - } - *dst_len = len; - return src; -} - -/* - * Decode decimal integer from 'str'; the value is written in '*v'. - * Returned value is a pointer to the next non-decimal character in the - * string. If there is no digit at all, or the value encoding is not - * minimal (extra leading zeros), or the value does not fit in an - * 'unsigned long', then NULL is returned. - */ -static const char *decode_decimal(const char *str, unsigned long *v) { - const char *orig; - unsigned long acc; - - acc = 0; - for (orig = str;; str++) { - int c; - - c = *str; - if (c < '0' || c > '9') { - break; - } - c -= '0'; - if (acc > (ULONG_MAX / 10)) { - return NULL; - } - acc *= 10; - if ((unsigned long)c > (ULONG_MAX - acc)) { - return NULL; - } - acc += (unsigned long)c; - } - if (str == orig || (*orig == '0' && str != (orig + 1))) { - return NULL; - } - *v = acc; - return str; -} - -/* ==================================================================== */ -/* - * Code specific to Argon2. - * - * The code below applies the following format: - * - * $argon2[$v=]$m=,t=,p=[,keyid=][,data=][$[$]] - * - * where is either 'd' or 'i', is a decimal integer (positive, fits in - * an 'unsigned long'), and is Base64-encoded data (no '=' padding - * characters, no newline or whitespace). - * The "keyid" is a binary identifier for a key (up to 8 bytes); - * "data" is associated data (up to 32 bytes). When the 'keyid' - * (resp. the 'data') is empty, then it is ommitted from the output. - * - * The last two binary chunks (encoded in Base64) are, in that order, - * the salt and the output. Both are optional, but you cannot have an - * output without a salt. The binary salt length is between 8 and 48 bytes. - * The output length is always exactly 32 bytes. - */ - -int decode_string(argon2_context *ctx, const char *str, argon2_type type) { - -/* check for prefix */ -#define CC(prefix) \ - do { \ - size_t cc_len = strlen(prefix); \ - if (strncmp(str, prefix, cc_len) != 0) { \ - return ARGON2_DECODING_FAIL; \ - } \ - str += cc_len; \ - } while ((void)0, 0) - -/* prefix checking with supplied code */ -#define CC_opt(prefix, code) \ - do { \ - size_t cc_len = strlen(prefix); \ - if (strncmp(str, prefix, cc_len) == 0) { \ - str += cc_len; \ - { code; } \ - } \ - } while ((void)0, 0) - -/* Decoding prefix into decimal */ -#define DECIMAL(x) \ - do { \ - unsigned long dec_x; \ - str = decode_decimal(str, &dec_x); \ - if (str == NULL) { \ - return ARGON2_DECODING_FAIL; \ - } \ - (x) = dec_x; \ - } while ((void)0, 0) - -#define BIN(buf, max_len, len) \ - do { \ - size_t bin_len = (max_len); \ - str = from_base64(buf, &bin_len, str); \ - if (str == NULL || bin_len > UINT32_MAX) { \ - return ARGON2_DECODING_FAIL; \ - } \ - (len) = (uint32_t)bin_len; \ - } while ((void)0, 0) - - size_t maxadlen = ctx->adlen; - size_t maxsaltlen = ctx->saltlen; - size_t maxoutlen = ctx->outlen; - int validation_result; - - ctx->adlen = 0; - ctx->saltlen = 0; - ctx->outlen = 0; - ctx->pwdlen = 0; - - if (type == Argon2_i) - CC("$argon2i"); - else if (type == Argon2_d) - CC("$argon2d"); - else - return ARGON2_INCORRECT_TYPE; - ctx->version = ARGON2_VERSION_10; - /* Reading the version number if the default is suppressed */ - CC_opt("$v=", DECIMAL(ctx->version)); - CC("$m="); - DECIMAL(ctx->m_cost); - CC(",t="); - DECIMAL(ctx->t_cost); - CC(",p="); - DECIMAL(ctx->lanes); - ctx->threads = ctx->lanes; - - CC_opt(",data=", BIN(ctx->ad, maxadlen, ctx->adlen)); - if (*str == 0) { - return ARGON2_OK; - } - CC("$"); - BIN(ctx->salt, maxsaltlen, ctx->saltlen); - if (*str == 0) { - return ARGON2_OK; - } - CC("$"); - BIN(ctx->out, maxoutlen, ctx->outlen); - validation_result = validate_inputs(ctx); - if (validation_result != ARGON2_OK) { - return validation_result; - } - if (*str == 0) { - return ARGON2_OK; - } else { - return ARGON2_DECODING_FAIL; - } -#undef CC -#undef CC_opt -#undef DECIMAL -#undef BIN -} - -int encode_string(char *dst, size_t dst_len, argon2_context *ctx, - argon2_type type) { -#define SS(str) \ - do { \ - size_t pp_len = strlen(str); \ - if (pp_len >= dst_len) { \ - return ARGON2_ENCODING_FAIL; \ - } \ - memcpy(dst, str, pp_len + 1); \ - dst += pp_len; \ - dst_len -= pp_len; \ - } while ((void)0, 0) - -#define SX(x) \ - do { \ - char tmp[30]; \ - sprintf(tmp, "%lu", (unsigned long)(x)); \ - SS(tmp); \ - } while ((void)0, 0) - -#define SB(buf, len) \ - do { \ - size_t sb_len = to_base64(dst, dst_len, buf, len); \ - if (sb_len == (size_t)-1) { \ - return ARGON2_ENCODING_FAIL; \ - } \ - dst += sb_len; \ - dst_len -= sb_len; \ - } while ((void)0, 0) - - if (type == Argon2_i) - SS("$argon2i$v="); - else if (type == Argon2_d) - SS("$argon2d$v="); - else - return ARGON2_ENCODING_FAIL; - - if (validate_inputs(ctx) != ARGON2_OK) { - return validate_inputs(ctx); - } - SX(ctx->version); - SS("$m="); - SX(ctx->m_cost); - SS(",t="); - SX(ctx->t_cost); - SS(",p="); - SX(ctx->lanes); - - if (ctx->adlen > 0) { - SS(",data="); - SB(ctx->ad, ctx->adlen); - } - - if (ctx->saltlen == 0) - return ARGON2_OK; - - SS("$"); - SB(ctx->salt, ctx->saltlen); - - if (ctx->outlen == 0) - return ARGON2_OK; - - SS("$"); - SB(ctx->out, ctx->outlen); - return ARGON2_OK; - -#undef SS -#undef SX -#undef SB -} - -size_t b64len(uint32_t len) { - return (((size_t)len + 2) / 3) * 4; -} - -size_t numlen(uint32_t num) { - size_t len = 1; - while (num >= 10) { - ++len; - num = num / 10; - } - return len; -} - diff --git a/ext/standard/argon2lib/encoding.h b/ext/standard/argon2lib/encoding.h deleted file mode 100644 index 8671f6b3d62..00000000000 --- a/ext/standard/argon2lib/encoding.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef ENCODING_H -#define ENCODING_H -#include "argon2.h" - -#define ARGON2_MAX_DECODED_LANES UINT32_C(255) -#define ARGON2_MIN_DECODED_SALT_LEN UINT32_C(8) -#define ARGON2_MIN_DECODED_OUT_LEN UINT32_C(12) - -/* -* encode an Argon2 hash string into the provided buffer. 'dst_len' -* contains the size, in characters, of the 'dst' buffer; if 'dst_len' -* is less than the number of required characters (including the -* terminating 0), then this function returns ARGON2_ENCODING_ERROR. -* -* if ctx->outlen is 0, then the hash string will be a salt string -* (no output). if ctx->saltlen is also 0, then the string will be a -* parameter-only string (no salt and no output). -* -* on success, ARGON2_OK is returned. -* -* No other parameters are checked -*/ -int encode_string(char *dst, size_t dst_len, argon2_context *ctx, - argon2_type type); - -/* -* Decodes an Argon2 hash string into the provided structure 'ctx'. -* The fields ctx.saltlen, ctx.adlen, ctx.outlen set the maximal salt, ad, out -* length values that are allowed; invalid input string causes an error. -* Returned value is ARGON2_OK on success, other ARGON2_ codes on error. -*/ -int decode_string(argon2_context *ctx, const char *str, argon2_type type); - -/* Returns the length of the encoded byte stream with length len */ -size_t b64len(uint32_t len); - -/* Returns the length of the encoded number num */ -size_t numlen(uint32_t num); - -#endif diff --git a/ext/standard/argon2lib/opt.c b/ext/standard/argon2lib/opt.c deleted file mode 100644 index 2ba467d5d67..00000000000 --- a/ext/standard/argon2lib/opt.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Argon2 source code package - * - * Written by Daniel Dinu and Dmitry Khovratovich, 2015 - * - * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with - * this software. If not, see - * . - */ - -#include -#include -#include - -#include "argon2.h" -#include "opt.h" - -#include "blake2/blake2.h" -#include "blake2/blamka-round-opt.h" - -void fill_block(__m128i *state, const uint8_t *ref_block, uint8_t *next_block) { - __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; - uint32_t i; - - for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { - block_XY[i] = state[i] = _mm_xor_si128( - state[i], _mm_loadu_si128((__m128i const *)(&ref_block[16 * i]))); - } - - for (i = 0; i < 8; ++i) { - BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], - state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], - state[8 * i + 6], state[8 * i + 7]); - } - - for (i = 0; i < 8; ++i) { - BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], - state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], - state[8 * 6 + i], state[8 * 7 + i]); - } - - for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { - state[i] = _mm_xor_si128(state[i], block_XY[i]); - _mm_storeu_si128((__m128i *)(&next_block[16 * i]), state[i]); - } -} - -void fill_block_with_xor(__m128i *state, const uint8_t *ref_block, - uint8_t *next_block) { - __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; - uint32_t i; - - for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { - state[i] = _mm_xor_si128( - state[i], _mm_loadu_si128((__m128i const *)(&ref_block[16 * i]))); - block_XY[i] = _mm_xor_si128( - state[i], _mm_loadu_si128((__m128i const *)(&next_block[16 * i]))); - } - - for (i = 0; i < 8; ++i) { - BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], - state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], - state[8 * i + 6], state[8 * i + 7]); - } - - for (i = 0; i < 8; ++i) { - BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], - state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], - state[8 * 6 + i], state[8 * 7 + i]); - } - - for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { - state[i] = _mm_xor_si128(state[i], block_XY[i]); - _mm_storeu_si128((__m128i *)(&next_block[16 * i]), state[i]); - } -} - -void generate_addresses(const argon2_instance_t *instance, - const argon2_position_t *position, - uint64_t *pseudo_rands) { - block address_block, input_block, tmp_block; - uint32_t i; - - init_block_value(&address_block, 0); - init_block_value(&input_block, 0); - - if (instance != NULL && position != NULL) { - input_block.v[0] = position->pass; - input_block.v[1] = position->lane; - input_block.v[2] = position->slice; - input_block.v[3] = instance->memory_blocks; - input_block.v[4] = instance->passes; - input_block.v[5] = instance->type; - - for (i = 0; i < instance->segment_length; ++i) { - if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { - /*Temporary zero-initialized blocks*/ - __m128i zero_block[ARGON2_OWORDS_IN_BLOCK]; - __m128i zero2_block[ARGON2_OWORDS_IN_BLOCK]; - memset(zero_block, 0, sizeof(zero_block)); - memset(zero2_block, 0, sizeof(zero2_block)); - init_block_value(&address_block, 0); - init_block_value(&tmp_block, 0); - /*Increasing index counter*/ - input_block.v[6]++; - /*First iteration of G*/ - fill_block_with_xor(zero_block, (uint8_t *)&input_block.v, - (uint8_t *)&tmp_block.v); - /*Second iteration of G*/ - fill_block_with_xor(zero2_block, (uint8_t *)&tmp_block.v, - (uint8_t *)&address_block.v); - } - - pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; - } - } -} - -void fill_segment(const argon2_instance_t *instance, - argon2_position_t position) { - block *ref_block = NULL, *curr_block = NULL; - uint64_t pseudo_rand, ref_index, ref_lane; - uint32_t prev_offset, curr_offset; - uint32_t starting_index, i; - __m128i state[64]; - int data_independent_addressing; - - /* Pseudo-random values that determine the reference block position */ - uint64_t *pseudo_rands = NULL; - - if (instance == NULL) { - return; - } - - data_independent_addressing = (instance->type == Argon2_i); - - pseudo_rands = - (uint64_t *)malloc(sizeof(uint64_t) * instance->segment_length); - if (pseudo_rands == NULL) { - return; - } - - if (data_independent_addressing) { - generate_addresses(instance, &position, pseudo_rands); - } - - starting_index = 0; - - if ((0 == position.pass) && (0 == position.slice)) { - starting_index = 2; /* we have already generated the first two blocks */ - } - - /* Offset of the current block */ - curr_offset = position.lane * instance->lane_length + - position.slice * instance->segment_length + starting_index; - - if (0 == curr_offset % instance->lane_length) { - /* Last block in this lane */ - prev_offset = curr_offset + instance->lane_length - 1; - } else { - /* Previous block */ - prev_offset = curr_offset - 1; - } - - memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE); - - for (i = starting_index; i < instance->segment_length; - ++i, ++curr_offset, ++prev_offset) { - /*1.1 Rotating prev_offset if needed */ - if (curr_offset % instance->lane_length == 1) { - prev_offset = curr_offset - 1; - } - - /* 1.2 Computing the index of the reference block */ - /* 1.2.1 Taking pseudo-random value from the previous block */ - if (data_independent_addressing) { - pseudo_rand = pseudo_rands[i]; - } else { - pseudo_rand = instance->memory[prev_offset].v[0]; - } - - /* 1.2.2 Computing the lane of the reference block */ - ref_lane = ((pseudo_rand >> 32)) % instance->lanes; - - if ((position.pass == 0) && (position.slice == 0)) { - /* Can not reference other lanes yet */ - ref_lane = position.lane; - } - - /* 1.2.3 Computing the number of possible reference block within the - * lane. - */ - position.index = i; - ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, - ref_lane == position.lane); - - /* 2 Creating a new block */ - ref_block = - instance->memory + instance->lane_length * ref_lane + ref_index; - curr_block = instance->memory + curr_offset; - if (ARGON2_VERSION_10 == instance->version) { - /* version 1.2.1 and earlier: overwrite, not XOR */ - fill_block(state, (uint8_t *)ref_block->v, - (uint8_t *)curr_block->v); - } else { - if(0 == position.pass) { - fill_block(state, (uint8_t *)ref_block->v, - (uint8_t *)curr_block->v); - } else { - fill_block_with_xor(state, (uint8_t *)ref_block->v, - (uint8_t *)curr_block->v); - } - } - } - - free(pseudo_rands); -} diff --git a/ext/standard/argon2lib/opt.h b/ext/standard/argon2lib/opt.h deleted file mode 100644 index 49660c2984f..00000000000 --- a/ext/standard/argon2lib/opt.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Argon2 source code package - * - * Written by Daniel Dinu and Dmitry Khovratovich, 2015 - * - * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with - * this software. If not, see - * . - */ - -#ifndef ARGON2_OPT_H -#define ARGON2_OPT_H - -#include "core.h" -#include - -/* - * Function fills a new memory block by XORing the new block over the old one. Memory must be initialized. - * After finishing, @state is identical to @next_block - * @param state Pointer to the just produced block. Content will be updated(!) - * @param ref_block Pointer to the reference block - * @param next_block Pointer to the block to be XORed over. May coincide with @ref_block - * @pre all block pointers must be valid - */ -void fill_block_with_xor(__m128i *state, const uint8_t *ref_block, uint8_t *next_block); - -/* LEGACY CODE: version 1.2.1 and earlier -* Function fills a new memory block by overwriting @next_block. -* @param state Pointer to the just produced block. Content will be updated(!) -* @param ref_block Pointer to the reference block -* @param next_block Pointer to the block to be XORed over. May coincide with @ref_block -* @pre all block pointers must be valid -*/ -void fill_block(__m128i *state, const uint8_t *ref_block, uint8_t *next_block); - - -/* - * Generate pseudo-random values to reference blocks in the segment and puts - * them into the array - * @param instance Pointer to the current instance - * @param position Pointer to the current position - * @param pseudo_rands Pointer to the array of 64-bit values - * @pre pseudo_rands must point to @a instance->segment_length allocated values - */ -void generate_addresses(const argon2_instance_t *instance, - const argon2_position_t *position, - uint64_t *pseudo_rands); - -#endif /* ARGON2_OPT_H */ diff --git a/ext/standard/argon2lib/ref.c b/ext/standard/argon2lib/ref.c deleted file mode 100644 index 9ee610128d9..00000000000 --- a/ext/standard/argon2lib/ref.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Argon2 source code package - * - * Written by Daniel Dinu and Dmitry Khovratovich, 2015 - * - * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with - * this software. If not, see - * . - */ - -#include -#include -#include - -#include "argon2.h" -#include "ref.h" - -#include "blake2/blamka-round-ref.h" -#include "blake2/blake2-impl.h" -#include "blake2/blake2.h" - - -void fill_block(const block *prev_block, const block *ref_block, - block *next_block) { - block blockR, block_tmp; - unsigned i; - - copy_block(&blockR, ref_block); - xor_block(&blockR, prev_block); - copy_block(&block_tmp, &blockR); - /*Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block */ - /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then - (16,17,..31)... finally (112,113,...127) */ - for (i = 0; i < 8; ++i) { - BLAKE2_ROUND_NOMSG( - blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], - blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], - blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], - blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], - blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], - blockR.v[16 * i + 15]); - } - - /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then - (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ - for (i = 0; i < 8; i++) { - BLAKE2_ROUND_NOMSG( - blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], - blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], - blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], - blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], - blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], - blockR.v[2 * i + 113]); - } - - copy_block(next_block, &block_tmp); - xor_block(next_block, &blockR); -} - - -void fill_block_with_xor(const block *prev_block, const block *ref_block, - block *next_block) { - block blockR, block_tmp; - unsigned i; - - copy_block(&blockR, ref_block); - xor_block(&blockR, prev_block); - copy_block(&block_tmp, &blockR); - xor_block(&block_tmp, next_block); /*Saving the next block contents for XOR over*/ - /*Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block + next_block*/ - /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then - (16,17,..31)... finally (112,113,...127) */ - for (i = 0; i < 8; ++i) { - BLAKE2_ROUND_NOMSG( - blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], - blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], - blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], - blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], - blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], - blockR.v[16 * i + 15]); - } - - /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then - (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ - for (i = 0; i < 8; i++) { - BLAKE2_ROUND_NOMSG( - blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], - blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], - blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], - blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], - blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], - blockR.v[2 * i + 113]); - } - - copy_block(next_block, &block_tmp); - xor_block(next_block, &blockR); -} - -void generate_addresses(const argon2_instance_t *instance, - const argon2_position_t *position, - uint64_t *pseudo_rands) { - block zero_block, input_block, address_block,tmp_block; - uint32_t i; - - init_block_value(&zero_block, 0); - init_block_value(&input_block, 0); - - if (instance != NULL && position != NULL) { - input_block.v[0] = position->pass; - input_block.v[1] = position->lane; - input_block.v[2] = position->slice; - input_block.v[3] = instance->memory_blocks; - input_block.v[4] = instance->passes; - input_block.v[5] = instance->type; - - for (i = 0; i < instance->segment_length; ++i) { - if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { - input_block.v[6]++; - init_block_value(&tmp_block, 0); - init_block_value(&address_block, 0); - fill_block_with_xor(&zero_block, &input_block, &tmp_block); - fill_block_with_xor(&zero_block, &tmp_block, &address_block); - } - - pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; - } - } -} - -void fill_segment(const argon2_instance_t *instance, - argon2_position_t position) { - block *ref_block = NULL, *curr_block = NULL; - uint64_t pseudo_rand, ref_index, ref_lane; - uint32_t prev_offset, curr_offset; - uint32_t starting_index; - uint32_t i; - int data_independent_addressing; - /* Pseudo-random values that determine the reference block position */ - uint64_t *pseudo_rands = NULL; - - if (instance == NULL) { - return; - } - - data_independent_addressing = (instance->type == Argon2_i); - - pseudo_rands = - (uint64_t *)malloc(sizeof(uint64_t) * (instance->segment_length)); - - if (pseudo_rands == NULL) { - return; - } - - if (data_independent_addressing) { - generate_addresses(instance, &position, pseudo_rands); - } - - starting_index = 0; - - if ((0 == position.pass) && (0 == position.slice)) { - starting_index = 2; /* we have already generated the first two blocks */ - } - - /* Offset of the current block */ - curr_offset = position.lane * instance->lane_length + - position.slice * instance->segment_length + starting_index; - - if (0 == curr_offset % instance->lane_length) { - /* Last block in this lane */ - prev_offset = curr_offset + instance->lane_length - 1; - } else { - /* Previous block */ - prev_offset = curr_offset - 1; - } - - for (i = starting_index; i < instance->segment_length; - ++i, ++curr_offset, ++prev_offset) { - /*1.1 Rotating prev_offset if needed */ - if (curr_offset % instance->lane_length == 1) { - prev_offset = curr_offset - 1; - } - - /* 1.2 Computing the index of the reference block */ - /* 1.2.1 Taking pseudo-random value from the previous block */ - if (data_independent_addressing) { - pseudo_rand = pseudo_rands[i]; - } else { - pseudo_rand = instance->memory[prev_offset].v[0]; - } - - /* 1.2.2 Computing the lane of the reference block */ - ref_lane = ((pseudo_rand >> 32)) % instance->lanes; - - if ((position.pass == 0) && (position.slice == 0)) { - /* Can not reference other lanes yet */ - ref_lane = position.lane; - } - - /* 1.2.3 Computing the number of possible reference block within the - * lane. - */ - position.index = i; - ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, - ref_lane == position.lane); - - /* 2 Creating a new block */ - ref_block = - instance->memory + instance->lane_length * ref_lane + ref_index; - curr_block = instance->memory + curr_offset; - if (ARGON2_VERSION_10 == instance->version) { - /* version 1.2.1 and earlier: overwrite, not XOR */ - fill_block(instance->memory + prev_offset, ref_block, curr_block); - } else { - if(0 == position.pass) { - fill_block(instance->memory + prev_offset, ref_block, - curr_block); - } else { - fill_block_with_xor(instance->memory + prev_offset, ref_block, - curr_block); - } - } - } - - free(pseudo_rands); -} diff --git a/ext/standard/argon2lib/ref.h b/ext/standard/argon2lib/ref.h deleted file mode 100644 index 8d06b2a8f91..00000000000 --- a/ext/standard/argon2lib/ref.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Argon2 source code package - * - * Written by Daniel Dinu and Dmitry Khovratovich, 2015 - * - * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with - * this software. If not, see - * . - */ - -#ifndef ARGON2_REF_H -#define ARGON2_REF_H - -#include "core.h" - -/* - * Function fills a new memory block by XORing over @next_block. @next_block must be initialized - * @param prev_block Pointer to the previous block - * @param ref_block Pointer to the reference block - * @param next_block Pointer to the block to be constructed - * @pre all block pointers must be valid - */ -void fill_block_with_xor(const block *prev_block, const block *ref_block, - block *next_block); - -/* LEGACY CODE: version 1.2.1 and earlier -* Function fills a new memory block by overwriting @next_block. -* @param prev_block Pointer to the previous block -* @param ref_block Pointer to the reference block -* @param next_block Pointer to the block to be constructed -* @pre all block pointers must be valid -*/ -void fill_block(const block *prev_block, const block *ref_block, - block *next_block); - -/* - * Generate pseudo-random values to reference blocks in the segment and puts - * them into the array - * @param instance Pointer to the current instance - * @param position Pointer to the current position - * @param pseudo_rands Pointer to the array of 64-bit values - * @pre pseudo_rands must point to @a instance->segment_length allocated values - */ -void generate_addresses(const argon2_instance_t *instance, - const argon2_position_t *position, - uint64_t *pseudo_rands); - -#endif /* ARGON2_REF_H */ diff --git a/ext/standard/argon2lib/thread.c b/ext/standard/argon2lib/thread.c deleted file mode 100644 index 412261f12ca..00000000000 --- a/ext/standard/argon2lib/thread.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "thread.h" -#if defined(_WIN32) -#include -#endif - -int argon2_thread_create(argon2_thread_handle_t *handle, - argon2_thread_func_t func, void *args) { - if (NULL == handle || func == NULL) { - return -1; - } -#if defined(_WIN32) - *handle = _beginthreadex(NULL, 0, func, args, 0, NULL); - return *handle != 0 ? 0 : -1; -#else - return pthread_create(handle, NULL, func, args); -#endif -} - -int argon2_thread_join(argon2_thread_handle_t handle) { -#if defined(_WIN32) - if (WaitForSingleObject((HANDLE)handle, INFINITE) == WAIT_OBJECT_0) { - return CloseHandle((HANDLE)handle) != 0 ? 0 : -1; - } - return -1; -#else - return pthread_join(handle, NULL); -#endif -} - -void argon2_thread_exit(void) { -#if defined(_WIN32) - _endthreadex(0); -#else - pthread_exit(NULL); -#endif -} diff --git a/ext/standard/argon2lib/thread.h b/ext/standard/argon2lib/thread.h deleted file mode 100644 index 57c4ce56225..00000000000 --- a/ext/standard/argon2lib/thread.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef ARGON2_THREAD_H -#define ARGON2_THREAD_H -/* - Here we implement an abstraction layer for the simpĺe requirements - of the Argon2 code. We only require 3 primitives---thread creation, - joining, and termination---so full emulation of the pthreads API - is unwarranted. Currently we wrap pthreads and Win32 threads. - - The API defines 2 types: the function pointer type, - argon2_thread_func_t, - and the type of the thread handle---argon2_thread_handle_t. -*/ -#if defined(_WIN32) -#include -typedef unsigned(__stdcall *argon2_thread_func_t)(void *); -typedef uintptr_t argon2_thread_handle_t; -#else -#include -typedef void *(*argon2_thread_func_t)(void *); -typedef pthread_t argon2_thread_handle_t; -#endif - -/* Creates a thread - * @param handle pointer to a thread handle, which is the output of this - * function. Must not be NULL. - * @param func A function pointer for the thread's entry point. Must not be - * NULL. - * @param args Pointer that is passed as an argument to @func. May be NULL. - * @return 0 if @handle and @func are valid pointers and a thread is successfuly - * created. - */ -int argon2_thread_create(argon2_thread_handle_t *handle, - argon2_thread_func_t func, void *args); - -/* Waits for a thread to terminate - * @param handle Handle to a thread created with argon2_thread_create. - * @return 0 if @handle is a valid handle, and joining completed successfully. -*/ -int argon2_thread_join(argon2_thread_handle_t handle); - -/* Terminate the current thread. Must be run inside a thread created by - * argon2_thread_create. -*/ -void argon2_thread_exit(void); - -#endif diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index f37d34928b2..f0dc00512ce 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -553,9 +553,38 @@ AC_CHECK_DECLS([getrandom]) dnl dnl Check for argon2 dnl -AC_MSG_RESULT([Using bundled Argon2 library]) +PHP_ARG_WITH(argon2, for Argon2 support, +[ --with-argon2[=DIR] Include Argon2 support in password_*. DIR is the Argon2 shared library path]]) -LIBS="$LIBS -lpthread" +if test "$PHP_ARGON2" != "no"; then + AC_MSG_CHECKING([for Argon2 library]) + if test "$PHP_ARGON2" = "yes"; then + SEARCH_PATH="/usr /usr/lib /usr/local /usr/local/share /usr/share" + else + SEARCH_PATH="$PHP_ARGON2" + fi + for i in $SEARCH_PATH ; do + if test -r $i/libargon2.so; then + ARGON2_DIR=$i; + AC_MSG_RESULT(found in $i) + fi + done + + if test -z "$ARGON2_DIR"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Please ensure the argon2 headers and static library are installed]) + fi + + PHP_ADD_INCLUDE($ARGON2_DIR/include) + + AC_CHECK_HEADERS([argon2.h]) + AC_CHECK_LIB(argon2, argon2_hash, [ + LIBS="-largon2 $LIBS -largon2" + AC_DEFINE(HAVE_ARGON2LIB, 1, [ Define to 1 if you have the header file ]) + ], [ + AC_MSG_ERROR([Problem with libargon2.(a|so). Please verify that Argon2 header and libaries are installed]) + ]) +fi dnl dnl Setup extension sources @@ -571,10 +600,8 @@ PHP_NEW_EXTENSION(standard, array.c base64.c basic_functions.c browscap.c crc32. http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ filters.c proc_open.c streamsfuncs.c http.c password.c \ - random.c argon2lib/argon2.c argon2lib/core.c argon2lib/blake2/blake2b.c \ - argon2lib/thread.c argon2lib/encoding.c argon2lib/ref.c,,, + random.c,,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_MAKEFILE_FRAGMENT PHP_INSTALL_HEADERS([ext/standard/]) -PHP_INSTALL_HEADERS([ext/standard/argon2lib]) diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index 431dd3e4847..adff3d8c878 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -20,13 +20,10 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \ url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ user_filters.c uuencode.c filters.c proc_open.c password.c \ - streamsfuncs.c http.c flock_compat.c random.c \ - argon2lib/argon2.c argon2lib/core.c argon2lib/blake2/blake2b.c \ - argon2lib/thread.c argon2lib/encoding.c argon2lib/ref.c", false /* never shared */, + streamsfuncs.c http.c flock_compat.c random.c", false /* never shared */, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); PHP_INSTALL_HEADERS("", "ext/standard"); if (PHP_MBREGEX != "no") { CHECK_HEADER_ADD_INCLUDE("oniguruma.h", "CFLAGS_STANDARD", PHP_MBREGEX + ";ext\\mbstring\\oniguruma") } PHP_INSTALL_HEADERS("", "ext/standard"); -PHP_INSTALL_HEADERS([ext/standard/argon2lib]) diff --git a/ext/standard/password.c b/ext/standard/password.c index ab967ee7c4b..1bcb54e3eb4 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -31,7 +31,9 @@ #include "zend_interfaces.h" #include "info.h" #include "php_random.h" -#include "argon2lib/argon2.h" +#if HAVE_ARGON2LIB +#include "argon2.h" +#endif #if PHP_WIN32 #include "win32/winutil.h" @@ -41,14 +43,18 @@ PHP_MINIT_FUNCTION(password) /* {{{ */ { REGISTER_LONG_CONSTANT("PASSWORD_DEFAULT", PHP_PASSWORD_DEFAULT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT", PHP_PASSWORD_BCRYPT, CONST_CS | CONST_PERSISTENT); +#if HAVE_ARGON2LIB REGISTER_LONG_CONSTANT("PASSWORD_ARGON2I", PHP_PASSWORD_ARGON2I, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_ARGON2D", PHP_PASSWORD_ARGON2D, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_ARGON2", PHP_PASSWORD_ARGON2, CONST_CS | CONST_PERSISTENT); +#endif REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT_DEFAULT_COST", PHP_PASSWORD_BCRYPT_COST, CONST_CS | CONST_PERSISTENT); +#if HAVE_ARGON2LIB REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_MEMORY_COST", PHP_PASSWORD_ARGON2_MEMORY_COST, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_TIME_COST", PHP_PASSWORD_ARGON2_TIME_COST, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_THREADS", PHP_PASSWORD_ARGON2_THREADS, CONST_CS | CONST_PERSISTENT); +#endif return SUCCESS; } @@ -59,10 +65,12 @@ static char* php_password_get_algo_name(const php_password_algo algo) switch (algo) { case PHP_PASSWORD_BCRYPT: return "bcrypt"; +#if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: return "argon2i"; case PHP_PASSWORD_ARGON2D: return "argon2d"; +#endif case PHP_PASSWORD_UNKNOWN: default: return "unknown"; @@ -73,11 +81,14 @@ static php_password_algo php_password_determine_algo(const char *hash, const siz { if (len > 3 && hash[0] == '$' && hash[1] == '2' && hash[2] == 'y' && len == 60) { return PHP_PASSWORD_BCRYPT; - } else if (hash[0] == '$' && strstr(hash, "argon2i")) { + } +#if HAVE_ARGON2LIB + if (hash[0] == '$' && strstr(hash, "argon2i")) { return PHP_PASSWORD_ARGON2I; } else if (hash[0] == '$' && strstr(hash, "argon2d")) { return PHP_PASSWORD_ARGON2D; } +#endif return PHP_PASSWORD_UNKNOWN; } @@ -185,6 +196,7 @@ PHP_FUNCTION(password_get_info) add_assoc_long(&options, "cost", cost); } break; +#if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { @@ -199,6 +211,7 @@ PHP_FUNCTION(password_get_info) add_assoc_long(&options, "threads", threads); } break; +#endif case PHP_PASSWORD_UNKNOWN: default: break; @@ -248,6 +261,7 @@ PHP_FUNCTION(password_needs_rehash) } } break; +#if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { @@ -275,6 +289,7 @@ PHP_FUNCTION(password_needs_rehash) } } break; +#endif case PHP_PASSWORD_UNKNOWN: default: break; @@ -300,15 +315,16 @@ PHP_FUNCTION(password_verify) algo = php_password_determine_algo(hash, (size_t) hash_len); switch(algo) { +#if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { argon2_type type = Argon2_i; - if (strstr(hash, "argon2d")) { - type = Argon2_d; - } else if (strstr(hash, "argon2i")) { + if (algo == PHP_PASSWORD_ARGON2I) { type = Argon2_i; + } else if (algo == PHP_PASSWORD_ARGON2D) { + type = Argon2_d; } status = argon2_verify(hash, password, password_len, type); @@ -320,6 +336,7 @@ PHP_FUNCTION(password_verify) RETURN_FALSE; } break; +#endif case PHP_PASSWORD_BCRYPT: case PHP_PASSWORD_UNKNOWN: default: @@ -363,11 +380,12 @@ PHP_FUNCTION(password_hash) HashTable *options = 0; zval *option_buffer; - // Argon2 Options +#if HAVE_ARGON2LIB size_t t_cost = PHP_PASSWORD_ARGON2_TIME_COST; size_t m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; size_t threads = PHP_PASSWORD_ARGON2_THREADS; argon2_type type = Argon2_i; +#endif if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|H", &password, &password_len, &algo, &options) == FAILURE) { return; @@ -392,6 +410,7 @@ PHP_FUNCTION(password_hash) hash_format_len = 7; } break; +#if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { @@ -431,6 +450,7 @@ PHP_FUNCTION(password_hash) required_salt_len = 16; } break; +#endif case PHP_PASSWORD_UNKNOWN: default: php_error_docref(NULL, E_WARNING, "Unknown password hashing algorithm: " ZEND_LONG_FMT, algo); @@ -524,6 +544,8 @@ PHP_FUNCTION(password_hash) RETURN_STR(result); } + break; +#if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { @@ -574,6 +596,8 @@ PHP_FUNCTION(password_hash) RETURN_STR(ret); } + break; +#endif default: RETURN_FALSE; } diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index e3104f7dbd3..a474013af79 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -29,19 +29,23 @@ PHP_FUNCTION(password_get_info); PHP_MINIT_FUNCTION(password); -#define PHP_PASSWORD_ARGON2 PHP_PASSWORD_ARGON2I #define PHP_PASSWORD_DEFAULT PHP_PASSWORD_BCRYPT - #define PHP_PASSWORD_BCRYPT_COST 10 + +#if HAVE_ARGON2LIB +#define PHP_PASSWORD_ARGON2 PHP_PASSWORD_ARGON2I #define PHP_PASSWORD_ARGON2_MEMORY_COST 1<<16 #define PHP_PASSWORD_ARGON2_TIME_COST 3 #define PHP_PASSWORD_ARGON2_THREADS 1 +#endif typedef enum { PHP_PASSWORD_UNKNOWN, PHP_PASSWORD_BCRYPT, +#if HAVE_ARGON2LIB PHP_PASSWORD_ARGON2D, PHP_PASSWORD_ARGON2I +#endif } php_password_algo; #endif diff --git a/ext/standard/tests/password/password_get_info.phpt b/ext/standard/tests/password/password_get_info.phpt index 3e8b665ba27..82365331bf4 100644 --- a/ext/standard/tests/password/password_get_info.phpt +++ b/ext/standard/tests/password/password_get_info.phpt @@ -11,10 +11,6 @@ var_dump(password_get_info('$2y$11$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vj var_dump(password_get_info('$2y$11$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100')); // Test Non-Bcrypt var_dump(password_get_info('$1$rasmusle$rISCgZzpwk3UhDidwXvin0')); -// Test Argon2i -var_dump(password_get_info('$argon2i$v=19$m=65536,t=3,p=1$SWhIcG5MT21Pc01PbWdVZw$WagZELICsz7jlqOR2YzoEVTWb2oOX1tYdnhZYXxptbU')); -// Test Argon2d -var_dump(password_get_info('$argon2d$v=19$m=32768,t=2,p=1$YWpxd0VYRW9MLmp6VjFPZw$pWV5IsbBfjEK5c0bHzvAo0FsDNHUyM4p6j8vf2cxzb8')); echo "OK!"; ?> --EXPECT-- @@ -58,34 +54,4 @@ array(3) { array(0) { } } -array(3) { - ["algo"]=> - int(3) - ["algoName"]=> - string(7) "argon2i" - ["options"]=> - array(3) { - ["m_cost"]=> - int(65536) - ["t_cost"]=> - int(3) - ["threads"]=> - int(1) - } -} -array(3) { - ["algo"]=> - int(2) - ["algoName"]=> - string(7) "argon2d" - ["options"]=> - array(3) { - ["m_cost"]=> - int(32768) - ["t_cost"]=> - int(2) - ["threads"]=> - int(1) - } -} OK! diff --git a/ext/standard/tests/password/password_get_info_argon2.phpt b/ext/standard/tests/password/password_get_info_argon2.phpt new file mode 100644 index 00000000000..c5743ae61f9 --- /dev/null +++ b/ext/standard/tests/password/password_get_info_argon2.phpt @@ -0,0 +1,45 @@ +--TEST-- +Test normal operation of password_get_info() with Argon2 +--SKIPIF-- + +--EXPECT-- +array(3) { + ["algo"]=> + int(3) + ["algoName"]=> + string(7) "argon2i" + ["options"]=> + array(3) { + ["m_cost"]=> + int(65536) + ["t_cost"]=> + int(3) + ["threads"]=> + int(1) + } +} +array(3) { + ["algo"]=> + int(2) + ["algoName"]=> + string(7) "argon2d" + ["options"]=> + array(3) { + ["m_cost"]=> + int(32768) + ["t_cost"]=> + int(2) + ["threads"]=> + int(1) + } +} +OK! \ No newline at end of file diff --git a/ext/standard/tests/password/password_hash.phpt b/ext/standard/tests/password/password_hash.phpt index 665ead92caa..47335c376a4 100644 --- a/ext/standard/tests/password/password_hash.phpt +++ b/ext/standard/tests/password/password_hash.phpt @@ -10,27 +10,9 @@ $hash = password_hash("foo", PASSWORD_BCRYPT); var_dump($hash === crypt("foo", $hash)); -$hash = password_hash('foo', PASSWORD_ARGON2); -var_dump(strlen($hash)); -var_dump(password_verify('foo', $hash)); - -$hash = password_hash('foo', PASSWORD_ARGON2I); -var_dump(strlen($hash)); -var_dump(password_verify('foo', $hash)); - -$hash = password_hash('foo', PASSWORD_ARGON2D); -var_dump(strlen($hash)); -var_dump(password_verify('foo', $hash)); - echo "OK!"; ?> --EXPECT-- int(60) bool(true) -int(99) -bool(true) -int(99) -bool(true) -int(99) -bool(true) OK! diff --git a/ext/standard/tests/password/password_hash_argon2.phpt b/ext/standard/tests/password/password_hash_argon2.phpt new file mode 100644 index 00000000000..af9e08e7f0a --- /dev/null +++ b/ext/standard/tests/password/password_hash_argon2.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test normal operation of password_hash() with argon2 +--SKIPIF-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +OK! \ No newline at end of file diff --git a/ext/standard/tests/password/password_hash_error.phpt b/ext/standard/tests/password/password_hash_error.phpt index 9207fb76efa..5fa593158df 100644 --- a/ext/standard/tests/password/password_hash_error.phpt +++ b/ext/standard/tests/password/password_hash_error.phpt @@ -20,13 +20,6 @@ var_dump(password_hash("123", PASSWORD_BCRYPT, array("salt" => array()))); /* Non-string salt, checking for memory leaks */ var_dump(password_hash('123', PASSWORD_BCRYPT, array('salt' => 1234))); - -var_dump(password_hash('test', PASSWORD_ARGON2, ['m_cost' => 0])); - -var_dump(password_hash('test', PASSWORD_ARGON2, ['t_cost' => 0])); - -var_dump(password_hash('test', PASSWORD_ARGON2, ['threads' => 0])); - ?> --EXPECTF-- Warning: password_hash() expects at least 2 parameters, 0 given in %s on line %d @@ -57,12 +50,3 @@ Deprecated: password_hash(): Use of the 'salt' option to password_hash is deprec Warning: password_hash(): Provided salt is too short: 4 expecting 22 in %s on line %d NULL -Warning: password_hash(): Memory cost is outside of allowed memory range in %s on line %d -NULL - -Warning: password_hash(): Time cost is outside of allowed time range in %s on line %d -NULL - -Warning: password_hash(): Invalid number of threads in %s on line %d -NULL - diff --git a/ext/standard/tests/password/password_hash_error_argon2.phpt b/ext/standard/tests/password/password_hash_error_argon2.phpt new file mode 100644 index 00000000000..6b24ee9ef74 --- /dev/null +++ b/ext/standard/tests/password/password_hash_error_argon2.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test error operation of password_hash() with argon2 +--SKIPIF-- + 0])); +var_dump(password_hash('test', PASSWORD_ARGON2, ['t_cost' => 0])); +var_dump(password_hash('test', PASSWORD_ARGON2, ['threads' => 0])); +?> +--EXPECTF-- +Warning: password_hash(): Memory cost is outside of allowed memory range in %s on line %d +NULL + +Warning: password_hash(): Time cost is outside of allowed time range in %s on line %d +NULL + +Warning: password_hash(): Invalid number of threads in %s on line %d +NULL \ No newline at end of file diff --git a/ext/standard/tests/password/password_needs_rehash.phpt b/ext/standard/tests/password/password_needs_rehash.phpt index b38c1dde20a..8d3582f76cd 100644 --- a/ext/standard/tests/password/password_needs_rehash.phpt +++ b/ext/standard/tests/password/password_needs_rehash.phpt @@ -28,10 +28,6 @@ var_dump(password_needs_rehash('$2y$'.$cost.'$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.o // Should Issue Needs Rehash, Since Foo is cast to 0... var_dump(password_needs_rehash('$2y$10$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100y', PASSWORD_BCRYPT, array('cost' => 'foo'))); - -var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['m_cost' => 1<<17])); -var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['t_cost' => 2])); -var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['threads' => 2])); echo "OK!"; ?> --EXPECT-- @@ -43,7 +39,4 @@ bool(true) bool(true) bool(false) bool(true) -bool(true) -bool(true) -bool(true) OK! diff --git a/ext/standard/tests/password/password_needs_rehash_argon2.phpt b/ext/standard/tests/password/password_needs_rehash_argon2.phpt new file mode 100644 index 00000000000..6393cb7f3eb --- /dev/null +++ b/ext/standard/tests/password/password_needs_rehash_argon2.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test normal operation of password_needs_rehash() with argon2 +--SKIPIF-- + 1<<17])); +var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['t_cost' => 2])); +var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['threads' => 2])); +echo "OK!"; +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +OK! diff --git a/ext/standard/tests/password/password_verify.phpt b/ext/standard/tests/password/password_verify.phpt index 0e85413a352..0e4be8d07c0 100644 --- a/ext/standard/tests/password/password_verify.phpt +++ b/ext/standard/tests/password/password_verify.phpt @@ -18,13 +18,6 @@ var_dump(password_verify("rasmuslerdorf", "rl.3StKT.4T8M")); var_dump(password_verify("foo", "$1")); -var_dump(password_verify('test', '$argon2d$v=19$m=32768,t=2,p=1$YWpxd0VYRW9MLmp6VjFPZw$pWV5IsbBfjEK5c0bHzvAo0FsDNHUyM4p6j8vf2cxzb8')); - -var_dump(password_verify('argon2', '$argon2d$v=19$m=32768,t=2,p=1$YWpxd0VYRW9MLmp6VjFPZw$pWV5IsbBfjEK5c0bHzvAo0FsDNHUyM4p6j8vf2cxzb8')); - -var_dump(password_verify('test', '$argon2i$v=19$m=65536,t=3,p=1$OEVjWWs2Z3YvWlNZQ0ZmNw$JKin7ahjmh8JYvMyFcXri0Ss/Uvd3uYpD7MG6C/5Cy0')); - -var_dump(password_verify('argon2', '$argon2i$v=19$m=65536,t=3,p=1$OEVjWWs2Z3YvWlNZQ0ZmNw$JKin7ahjmh8JYvMyFcXri0Ss/Uvd3uYpD7MG6C/5Cy0')); echo "OK!"; ?> --EXPECT-- @@ -35,8 +28,4 @@ bool(true) bool(false) bool(true) bool(false) -bool(true) -bool(false) -bool(true) -bool(false) OK! \ No newline at end of file diff --git a/ext/standard/tests/password/password_verify_argon2.phpt b/ext/standard/tests/password/password_verify_argon2.phpt new file mode 100644 index 00000000000..e5afce424ca --- /dev/null +++ b/ext/standard/tests/password/password_verify_argon2.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test normal operation of password_verify() with argon2 +--SKIPIF-- + +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(false) +OK! \ No newline at end of file From 9f37be5c43604a30a60de9a2b7b4ebd5d233c72c Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Mon, 11 Jul 2016 18:39:04 -0500 Subject: [PATCH 08/18] Fixing failing tests for Argon2 - Added "Skipped:" flag so argon2 tests would be skipped when PHP is compiled without Argon2 support --- ext/standard/tests/password/password_get_info_argon2.phpt | 3 ++- ext/standard/tests/password/password_hash_argon2.phpt | 2 +- ext/standard/tests/password/password_hash_error_argon2.phpt | 3 ++- ext/standard/tests/password/password_needs_rehash_argon2.phpt | 3 ++- ext/standard/tests/password/password_verify_argon2.phpt | 4 ++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ext/standard/tests/password/password_get_info_argon2.phpt b/ext/standard/tests/password/password_get_info_argon2.phpt index c5743ae61f9..d756977d7b8 100644 --- a/ext/standard/tests/password/password_get_info_argon2.phpt +++ b/ext/standard/tests/password/password_get_info_argon2.phpt @@ -2,7 +2,8 @@ Test normal operation of password_get_info() with Argon2 --SKIPIF-- --FILE-- --FILE-- 0])); diff --git a/ext/standard/tests/password/password_needs_rehash_argon2.phpt b/ext/standard/tests/password/password_needs_rehash_argon2.phpt index 6393cb7f3eb..478f923f21e 100644 --- a/ext/standard/tests/password/password_needs_rehash_argon2.phpt +++ b/ext/standard/tests/password/password_needs_rehash_argon2.phpt @@ -2,7 +2,8 @@ Test normal operation of password_needs_rehash() with argon2 --SKIPIF-- --FILE-- 1<<17])); diff --git a/ext/standard/tests/password/password_verify_argon2.phpt b/ext/standard/tests/password/password_verify_argon2.phpt index e5afce424ca..ec174d3603c 100644 --- a/ext/standard/tests/password/password_verify_argon2.phpt +++ b/ext/standard/tests/password/password_verify_argon2.phpt @@ -2,11 +2,11 @@ Test normal operation of password_verify() with argon2 --SKIPIF-- --FILE-- Date: Mon, 11 Jul 2016 22:12:27 -0500 Subject: [PATCH 09/18] Adding Windows build flag for --with-argon2 --- ext/standard/config.w32 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index adff3d8c878..c24f8aa63d9 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -1,6 +1,18 @@ // vim:ft=javascript // $Id$ +ARG_WITH("argon2", "Argon2 support", "no"); + +if (PHP_ARGON2 != "no") { + if (CHECK_LIB("Argon2Ref.lib", "argon2", PHP_ARGON2) + && CHECK_HEADER_ADD_INCLUDE("argon2.h", "CFLAGS_ARGON2")) { + AC_DEFINE('HAVE_ARGON2LIB', 1); + EXTENSION("argon2", null, false); + } else { + WARNING("Argon2 not enabled; libaries and headers not found"); + } +} + ARG_WITH("config-file-scan-dir", "Dir to check for additional php ini files", ""); AC_DEFINE("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR); From f4aa3a465b248f0e0db970f882e6cd39968a2057 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Mon, 11 Jul 2016 23:13:07 -0500 Subject: [PATCH 10/18] Fixing linker issue on linux when DIR is specified on --with-argon2 --- ext/standard/config.m4 | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index f0dc00512ce..8cf64a5550c 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -558,28 +558,24 @@ PHP_ARG_WITH(argon2, for Argon2 support, if test "$PHP_ARGON2" != "no"; then AC_MSG_CHECKING([for Argon2 library]) - if test "$PHP_ARGON2" = "yes"; then - SEARCH_PATH="/usr /usr/lib /usr/local /usr/local/share /usr/share" - else - SEARCH_PATH="$PHP_ARGON2" - fi - for i in $SEARCH_PATH ; do - if test -r $i/libargon2.so; then + for i in $PHP_ARGON2 /usr /usr/local ; do + if test -r $i/include/argon2.h; then ARGON2_DIR=$i; AC_MSG_RESULT(found in $i) + break fi done if test -z "$ARGON2_DIR"; then AC_MSG_RESULT([not found]) - AC_MSG_ERROR([Please ensure the argon2 headers and static library are installed]) + AC_MSG_ERROR([Please ensure the argon2 header and library are installed]) fi - + + PHP_ADD_LIBRARY_WITH_PATH(argon2, $ARGON2_DIR) PHP_ADD_INCLUDE($ARGON2_DIR/include) - AC_CHECK_HEADERS([argon2.h]) AC_CHECK_LIB(argon2, argon2_hash, [ - LIBS="-largon2 $LIBS -largon2" + LIBS="$LIBS -largon2" AC_DEFINE(HAVE_ARGON2LIB, 1, [ Define to 1 if you have the header file ]) ], [ AC_MSG_ERROR([Problem with libargon2.(a|so). Please verify that Argon2 header and libaries are installed]) From 9bedcb7a618f9742ec75cd723867411ede1f305d Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Tue, 12 Jul 2016 10:24:11 -0500 Subject: [PATCH 11/18] Adding to PHP library includes --- ext/standard/config.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 8cf64a5550c..8352fe234fb 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -571,7 +571,7 @@ if test "$PHP_ARGON2" != "no"; then AC_MSG_ERROR([Please ensure the argon2 header and library are installed]) fi - PHP_ADD_LIBRARY_WITH_PATH(argon2, $ARGON2_DIR) + PHP_ADD_LIBRARY_WITH_PATH(argon2, $ARGON2_DIR/$PHP_LIBDIR) PHP_ADD_INCLUDE($ARGON2_DIR/include) AC_CHECK_LIB(argon2, argon2_hash, [ From 1c954c95494a9f73531624df65212e981df0836d Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Tue, 12 Jul 2016 16:38:49 -0500 Subject: [PATCH 12/18] Untouching old tests --- ext/standard/tests/password/password_get_info.phpt | 1 + ext/standard/tests/password/password_hash.phpt | 2 +- ext/standard/tests/password/password_hash_error.phpt | 2 +- ext/standard/tests/password/password_needs_rehash.phpt | 3 +++ ext/standard/tests/password/password_verify.phpt | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ext/standard/tests/password/password_get_info.phpt b/ext/standard/tests/password/password_get_info.phpt index 82365331bf4..4c8dc04ff80 100644 --- a/ext/standard/tests/password/password_get_info.phpt +++ b/ext/standard/tests/password/password_get_info.phpt @@ -11,6 +11,7 @@ var_dump(password_get_info('$2y$11$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vj var_dump(password_get_info('$2y$11$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100')); // Test Non-Bcrypt var_dump(password_get_info('$1$rasmusle$rISCgZzpwk3UhDidwXvin0')); + echo "OK!"; ?> --EXPECT-- diff --git a/ext/standard/tests/password/password_hash.phpt b/ext/standard/tests/password/password_hash.phpt index 47335c376a4..ebb27292ea2 100644 --- a/ext/standard/tests/password/password_hash.phpt +++ b/ext/standard/tests/password/password_hash.phpt @@ -15,4 +15,4 @@ echo "OK!"; --EXPECT-- int(60) bool(true) -OK! +OK! \ No newline at end of file diff --git a/ext/standard/tests/password/password_hash_error.phpt b/ext/standard/tests/password/password_hash_error.phpt index 5fa593158df..8dc954649db 100644 --- a/ext/standard/tests/password/password_hash_error.phpt +++ b/ext/standard/tests/password/password_hash_error.phpt @@ -20,6 +20,7 @@ var_dump(password_hash("123", PASSWORD_BCRYPT, array("salt" => array()))); /* Non-string salt, checking for memory leaks */ var_dump(password_hash('123', PASSWORD_BCRYPT, array('salt' => 1234))); + ?> --EXPECTF-- Warning: password_hash() expects at least 2 parameters, 0 given in %s on line %d @@ -49,4 +50,3 @@ Deprecated: password_hash(): Use of the 'salt' option to password_hash is deprec Warning: password_hash(): Provided salt is too short: 4 expecting 22 in %s on line %d NULL - diff --git a/ext/standard/tests/password/password_needs_rehash.phpt b/ext/standard/tests/password/password_needs_rehash.phpt index 8d3582f76cd..8efd0add8f3 100644 --- a/ext/standard/tests/password/password_needs_rehash.phpt +++ b/ext/standard/tests/password/password_needs_rehash.phpt @@ -28,6 +28,9 @@ var_dump(password_needs_rehash('$2y$'.$cost.'$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.o // Should Issue Needs Rehash, Since Foo is cast to 0... var_dump(password_needs_rehash('$2y$10$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100y', PASSWORD_BCRYPT, array('cost' => 'foo'))); + + + echo "OK!"; ?> --EXPECT-- diff --git a/ext/standard/tests/password/password_verify.phpt b/ext/standard/tests/password/password_verify.phpt index 0e4be8d07c0..a196763c136 100644 --- a/ext/standard/tests/password/password_verify.phpt +++ b/ext/standard/tests/password/password_verify.phpt @@ -28,4 +28,4 @@ bool(true) bool(false) bool(true) bool(false) -OK! \ No newline at end of file +OK! From 98722089a0a0f44f7540e7e0f6da0fa1dd56b1fc Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Wed, 13 Jul 2016 07:59:33 -0500 Subject: [PATCH 13/18] Updating config.w32 to correctly add Argon2RefLib to LIBS flag --- ext/standard/config.w32 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index c24f8aa63d9..dc42ebfa512 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -4,10 +4,9 @@ ARG_WITH("argon2", "Argon2 support", "no"); if (PHP_ARGON2 != "no") { - if (CHECK_LIB("Argon2Ref.lib", "argon2", PHP_ARGON2) - && CHECK_HEADER_ADD_INCLUDE("argon2.h", "CFLAGS_ARGON2")) { + if (CHECK_LIB("Argon2Ref.lib", null, PHP_ARGON2) + && CHECK_HEADER_ADD_INCLUDE("argon2.h", "CFLAGS")) { AC_DEFINE('HAVE_ARGON2LIB', 1); - EXTENSION("argon2", null, false); } else { WARNING("Argon2 not enabled; libaries and headers not found"); } From ab837a6a0a12c82afaeecfbbcb81eb9be5183741 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Mon, 18 Jul 2016 13:15:29 -0500 Subject: [PATCH 14/18] Fixing potential memory leak with encoded in password_hash Using zend_string_alloc instead of char* for out and encoded variables --- ext/standard/password.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/ext/standard/password.c b/ext/standard/password.c index 1bcb54e3eb4..d99593128ba 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -83,9 +83,9 @@ static php_password_algo php_password_determine_algo(const char *hash, const siz return PHP_PASSWORD_BCRYPT; } #if HAVE_ARGON2LIB - if (hash[0] == '$' && strstr(hash, "argon2i")) { - return PHP_PASSWORD_ARGON2I; - } else if (hash[0] == '$' && strstr(hash, "argon2d")) { + if (len >= sizeof("$argon2i$")-1 && !memcmp(hash, "$argon2i$", sizeof("$argon2i$")-1)) { + return PHP_PASSWORD_ARGON2I; + } else if (len >= sizeof("$argon2d$")-1 && !memcmp(hash, "$argon2d$", sizeof("$argon2d$")-1)) { return PHP_PASSWORD_ARGON2D; } #endif @@ -549,9 +549,6 @@ PHP_FUNCTION(password_hash) case PHP_PASSWORD_ARGON2I: case PHP_PASSWORD_ARGON2D: { - char *out; - char *encoded; - size_t out_len = 32; size_t encoded_len; int status = 0; @@ -564,8 +561,8 @@ PHP_FUNCTION(password_hash) out_len ); - encoded = emalloc(encoded_len + 1); - out = emalloc(out_len + 1); + zend_string *out = zend_string_alloc(out_len, 0); + zend_string *encoded = zend_string_alloc(encoded_len, 0); status = argon2_hash( t_cost, @@ -575,26 +572,24 @@ PHP_FUNCTION(password_hash) password_len, salt, salt_len, - out, + out->val, out_len, - encoded, + encoded->val, encoded_len, type, ARGON2_VERSION_NUMBER ); - zend_string *ret = zend_string_init(encoded, encoded_len, 0); - efree(out); efree(salt); - efree(encoded); if (status != ARGON2_OK) { + efree(encoded); php_error_docref(NULL, E_WARNING, argon2_error_message(status)); RETURN_FALSE; } - RETURN_STR(ret); + RETURN_STR(encoded); } break; #endif From 0d4d8eab53d52ecdeca9b4630aeaa976fed3d6c5 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Mon, 1 Aug 2016 18:53:24 -0500 Subject: [PATCH 15/18] Removing Argon2d, changing config arg to --with-password-argon2 Argon2d is not suitable for password_hashing. To ensure best practices within password_*, Argon2d was removed. --with-argon2 implies the full feature set of Argon2, whereas this feature only implements Argon2i within password_*. Consequently the feature flag was renamed to --with-password-argon2 --- ext/standard/config.m4 | 4 +-- ext/standard/config.w32 | 2 +- ext/standard/password.c | 26 ++----------------- ext/standard/php_password.h | 3 +-- .../password/password_get_info_argon2.phpt | 21 ++------------- .../tests/password/password_hash_argon2.phpt | 4 --- .../password_needs_rehash_argon2.phpt | 10 ++++--- .../password/password_verify_argon2.phpt | 6 ----- 8 files changed, 15 insertions(+), 61 deletions(-) diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 8352fe234fb..0ab96c1f2cd 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -553,8 +553,8 @@ AC_CHECK_DECLS([getrandom]) dnl dnl Check for argon2 dnl -PHP_ARG_WITH(argon2, for Argon2 support, -[ --with-argon2[=DIR] Include Argon2 support in password_*. DIR is the Argon2 shared library path]]) +PHP_ARG_WITH(password-argon2, for Argon2 support, +[ --with-password-argon2[=DIR] Include Argon2 support in password_*. DIR is the Argon2 shared library path]]) if test "$PHP_ARGON2" != "no"; then AC_MSG_CHECKING([for Argon2 library]) diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index dc42ebfa512..87679c3e380 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -1,7 +1,7 @@ // vim:ft=javascript // $Id$ -ARG_WITH("argon2", "Argon2 support", "no"); +ARG_WITH("password-argon2", "Argon2 support", "no"); if (PHP_ARGON2 != "no") { if (CHECK_LIB("Argon2Ref.lib", null, PHP_ARGON2) diff --git a/ext/standard/password.c b/ext/standard/password.c index d99593128ba..ca5c3000f48 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -45,7 +45,6 @@ PHP_MINIT_FUNCTION(password) /* {{{ */ REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT", PHP_PASSWORD_BCRYPT, CONST_CS | CONST_PERSISTENT); #if HAVE_ARGON2LIB REGISTER_LONG_CONSTANT("PASSWORD_ARGON2I", PHP_PASSWORD_ARGON2I, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PASSWORD_ARGON2D", PHP_PASSWORD_ARGON2D, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PASSWORD_ARGON2", PHP_PASSWORD_ARGON2, CONST_CS | CONST_PERSISTENT); #endif @@ -68,8 +67,6 @@ static char* php_password_get_algo_name(const php_password_algo algo) #if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: return "argon2i"; - case PHP_PASSWORD_ARGON2D: - return "argon2d"; #endif case PHP_PASSWORD_UNKNOWN: default: @@ -85,8 +82,6 @@ static php_password_algo php_password_determine_algo(const char *hash, const siz #if HAVE_ARGON2LIB if (len >= sizeof("$argon2i$")-1 && !memcmp(hash, "$argon2i$", sizeof("$argon2i$")-1)) { return PHP_PASSWORD_ARGON2I; - } else if (len >= sizeof("$argon2d$")-1 && !memcmp(hash, "$argon2d$", sizeof("$argon2d$")-1)) { - return PHP_PASSWORD_ARGON2D; } #endif @@ -198,14 +193,13 @@ PHP_FUNCTION(password_get_info) break; #if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: - case PHP_PASSWORD_ARGON2D: { zend_long v = 0; zend_long m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; zend_long t_cost = PHP_PASSWORD_ARGON2_TIME_COST; zend_long threads = PHP_PASSWORD_ARGON2_THREADS; - sscanf(hash, "$%*[argon2id]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &m_cost, &t_cost, &threads); + sscanf(hash, "$%*[argon2i]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &m_cost, &t_cost, &threads); add_assoc_long(&options, "m_cost", m_cost); add_assoc_long(&options, "t_cost", t_cost); add_assoc_long(&options, "threads", threads); @@ -263,7 +257,6 @@ PHP_FUNCTION(password_needs_rehash) break; #if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: - case PHP_PASSWORD_ARGON2D: { zend_long v = 0; zend_long new_m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST, m_cost = 0; @@ -282,7 +275,7 @@ PHP_FUNCTION(password_needs_rehash) new_threads = zval_get_long(option_buffer); } - sscanf(hash, "$%*[argon2id]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &m_cost, &t_cost, &threads); + sscanf(hash, "$%*[argon2i]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &m_cost, &t_cost, &threads); if (new_t_cost != t_cost || new_m_cost != m_cost || new_threads != threads) { RETURN_TRUE; @@ -317,16 +310,9 @@ PHP_FUNCTION(password_verify) switch(algo) { #if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: - case PHP_PASSWORD_ARGON2D: { argon2_type type = Argon2_i; - if (algo == PHP_PASSWORD_ARGON2I) { - type = Argon2_i; - } else if (algo == PHP_PASSWORD_ARGON2D) { - type = Argon2_d; - } - status = argon2_verify(hash, password, password_len, type); if (status == ARGON2_OK) { @@ -412,7 +398,6 @@ PHP_FUNCTION(password_hash) break; #if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: - case PHP_PASSWORD_ARGON2D: { if (options && (option_buffer = zend_hash_str_find(options, "m_cost", sizeof("m_cost")-1)) != NULL) { m_cost = zval_get_long(option_buffer); @@ -441,12 +426,6 @@ PHP_FUNCTION(password_hash) RETURN_NULL(); } - if (algo == PHP_PASSWORD_ARGON2D) { - type = Argon2_d; - } else if (algo == PHP_PASSWORD_ARGON2I) { - type = Argon2_i; - } - required_salt_len = 16; } break; @@ -547,7 +526,6 @@ PHP_FUNCTION(password_hash) break; #if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: - case PHP_PASSWORD_ARGON2D: { size_t out_len = 32; size_t encoded_len; diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index a474013af79..e2d6b4a73e3 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -43,8 +43,7 @@ typedef enum { PHP_PASSWORD_UNKNOWN, PHP_PASSWORD_BCRYPT, #if HAVE_ARGON2LIB - PHP_PASSWORD_ARGON2D, - PHP_PASSWORD_ARGON2I + PHP_PASSWORD_ARGON2I, #endif } php_password_algo; diff --git a/ext/standard/tests/password/password_get_info_argon2.phpt b/ext/standard/tests/password/password_get_info_argon2.phpt index d756977d7b8..67ac8520a7d 100644 --- a/ext/standard/tests/password/password_get_info_argon2.phpt +++ b/ext/standard/tests/password/password_get_info_argon2.phpt @@ -6,16 +6,14 @@ if (!defined('PASSWORD_ARGON2')) die('Skipped: password_get_info not built with ?> --FILE-- --EXPECT-- array(3) { ["algo"]=> - int(3) + int(2) ["algoName"]=> string(7) "argon2i" ["options"]=> @@ -28,19 +26,4 @@ array(3) { int(1) } } -array(3) { - ["algo"]=> - int(2) - ["algoName"]=> - string(7) "argon2d" - ["options"]=> - array(3) { - ["m_cost"]=> - int(32768) - ["t_cost"]=> - int(2) - ["threads"]=> - int(1) - } -} OK! \ No newline at end of file diff --git a/ext/standard/tests/password/password_hash_argon2.phpt b/ext/standard/tests/password/password_hash_argon2.phpt index 87e42d33964..02d239c0cd0 100644 --- a/ext/standard/tests/password/password_hash_argon2.phpt +++ b/ext/standard/tests/password/password_hash_argon2.phpt @@ -14,13 +14,9 @@ var_dump(password_verify($password, $hash)); $hash = password_hash($password, PASSWORD_ARGON2I); var_dump(password_verify($password, $hash)); -$hash = password_hash($password, PASSWORD_ARGON2D); -var_dump(password_verify($password, $hash)); - echo "OK!"; ?> --EXPECT-- bool(true) bool(true) -bool(true) OK! \ No newline at end of file diff --git a/ext/standard/tests/password/password_needs_rehash_argon2.phpt b/ext/standard/tests/password/password_needs_rehash_argon2.phpt index 478f923f21e..315fe1f6a1d 100644 --- a/ext/standard/tests/password/password_needs_rehash_argon2.phpt +++ b/ext/standard/tests/password/password_needs_rehash_argon2.phpt @@ -6,12 +6,16 @@ if (!defined('PASSWORD_ARGON2')) die('Skipped: password_get_info not built with ?> --FILE-- 1<<17])); -var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['t_cost' => 2])); -var_dump(password_needs_rehash('$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0', PASSWORD_ARGON2, ['threads' => 2])); + +$hash = '$argon2i$v=19$m=65536,t=3,p=1$YkprUktYN0lHQTd2bWRFeA$79aA+6IvgclpDAJVoezProlqzIPy7do/P0sBDXS9Nn0'; +var_dump(password_needs_rehash($hash, PASSWORD_ARGON2)); +var_dump(password_needs_rehash($hash, PASSWORD_ARGON2, ['m_cost' => 1<<17])); +var_dump(password_needs_rehash($hash, PASSWORD_ARGON2, ['t_cost' => 2])); +var_dump(password_needs_rehash($hash, PASSWORD_ARGON2, ['threads' => 2])); echo "OK!"; ?> --EXPECT-- +bool(false) bool(true) bool(true) bool(true) diff --git a/ext/standard/tests/password/password_verify_argon2.phpt b/ext/standard/tests/password/password_verify_argon2.phpt index ec174d3603c..557e7372f8a 100644 --- a/ext/standard/tests/password/password_verify_argon2.phpt +++ b/ext/standard/tests/password/password_verify_argon2.phpt @@ -7,10 +7,6 @@ if (!defined('PASSWORD_ARGON2')) die('Skipped: password_get_info not built with --FILE-- Date: Mon, 1 Aug 2016 19:03:34 -0500 Subject: [PATCH 16/18] Fixing issue with config.m4 script not correctly checking for PHP_PASSWORD_ARGON2 --- ext/standard/config.m4 | 4 ++-- ext/standard/config.w32 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 0ab96c1f2cd..0b407ca27cf 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -556,9 +556,9 @@ dnl PHP_ARG_WITH(password-argon2, for Argon2 support, [ --with-password-argon2[=DIR] Include Argon2 support in password_*. DIR is the Argon2 shared library path]]) -if test "$PHP_ARGON2" != "no"; then +if test "$PHP_PASSWORD_ARGON2" != "no"; then AC_MSG_CHECKING([for Argon2 library]) - for i in $PHP_ARGON2 /usr /usr/local ; do + for i in $PHP_PASSWORD_ARGON2 /usr /usr/local ; do if test -r $i/include/argon2.h; then ARGON2_DIR=$i; AC_MSG_RESULT(found in $i) diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index 87679c3e380..b752d9cb8c3 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -3,8 +3,8 @@ ARG_WITH("password-argon2", "Argon2 support", "no"); -if (PHP_ARGON2 != "no") { - if (CHECK_LIB("Argon2Ref.lib", null, PHP_ARGON2) +if (PHP_PASSWORD_ARGON2 != "no") { + if (CHECK_LIB("Argon2Ref.lib", null, PHP_PASSWORD_ARGON2) && CHECK_HEADER_ADD_INCLUDE("argon2.h", "CFLAGS")) { AC_DEFINE('HAVE_ARGON2LIB', 1); } else { From 0e3b3b031fde75f660b57d3af685c0e7f1ac1f02 Mon Sep 17 00:00:00 2001 From: "Charles R. Portwood II" Date: Fri, 5 Aug 2016 13:26:21 -0500 Subject: [PATCH 17/18] Changing m_cost and t_cost to memory_cost and time_cost - Updating tests - Adjusting cost factors: - memory_cost = 1 MiB - time_cost = 2 - threads = 2 --- ext/standard/password.c | 55 +++++++++---------- ext/standard/php_password.h | 7 +-- .../password/password_get_info_argon2.phpt | 6 +- .../tests/password/password_hash_argon2.phpt | 6 +- .../password/password_hash_error_argon2.phpt | 8 +-- .../password_needs_rehash_argon2.phpt | 10 ++-- .../password/password_verify_argon2.phpt | 2 +- 7 files changed, 44 insertions(+), 50 deletions(-) diff --git a/ext/standard/password.c b/ext/standard/password.c index ca5c3000f48..117db2bf164 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -45,7 +45,6 @@ PHP_MINIT_FUNCTION(password) /* {{{ */ REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT", PHP_PASSWORD_BCRYPT, CONST_CS | CONST_PERSISTENT); #if HAVE_ARGON2LIB REGISTER_LONG_CONSTANT("PASSWORD_ARGON2I", PHP_PASSWORD_ARGON2I, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PASSWORD_ARGON2", PHP_PASSWORD_ARGON2, CONST_CS | CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT_DEFAULT_COST", PHP_PASSWORD_BCRYPT_COST, CONST_CS | CONST_PERSISTENT); @@ -195,13 +194,13 @@ PHP_FUNCTION(password_get_info) case PHP_PASSWORD_ARGON2I: { zend_long v = 0; - zend_long m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; - zend_long t_cost = PHP_PASSWORD_ARGON2_TIME_COST; + zend_long memory_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; + zend_long time_cost = PHP_PASSWORD_ARGON2_TIME_COST; zend_long threads = PHP_PASSWORD_ARGON2_THREADS; - sscanf(hash, "$%*[argon2i]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &m_cost, &t_cost, &threads); - add_assoc_long(&options, "m_cost", m_cost); - add_assoc_long(&options, "t_cost", t_cost); + sscanf(hash, "$%*[argon2i]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &memory_cost, &time_cost, &threads); + add_assoc_long(&options, "memory_cost", memory_cost); + add_assoc_long(&options, "time_cost", time_cost); add_assoc_long(&options, "threads", threads); } break; @@ -259,25 +258,25 @@ PHP_FUNCTION(password_needs_rehash) case PHP_PASSWORD_ARGON2I: { zend_long v = 0; - zend_long new_m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST, m_cost = 0; - zend_long new_t_cost = PHP_PASSWORD_ARGON2_TIME_COST, t_cost = 0; + zend_long new_memory_cost = PHP_PASSWORD_ARGON2_MEMORY_COST, memory_cost = 0; + zend_long new_time_cost = PHP_PASSWORD_ARGON2_TIME_COST, time_cost = 0; zend_long new_threads = PHP_PASSWORD_ARGON2_THREADS, threads = 0; - if (options && (option_buffer = zend_hash_str_find(options, "m_cost", sizeof("m_cost")-1)) != NULL) { - new_m_cost = zval_get_long(option_buffer); + if (options && (option_buffer = zend_hash_str_find(options, "memory_cost", sizeof("memory_cost")-1)) != NULL) { + new_memory_cost = zval_get_long(option_buffer); } - if (options && (option_buffer = zend_hash_str_find(options, "t_cost", sizeof("t_cost")-1)) != NULL) { - new_t_cost = zval_get_long(option_buffer); + if (options && (option_buffer = zend_hash_str_find(options, "time_cost", sizeof("time_cost")-1)) != NULL) { + new_time_cost = zval_get_long(option_buffer); } if (options && (option_buffer = zend_hash_str_find(options, "threads", sizeof("threads")-1)) != NULL) { new_threads = zval_get_long(option_buffer); } - sscanf(hash, "$%*[argon2i]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &m_cost, &t_cost, &threads); + sscanf(hash, "$%*[argon2i]$v=" ZEND_LONG_FMT "$m=" ZEND_LONG_FMT ",t=" ZEND_LONG_FMT ",p=" ZEND_LONG_FMT, &v, &memory_cost, &time_cost, &threads); - if (new_t_cost != t_cost || new_m_cost != m_cost || new_threads != threads) { + if (new_time_cost != time_cost || new_memory_cost != memory_cost || new_threads != threads) { RETURN_TRUE; } } @@ -367,8 +366,8 @@ PHP_FUNCTION(password_hash) zval *option_buffer; #if HAVE_ARGON2LIB - size_t t_cost = PHP_PASSWORD_ARGON2_TIME_COST; - size_t m_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; + size_t time_cost = PHP_PASSWORD_ARGON2_TIME_COST; + size_t memory_cost = PHP_PASSWORD_ARGON2_MEMORY_COST; size_t threads = PHP_PASSWORD_ARGON2_THREADS; argon2_type type = Argon2_i; #endif @@ -399,21 +398,21 @@ PHP_FUNCTION(password_hash) #if HAVE_ARGON2LIB case PHP_PASSWORD_ARGON2I: { - if (options && (option_buffer = zend_hash_str_find(options, "m_cost", sizeof("m_cost")-1)) != NULL) { - m_cost = zval_get_long(option_buffer); + if (options && (option_buffer = zend_hash_str_find(options, "memory_cost", sizeof("memory_cost")-1)) != NULL) { + memory_cost = zval_get_long(option_buffer); } - if (m_cost > ARGON2_MAX_MEMORY || m_cost < ARGON2_MIN_MEMORY) { - php_error_docref(NULL, E_WARNING, "Memory cost is outside of allowed memory range", m_cost); + if (memory_cost > ARGON2_MAX_MEMORY || memory_cost < ARGON2_MIN_MEMORY) { + php_error_docref(NULL, E_WARNING, "Memory cost is outside of allowed memory range", memory_cost); RETURN_NULL(); } - if (options && (option_buffer = zend_hash_str_find(options, "t_cost", sizeof("t_cost")-1)) != NULL) { - t_cost = zval_get_long(option_buffer); + if (options && (option_buffer = zend_hash_str_find(options, "time_cost", sizeof("time_cost")-1)) != NULL) { + time_cost = zval_get_long(option_buffer); } - if (t_cost > ARGON2_MAX_TIME || t_cost < ARGON2_MIN_TIME) { - php_error_docref(NULL, E_WARNING, "Time cost is outside of allowed time range", t_cost); + if (time_cost > ARGON2_MAX_TIME || time_cost < ARGON2_MIN_TIME) { + php_error_docref(NULL, E_WARNING, "Time cost is outside of allowed time range", time_cost); RETURN_NULL(); } @@ -532,8 +531,8 @@ PHP_FUNCTION(password_hash) int status = 0; encoded_len = argon2_encodedlen( - t_cost, - m_cost, + time_cost, + memory_cost, threads, (uint32_t)salt_len, out_len @@ -543,8 +542,8 @@ PHP_FUNCTION(password_hash) zend_string *encoded = zend_string_alloc(encoded_len, 0); status = argon2_hash( - t_cost, - m_cost, + time_cost, + memory_cost, threads, password, password_len, diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h index e2d6b4a73e3..4bc2e5660f2 100644 --- a/ext/standard/php_password.h +++ b/ext/standard/php_password.h @@ -33,10 +33,9 @@ PHP_MINIT_FUNCTION(password); #define PHP_PASSWORD_BCRYPT_COST 10 #if HAVE_ARGON2LIB -#define PHP_PASSWORD_ARGON2 PHP_PASSWORD_ARGON2I -#define PHP_PASSWORD_ARGON2_MEMORY_COST 1<<16 -#define PHP_PASSWORD_ARGON2_TIME_COST 3 -#define PHP_PASSWORD_ARGON2_THREADS 1 +#define PHP_PASSWORD_ARGON2_MEMORY_COST 1<<10 +#define PHP_PASSWORD_ARGON2_TIME_COST 2 +#define PHP_PASSWORD_ARGON2_THREADS 2 #endif typedef enum { diff --git a/ext/standard/tests/password/password_get_info_argon2.phpt b/ext/standard/tests/password/password_get_info_argon2.phpt index 67ac8520a7d..903f9faca52 100644 --- a/ext/standard/tests/password/password_get_info_argon2.phpt +++ b/ext/standard/tests/password/password_get_info_argon2.phpt @@ -2,7 +2,7 @@ Test normal operation of password_get_info() with Argon2 --SKIPIF-- --FILE-- array(3) { - ["m_cost"]=> + ["memory_cost"]=> int(65536) - ["t_cost"]=> + ["time_cost"]=> int(3) ["threads"]=> int(1) diff --git a/ext/standard/tests/password/password_hash_argon2.phpt b/ext/standard/tests/password/password_hash_argon2.phpt index 02d239c0cd0..229d26fcae4 100644 --- a/ext/standard/tests/password/password_hash_argon2.phpt +++ b/ext/standard/tests/password/password_hash_argon2.phpt @@ -2,15 +2,12 @@ Test normal operation of password_hash() with argon2 --SKIPIF-- --EXPECT-- bool(true) -bool(true) OK! \ No newline at end of file diff --git a/ext/standard/tests/password/password_hash_error_argon2.phpt b/ext/standard/tests/password/password_hash_error_argon2.phpt index 60496447a26..cce3c61c122 100644 --- a/ext/standard/tests/password/password_hash_error_argon2.phpt +++ b/ext/standard/tests/password/password_hash_error_argon2.phpt @@ -2,13 +2,13 @@ Test error operation of password_hash() with argon2 --SKIPIF-- --FILE-- 0])); -var_dump(password_hash('test', PASSWORD_ARGON2, ['t_cost' => 0])); -var_dump(password_hash('test', PASSWORD_ARGON2, ['threads' => 0])); +var_dump(password_hash('test', PASSWORD_ARGON2I, ['memory_cost' => 0])); +var_dump(password_hash('test', PASSWORD_ARGON2I, ['time_cost' => 0])); +var_dump(password_hash('test', PASSWORD_ARGON2I, ['threads' => 0])); ?> --EXPECTF-- Warning: password_hash(): Memory cost is outside of allowed memory range in %s on line %d diff --git a/ext/standard/tests/password/password_needs_rehash_argon2.phpt b/ext/standard/tests/password/password_needs_rehash_argon2.phpt index 315fe1f6a1d..28592eb80b2 100644 --- a/ext/standard/tests/password/password_needs_rehash_argon2.phpt +++ b/ext/standard/tests/password/password_needs_rehash_argon2.phpt @@ -2,16 +2,16 @@ Test normal operation of password_needs_rehash() with argon2 --SKIPIF-- --FILE-- 1<<17])); -var_dump(password_needs_rehash($hash, PASSWORD_ARGON2, ['t_cost' => 2])); -var_dump(password_needs_rehash($hash, PASSWORD_ARGON2, ['threads' => 2])); +var_dump(password_needs_rehash($hash, PASSWORD_ARGON2I)); +var_dump(password_needs_rehash($hash, PASSWORD_ARGON2I, ['memory_cost' => 1<<17])); +var_dump(password_needs_rehash($hash, PASSWORD_ARGON2I, ['time_cost' => 2])); +var_dump(password_needs_rehash($hash, PASSWORD_ARGON2I, ['threads' => 2])); echo "OK!"; ?> --EXPECT-- diff --git a/ext/standard/tests/password/password_verify_argon2.phpt b/ext/standard/tests/password/password_verify_argon2.phpt index 557e7372f8a..a3caefb09cf 100644 --- a/ext/standard/tests/password/password_verify_argon2.phpt +++ b/ext/standard/tests/password/password_verify_argon2.phpt @@ -2,7 +2,7 @@ Test normal operation of password_verify() with argon2 --SKIPIF-- --FILE-- Date: Sat, 27 Aug 2016 21:57:09 -0500 Subject: [PATCH 18/18] Fixing typo in tests --- ext/standard/tests/password/password_hash_argon2.phpt | 2 +- ext/standard/tests/password/password_hash_error_argon2.phpt | 2 +- ext/standard/tests/password/password_needs_rehash_argon2.phpt | 2 +- ext/standard/tests/password/password_verify_argon2.phpt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/standard/tests/password/password_hash_argon2.phpt b/ext/standard/tests/password/password_hash_argon2.phpt index 229d26fcae4..03fee3978e2 100644 --- a/ext/standard/tests/password/password_hash_argon2.phpt +++ b/ext/standard/tests/password/password_hash_argon2.phpt @@ -2,7 +2,7 @@ Test normal operation of password_hash() with argon2 --SKIPIF-- --FILE-- --FILE-- --FILE--