23 changed files with 4216 additions and 60 deletions
@ -0,0 +1,3 @@
|
||||
these files are copies from ../ios/Classes/ |
||||
they should stay in sync. |
||||
|
@ -0,0 +1,136 @@
|
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include "argon2src/argon2.h" |
||||
|
||||
//extern "C" __attribute__((visibility("default"))) __attribute__((used))
|
||||
int32_t native_add(int32_t x, int32_t y) { |
||||
return x + y; |
||||
} |
||||
//EOF
|
||||
|
||||
#define HASHLEN 32 |
||||
#define SALTLEN 16 |
||||
#define PWD "password" |
||||
|
||||
#define DEBUG 0 |
||||
#define PRINT_DEBUG(fmt, ...) \ |
||||
do { if (DEBUG) printf(fmt, ##__VA_ARGS__); } while (0) |
||||
|
||||
|
||||
// base64 encoding https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/
|
||||
|
||||
size_t b64_encoded_size(size_t inlen) { |
||||
size_t ret; |
||||
|
||||
ret = inlen; |
||||
if (inlen % 3 != 0) |
||||
ret += 3 - (inlen % 3); |
||||
ret /= 3; |
||||
ret *= 4; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
||||
|
||||
char *b64_encode(const unsigned char *in, size_t len) { |
||||
char *out; |
||||
size_t elen; |
||||
size_t i; |
||||
size_t j; |
||||
size_t v; |
||||
|
||||
if (in == NULL || len == 0) |
||||
return NULL; |
||||
|
||||
elen = b64_encoded_size(len); |
||||
out = malloc(elen + 1); |
||||
out[elen] = '\0'; |
||||
|
||||
for (i = 0, j = 0; i < len; i += 3, j += 4) { |
||||
v = in[i]; |
||||
v = i + 1 < len ? v << 8 | in[i + 1] : v << 8; |
||||
v = i + 2 < len ? v << 8 | in[i + 2] : v << 8; |
||||
|
||||
out[j] = b64chars[(v >> 18) & 0x3F]; |
||||
out[j + 1] = b64chars[(v >> 12) & 0x3F]; |
||||
if (i + 1 < len) { |
||||
out[j + 2] = b64chars[(v >> 6) & 0x3F]; |
||||
} else { |
||||
out[j + 2] = '='; |
||||
} |
||||
if (i + 2 < len) { |
||||
out[j + 3] = b64chars[v & 0x3F]; |
||||
} else { |
||||
out[j + 3] = '='; |
||||
} |
||||
} |
||||
|
||||
return out; |
||||
} |
||||
|
||||
|
||||
char *hashStuff(char *hashPwd) { |
||||
uint8_t hash1[HASHLEN]; |
||||
uint8_t salt[SALTLEN]; |
||||
memset(salt, 0x00, SALTLEN); |
||||
|
||||
uint8_t *pwd = (uint8_t *) strdup(PWD); |
||||
uint32_t pwdlen = strlen((char *) pwd); |
||||
|
||||
uint32_t t_cost = 2; // 1-pass computation
|
||||
uint32_t m_cost = (1 << 16); // 64 mebibytes memory usage
|
||||
uint32_t parallelism = 1; // number of threads and lanes
|
||||
argon2i_hash_raw(t_cost, m_cost, parallelism, pwd, pwdlen, salt, SALTLEN, |
||||
hash1, HASHLEN); |
||||
char *b64ret = b64_encode(hash1, HASHLEN); |
||||
return b64ret; |
||||
} |
||||
|
||||
void debugBytes(uint8_t *bytes, int length) { |
||||
PRINT_DEBUG("length: %d -- ", length); |
||||
for (int i = 0; i < length; i++) { |
||||
PRINT_DEBUG("%02x ", bytes[i]); |
||||
} |
||||
} |
||||
|
||||
char *hp_argon2_hash(uint8_t *key, size_t keylen, uint8_t *salt, size_t saltlen, |
||||
uint32_t m_cost, |
||||
uint32_t t_cost /* iterations*/, uint32_t parallelism, |
||||
size_t hashlen, |
||||
uint8_t type, int32_t version) { |
||||
uint8_t hash1[hashlen]; |
||||
PRINT_DEBUG("keylen: %ld, saltlen: %ld, m_cost: %ld, t_cost: %ld, hashlen: %ld, type: %d, version: %02x\n", |
||||
keylen, saltlen, m_cost, t_cost, hashlen, type, version); |
||||
PRINT_DEBUG("key: "); |
||||
|
||||
debugBytes(key, keylen); |
||||
PRINT_DEBUG("\n"); |
||||
|
||||
PRINT_DEBUG("salt: "); |
||||
debugBytes(salt, saltlen); |
||||
PRINT_DEBUG("\n"); |
||||
|
||||
if (type == 0) { |
||||
PRINT_DEBUG("argon2d\n"); |
||||
argon2d_hash_raw(t_cost, m_cost, parallelism, key, keylen, salt, |
||||
saltlen, |
||||
hash1, hashlen); |
||||
} else if (type == 1) { |
||||
argon2i_hash_raw(t_cost, m_cost, parallelism, key, keylen, salt, |
||||
saltlen, |
||||
hash1, hashlen); |
||||
} |
||||
|
||||
PRINT_DEBUG("hash: "); |
||||
debugBytes(hash1, hashlen); |
||||
PRINT_DEBUG("\n"); |
||||
char *b64ret = b64_encode(hash1, hashlen); |
||||
return b64ret; |
||||
} |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
Sources copied from https://github.com/P-H-C/phc-winner-argon2 |
||||
62358ba2123abd17fccf2a108a301d4b52c01a7c |
||||
|
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
|
||||
#include "argon2.h" |
||||
#include "encoding.h" |
||||
#include "core.h" |
||||
|
||||
const char *argon2_type2string(argon2_type type, int uppercase) { |
||||
switch (type) { |
||||
case Argon2_d: |
||||
return uppercase ? "Argon2d" : "argon2d"; |
||||
case Argon2_i: |
||||
return uppercase ? "Argon2i" : "argon2i"; |
||||
case Argon2_id: |
||||
return uppercase ? "Argon2id" : "argon2id"; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
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 && Argon2_id != 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; |
||||
|
||||
if (instance.threads > instance.lanes) { |
||||
instance.threads = instance.lanes; |
||||
} |
||||
|
||||
/* 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 (pwdlen > ARGON2_MAX_PWD_LENGTH) { |
||||
return ARGON2_PWD_TOO_LONG; |
||||
} |
||||
|
||||
if (saltlen > ARGON2_MAX_SALT_LENGTH) { |
||||
return ARGON2_SALT_TOO_LONG; |
||||
} |
||||
|
||||
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) { |
||||
clear_internal_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) { |
||||
clear_internal_memory(out, hashlen); /* wipe buffers if error */ |
||||
clear_internal_memory(encoded, encodedlen); |
||||
free(out); |
||||
return ARGON2_ENCODING_FAIL; |
||||
} |
||||
} |
||||
clear_internal_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); |
||||
} |
||||
|
||||
int argon2id_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_id, |
||||
ARGON2_VERSION_NUMBER); |
||||
} |
||||
|
||||
int argon2id_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_id, |
||||
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 *desired_result = NULL; |
||||
|
||||
int ret = ARGON2_OK; |
||||
|
||||
size_t encoded_len; |
||||
uint32_t max_field_len; |
||||
|
||||
if (pwdlen > ARGON2_MAX_PWD_LENGTH) { |
||||
return ARGON2_PWD_TOO_LONG; |
||||
} |
||||
|
||||
if (encoded == NULL) { |
||||
return ARGON2_DECODING_FAIL; |
||||
} |
||||
|
||||
encoded_len = strlen(encoded); |
||||
if (encoded_len > UINT32_MAX) { |
||||
return ARGON2_DECODING_FAIL; |
||||
} |
||||
|
||||
/* No field can be longer than the encoded length */ |
||||
max_field_len = (uint32_t)encoded_len; |
||||
|
||||
ctx.saltlen = max_field_len; |
||||
ctx.outlen = max_field_len; |
||||
|
||||
ctx.salt = malloc(ctx.saltlen); |
||||
ctx.out = malloc(ctx.outlen); |
||||
if (!ctx.salt || !ctx.out) { |
||||
ret = ARGON2_MEMORY_ALLOCATION_ERROR; |
||||
goto fail; |
||||
} |
||||
|
||||
ctx.pwd = (uint8_t *)pwd; |
||||
ctx.pwdlen = (uint32_t)pwdlen; |
||||
|
||||
ret = decode_string(&ctx, encoded, type); |
||||
if (ret != ARGON2_OK) { |
||||
goto fail; |
||||
} |
||||
|
||||
/* Set aside the desired result, and get a new buffer. */ |
||||
desired_result = ctx.out; |
||||
ctx.out = malloc(ctx.outlen); |
||||
if (!ctx.out) { |
||||
ret = ARGON2_MEMORY_ALLOCATION_ERROR; |
||||
goto fail; |
||||
} |
||||
|
||||
ret = argon2_verify_ctx(&ctx, (char *)desired_result, type); |
||||
if (ret != ARGON2_OK) { |
||||
goto fail; |
||||
} |
||||
|
||||
fail: |
||||
free(ctx.salt); |
||||
free(ctx.out); |
||||
free(desired_result); |
||||
|
||||
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 argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) { |
||||
|
||||
return argon2_verify(encoded, pwd, pwdlen, Argon2_id); |
||||
} |
||||
|
||||
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 argon2id_ctx(argon2_context *context) { |
||||
return argon2_ctx(context, Argon2_id); |
||||
} |
||||
|
||||
int argon2_verify_ctx(argon2_context *context, const char *hash, |
||||
argon2_type type) { |
||||
int ret = argon2_ctx(context, type); |
||||
if (ret != ARGON2_OK) { |
||||
return ret; |
||||
} |
||||
|
||||
if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) { |
||||
return ARGON2_VERIFY_MISMATCH; |
||||
} |
||||
|
||||
return ARGON2_OK; |
||||
} |
||||
|
||||
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); |
||||
} |
||||
|
||||
int argon2id_verify_ctx(argon2_context *context, const char *hash) { |
||||
return argon2_verify_ctx(context, hash, Argon2_id); |
||||
} |
||||
|
||||
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, argon2_type type) { |
||||
return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) + |
||||
numlen(t_cost) + numlen(m_cost) + numlen(parallelism) + |
||||
b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1; |
||||
} |
@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#ifndef ARGON2_H |
||||
#define ARGON2_H |
||||
|
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
#include <limits.h> |
||||
|
||||
#if defined(__cplusplus) |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Symbols visibility control */ |
||||
#ifdef A2_VISCTL |
||||
#define ARGON2_PUBLIC __attribute__((visibility("default"))) |
||||
#define ARGON2_LOCAL __attribute__ ((visibility ("hidden"))) |
||||
#elif _MSC_VER |
||||
#define ARGON2_PUBLIC __declspec(dllexport) |
||||
#define ARGON2_LOCAL |
||||
#else |
||||
#define ARGON2_PUBLIC |
||||
#define ARGON2_LOCAL |
||||
#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) |
||||
|
||||
/* Flags to determine which fields are securely wiped (default = no wipe). */ |
||||
#define ARGON2_DEFAULT_FLAGS UINT32_C(0) |
||||
#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) |
||||
#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) |
||||
|
||||
/* Global flag to determine if we are wiping internal memory buffers. This flag
|
||||
* is defined in core.c and defaults to 1 (wipe internal memory). */ |
||||
extern int FLAG_clear_internal_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_id = 2 |
||||
} 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 gives the string representation of an argon2_type. |
||||
* @param type The argon2_type that we want the string for |
||||
* @param uppercase Whether the string should have the first letter uppercase |
||||
* @return NULL if invalid type, otherwise the string representation. |
||||
*/ |
||||
ARGON2_PUBLIC const char *argon2_type2string(argon2_type type, int uppercase); |
||||
|
||||
/*
|
||||
* 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 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); |
||||
|
||||
ARGON2_PUBLIC int argon2id_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 argon2id_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); |
||||
|
||||
ARGON2_PUBLIC int argon2id_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); |
||||
|
||||
/**
|
||||
* Argon2id: Version of Argon2 where the first half-pass over memory is |
||||
* password-independent, the rest are password-dependent (on the password and |
||||
* salt). OK against side channels (they reduce to 1/2-pass Argon2i), and |
||||
* better with w.r.t. tradeoff attacks (similar to Argon2d). |
||||
***** |
||||
* @param context Pointer to current Argon2 context |
||||
* @return Zero if successful, a non zero error code otherwise |
||||
*/ |
||||
ARGON2_PUBLIC int argon2id_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); |
||||
|
||||
/**
|
||||
* Verify if a given password is correct for Argon2id 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 argon2id_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 |
||||
* @param type The argon2_type that we want the encoded length for |
||||
* @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, argon2_type type); |
||||
|
||||
#if defined(__cplusplus) |
||||
} |
||||
#endif |
||||
|
||||
#endif |
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#ifndef PORTABLE_BLAKE2_IMPL_H |
||||
#define PORTABLE_BLAKE2_IMPL_H |
||||
|
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
|
||||
#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)); |
||||
} |
||||
|
||||
void clear_internal_memory(void *v, size_t n); |
||||
|
||||
#endif |
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#ifndef PORTABLE_BLAKE2_H |
||||
#define PORTABLE_BLAKE2_H |
||||
|
||||
#include "../argon2.h" |
||||
|
||||
#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 */ |
||||
ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen); |
||||
ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, |
||||
size_t keylen); |
||||
ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P); |
||||
ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen); |
||||
ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen); |
||||
|
||||
/* Simple API */ |
||||
ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen, |
||||
const void *key, size_t keylen); |
||||
|
||||
/* Argon2 Team - Begin Code */ |
||||
ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); |
||||
/* Argon2 Team - End Code */ |
||||
|
||||
#if defined(__cplusplus) |
||||
} |
||||
#endif |
||||
|
||||
#endif |
@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
|
||||
#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) { |
||||
clear_internal_memory(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 the key from stack */ |
||||
clear_internal_memory(block, BLAKE2B_BLOCKBYTES); |
||||
} |
||||
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); |
||||
clear_internal_memory(buffer, sizeof(buffer)); |
||||
clear_internal_memory(S->buf, sizeof(S->buf)); |
||||
clear_internal_memory(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: |
||||
clear_internal_memory(&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: |
||||
clear_internal_memory(&blake_state, sizeof(blake_state)); |
||||
return ret; |
||||
#undef TRY |
||||
} |
||||
/* Argon2 Team - End Code */ |
@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#ifndef BLAKE_ROUND_MKA_OPT_H |
||||
#define BLAKE_ROUND_MKA_OPT_H |
||||
|
||||
#include "blake2-impl.h" |
||||
|
||||
#include <emmintrin.h> |
||||
#if defined(__SSSE3__) |
||||
#include <tmmintrin.h> /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */ |
||||
#endif |
||||
|
||||
#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__)) |
||||
#include <x86intrin.h> |
||||
#endif |
||||
|
||||
#if !defined(__AVX512F__) |
||||
#if !defined(__AVX2__) |
||||
#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) |
||||
#else /* __AVX2__ */ |
||||
|
||||
#include <immintrin.h> |
||||
|
||||
#define rotr32(x) _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1)) |
||||
#define rotr24(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10)) |
||||
#define rotr16(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9)) |
||||
#define rotr63(x) _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x))) |
||||
|
||||
#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ |
||||
do { \
|
||||
__m256i ml = _mm256_mul_epu32(A0, B0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
|
||||
D0 = _mm256_xor_si256(D0, A0); \
|
||||
D0 = rotr32(D0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C0, D0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
|
||||
\
|
||||
B0 = _mm256_xor_si256(B0, C0); \
|
||||
B0 = rotr24(B0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(A1, B1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
|
||||
D1 = _mm256_xor_si256(D1, A1); \
|
||||
D1 = rotr32(D1); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C1, D1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
|
||||
\
|
||||
B1 = _mm256_xor_si256(B1, C1); \
|
||||
B1 = rotr24(B1); \
|
||||
} while((void)0, 0); |
||||
|
||||
#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ |
||||
do { \
|
||||
__m256i ml = _mm256_mul_epu32(A0, B0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
|
||||
D0 = _mm256_xor_si256(D0, A0); \
|
||||
D0 = rotr16(D0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C0, D0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
|
||||
B0 = _mm256_xor_si256(B0, C0); \
|
||||
B0 = rotr63(B0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(A1, B1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
|
||||
D1 = _mm256_xor_si256(D1, A1); \
|
||||
D1 = rotr16(D1); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C1, D1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
|
||||
B1 = _mm256_xor_si256(B1, C1); \
|
||||
B1 = rotr63(B1); \
|
||||
} while((void)0, 0); |
||||
|
||||
#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \ |
||||
do { \
|
||||
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
\
|
||||
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
} while((void)0, 0); |
||||
|
||||
#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \ |
||||
do { \
|
||||
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
|
||||
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
|
||||
B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
\
|
||||
tmp1 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = tmp1; \
|
||||
\
|
||||
tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \
|
||||
tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \
|
||||
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
} while(0); |
||||
|
||||
#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \ |
||||
do { \
|
||||
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
\
|
||||
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
} while((void)0, 0); |
||||
|
||||
#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \ |
||||
do { \
|
||||
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
|
||||
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
|
||||
B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
\
|
||||
tmp1 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = tmp1; \
|
||||
\
|
||||
tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \
|
||||
tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \
|
||||
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
} while((void)0, 0); |
||||
|
||||
#define BLAKE2_ROUND_1(A0, A1, B0, B1, C0, C1, D0, D1) \ |
||||
do{ \
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
\
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
} while((void)0, 0); |
||||
|
||||
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \ |
||||
do{ \
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
} while((void)0, 0); |
||||
|
||||
#endif /* __AVX2__ */ |
||||
|
||||
#else /* __AVX512F__ */ |
||||
|
||||
#include <immintrin.h> |
||||
|
||||
#define ror64(x, n) _mm512_ror_epi64((x), (n)) |
||||
|
||||
static __m512i muladd(__m512i x, __m512i y) |
||||
{ |
||||
__m512i z = _mm512_mul_epu32(x, y); |
||||
return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z)); |
||||
} |
||||
|
||||
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ |
||||
do { \
|
||||
A0 = muladd(A0, B0); \
|
||||
A1 = muladd(A1, B1); \
|
||||
\
|
||||
D0 = _mm512_xor_si512(D0, A0); \
|
||||
D1 = _mm512_xor_si512(D1, A1); \
|
||||
\
|
||||
D0 = ror64(D0, 32); \
|
||||
D1 = ror64(D1, 32); \
|
||||
\
|
||||
C0 = muladd(C0, D0); \
|
||||
C1 = muladd(C1, D1); \
|
||||
\
|
||||
B0 = _mm512_xor_si512(B0, C0); \
|
||||
B1 = _mm512_xor_si512(B1, C1); \
|
||||
\
|
||||
B0 = ror64(B0, 24); \
|
||||
B1 = ror64(B1, 24); \
|
||||
} while ((void)0, 0) |
||||
|
||||
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ |
||||
do { \
|
||||
A0 = muladd(A0, B0); \
|
||||
A1 = muladd(A1, B1); \
|
||||
\
|
||||
D0 = _mm512_xor_si512(D0, A0); \
|
||||
D1 = _mm512_xor_si512(D1, A1); \
|
||||
\
|
||||
D0 = ror64(D0, 16); \
|
||||
D1 = ror64(D1, 16); \
|
||||
\
|
||||
C0 = muladd(C0, D0); \
|
||||
C1 = muladd(C1, D1); \
|
||||
\
|
||||
B0 = _mm512_xor_si512(B0, C0); \
|
||||
B1 = _mm512_xor_si512(B1, C1); \
|
||||
\
|
||||
B0 = ror64(B0, 63); \
|
||||
B1 = ror64(B1, 63); \
|
||||
} while ((void)0, 0) |
||||
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ |
||||
do { \
|
||||
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
\
|
||||
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
\
|
||||
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
} while ((void)0, 0) |
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ |
||||
do { \
|
||||
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
\
|
||||
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
\
|
||||
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
} while ((void)0, 0) |
||||
|
||||
#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, 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) |
||||
|
||||
#define SWAP_HALVES(A0, A1) \ |
||||
do { \
|
||||
__m512i t0, t1; \
|
||||
t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \
|
||||
t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \
|
||||
A0 = t0; \
|
||||
A1 = t1; \
|
||||
} while((void)0, 0) |
||||
|
||||
#define SWAP_QUARTERS(A0, A1) \ |
||||
do { \
|
||||
SWAP_HALVES(A0, A1); \
|
||||
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
|
||||
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
|
||||
} while((void)0, 0) |
||||
|
||||
#define UNSWAP_QUARTERS(A0, A1) \ |
||||
do { \
|
||||
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
|
||||
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
|
||||
SWAP_HALVES(A0, A1); \
|
||||
} while((void)0, 0) |
||||
|
||||
#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \ |
||||
do { \
|
||||
SWAP_HALVES(A0, B0); \
|
||||
SWAP_HALVES(C0, D0); \
|
||||
SWAP_HALVES(A1, B1); \
|
||||
SWAP_HALVES(C1, D1); \
|
||||
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
SWAP_HALVES(A0, B0); \
|
||||
SWAP_HALVES(C0, D0); \
|
||||
SWAP_HALVES(A1, B1); \
|
||||
SWAP_HALVES(C1, D1); \
|
||||
} while ((void)0, 0) |
||||
|
||||
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \ |
||||
do { \
|
||||
SWAP_QUARTERS(A0, A1); \
|
||||
SWAP_QUARTERS(B0, B1); \
|
||||
SWAP_QUARTERS(C0, C1); \
|
||||
SWAP_QUARTERS(D0, D1); \
|
||||
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
UNSWAP_QUARTERS(A0, A1); \
|
||||
UNSWAP_QUARTERS(B0, B1); \
|
||||
UNSWAP_QUARTERS(C0, C1); \
|
||||
UNSWAP_QUARTERS(D0, D1); \
|
||||
} while ((void)0, 0) |
||||
|
||||
#endif /* __AVX512F__ */ |
||||
#endif /* BLAKE_ROUND_MKA_OPT_H */ |
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#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 |
@ -0,0 +1,648 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
/*For memory wiping*/ |
||||
#ifdef _MSC_VER |
||||
#include <windows.h> |
||||
#include <winbase.h> /* For SecureZeroMemory */ |
||||
#endif |
||||
#if defined __STDC_LIB_EXT1__ |
||||
#define __STDC_WANT_LIB_EXT1__ 1 |
||||
#endif |
||||
#define VC_GE_2005(version) (version >= 1400) |
||||
|
||||
/* for explicit_bzero() on glibc */ |
||||
#define _DEFAULT_SOURCE |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#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 functions*****************/ |
||||
|
||||
int allocate_memory(const argon2_context *context, uint8_t **memory, |
||||
size_t num, size_t size) { |
||||
size_t memory_size = num*size; |
||||
if (memory == NULL) { |
||||
return ARGON2_MEMORY_ALLOCATION_ERROR; |
||||
} |
||||
|
||||
/* 1. Check for multiplication overflow */ |
||||
if (size != 0 && memory_size / size != num) { |
||||
return ARGON2_MEMORY_ALLOCATION_ERROR; |
||||
} |
||||
|
||||
/* 2. Try to allocate with appropriate allocator */ |
||||
if (context->allocate_cbk) { |
||||
(context->allocate_cbk)(memory, memory_size); |
||||
} else { |
||||
*memory = malloc(memory_size); |
||||
} |
||||
|
||||
if (*memory == NULL) { |
||||
return ARGON2_MEMORY_ALLOCATION_ERROR; |
||||
} |
||||
|
||||
return ARGON2_OK; |
||||
} |
||||
|
||||
void free_memory(const argon2_context *context, uint8_t *memory, |
||||
size_t num, size_t size) { |
||||
size_t memory_size = num*size; |
||||
clear_internal_memory(memory, memory_size); |
||||
if (context->free_cbk) { |
||||
(context->free_cbk)(memory, memory_size); |
||||
} else { |
||||
free(memory); |
||||
} |
||||
} |
||||
|
||||
#if defined(__OpenBSD__) |
||||
#define HAVE_EXPLICIT_BZERO 1 |
||||
#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ) |
||||
#if __GLIBC_PREREQ(2,25) |
||||
#define HAVE_EXPLICIT_BZERO 1 |
||||
#endif |
||||
#endif |
||||
|
||||
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(HAVE_EXPLICIT_BZERO) |
||||
explicit_bzero(v, n); |
||||
#else |
||||
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset; |
||||
memset_sec(v, 0, n); |
||||
#endif |
||||
} |
||||
|
||||
/* Memory clear flag defaults to true. */ |
||||
int FLAG_clear_internal_memory = 1; |
||||
void clear_internal_memory(void *v, size_t n) { |
||||
if (FLAG_clear_internal_memory && v) { |
||||
secure_wipe_memory(v, n); |
||||
} |
||||
} |
||||
|
||||
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); |
||||
/* clear blockhash and blockhash_bytes */ |
||||
clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE); |
||||
clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); |
||||
} |
||||
|
||||
#ifdef GENKAT |
||||
print_tag(context->out, context->outlen); |
||||
#endif |
||||
|
||||
free_memory(context, (uint8_t *)instance->memory, |
||||
instance->memory_blocks, sizeof(block)); |
||||
} |
||||
} |
||||
|
||||
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..<reference_area_size-1> 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; |
||||
} |
||||
|
||||
/* Single-threaded version for p=1 case */ |
||||
static int fill_memory_blocks_st(argon2_instance_t *instance) { |
||||
uint32_t r, s, l; |
||||
|
||||
for (r = 0; r < instance->passes; ++r) { |
||||
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { |
||||
for (l = 0; l < instance->lanes; ++l) { |
||||
argon2_position_t position = {r, l, (uint8_t)s, 0}; |
||||
fill_segment(instance, position); |
||||
} |
||||
} |
||||
#ifdef GENKAT |
||||
internal_kat(instance, r); /* Print all memory blocks */ |
||||
#endif |
||||
} |
||||
return ARGON2_OK; |
||||
} |
||||
|
||||
#if !defined(ARGON2_NO_THREADS) |
||||
|
||||
#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 = thread_data; |
||||
fill_segment(my_data->instance_ptr, my_data->pos); |
||||
argon2_thread_exit(); |
||||
return 0; |
||||
} |
||||
|
||||
/* Multi-threaded version for p > 1 case */ |
||||
static int fill_memory_blocks_mt(argon2_instance_t *instance) { |
||||
uint32_t r, s; |
||||
argon2_thread_handle_t *thread = NULL; |
||||
argon2_thread_data *thr_data = NULL; |
||||
int rc = ARGON2_OK; |
||||
|
||||
/* 1. Allocating space for threads */ |
||||
thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t)); |
||||
if (thread == NULL) { |
||||
rc = ARGON2_MEMORY_ALLOCATION_ERROR; |
||||
goto fail; |
||||
} |
||||
|
||||
thr_data = calloc(instance->lanes, sizeof(argon2_thread_data)); |
||||
if (thr_data == NULL) { |
||||
rc = ARGON2_MEMORY_ALLOCATION_ERROR; |
||||
goto fail; |
||||
} |
||||
|
||||
for (r = 0; r < instance->passes; ++r) { |
||||
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { |
||||
uint32_t l, ll; |
||||
|
||||
/* 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) { |
||||
if (argon2_thread_join(thread[l - instance->threads])) { |
||||
rc = ARGON2_THREAD_FAIL; |
||||
goto 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)); |
||||
if (argon2_thread_create(&thread[l], &fill_segment_thr, |
||||
(void *)&thr_data[l])) { |
||||
/* Wait for already running threads */ |
||||
for (ll = 0; ll < l; ++ll) |
||||
argon2_thread_join(thread[ll]); |
||||
rc = ARGON2_THREAD_FAIL; |
||||
goto 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) { |
||||
if (argon2_thread_join(thread[l])) { |
||||
rc = ARGON2_THREAD_FAIL; |
||||
goto fail; |
||||
} |
||||
} |
||||
} |
||||
|
||||
#ifdef GENKAT |
||||
internal_kat(instance, r); /* Print all memory blocks */ |
||||
#endif |
||||
} |
||||
|
||||
fail: |
||||
if (thread != NULL) { |
||||
free(thread); |
||||
} |
||||
if (thr_data != NULL) { |
||||
free(thr_data); |
||||
} |
||||
return rc; |
||||
} |
||||
|
||||
#endif /* ARGON2_NO_THREADS */ |
||||
|
||||
int fill_memory_blocks(argon2_instance_t *instance) { |
||||
if (instance == NULL || instance->lanes == 0) { |
||||
return ARGON2_INCORRECT_PARAMETER; |
||||
} |
||||
#if defined(ARGON2_NO_THREADS) |
||||
return fill_memory_blocks_st(instance); |
||||
#else |
||||
return instance->threads == 1 ? |
||||
fill_memory_blocks_st(instance) : fill_memory_blocks_mt(instance); |
||||
#endif |
||||
} |
||||
|
||||
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 (required param) */ |
||||
if (NULL == context->pwd) { |
||||
if (0 != context->pwdlen) { |
||||
return ARGON2_PWD_PTR_MISMATCH; |
||||
} |
||||
} |
||||
|
||||
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 (required param) */ |
||||
if (NULL == context->salt) { |
||||
if (0 != context->saltlen) { |
||||
return ARGON2_SALT_PTR_MISMATCH; |
||||
} |
||||
} |
||||
|
||||
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 (optional param) */ |
||||
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 (optional param) */ |
||||
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||0||i) or
|
||||
G(H0||1||i) */ |
||||
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); |
||||
} |
||||
clear_internal_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; |
||||
instance->context_ptr = context; |
||||
|
||||
/* 1. Memory allocation */ |
||||
result = allocate_memory(context, (uint8_t **)&(instance->memory), |
||||
instance->memory_blocks, sizeof(block)); |
||||
if (result != ARGON2_OK) { |
||||
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 */ |
||||
clear_internal_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 */ |
||||
clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH); |
||||
|
||||
return ARGON2_OK; |
||||
} |
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#ifndef ARGON2_CORE_H |
||||
#define ARGON2_CORE_H |
||||
|
||||
#include "argon2.h" |
||||
|
||||
#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, |
||||
ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32, |
||||
ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64, |
||||
|
||||
/* 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_context *context_ptr; /* points back to original context */ |
||||
} 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, uses the appropriate allocator as
|
||||
* specified in the context. Total allocated memory is num*size. |
||||
* @param context argon2_context which specifies the allocator |
||||
* @param memory pointer to the pointer to the memory |
||||
* @param size the size in bytes for each element to be allocated |
||||
* @param num the number of elements to be allocated |
||||
* @return ARGON2_OK if @memory is a valid pointer and memory is allocated |
||||
*/ |
||||
int allocate_memory(const argon2_context *context, uint8_t **memory, |
||||
size_t num, size_t size); |
||||
|
||||
/*
|
||||
* Frees memory at the given pointer, uses the appropriate deallocator as |
||||
* specified in the context. Also cleans the memory using clear_internal_memory. |
||||
* @param context argon2_context which specifies the deallocator |
||||
* @param memory pointer to buffer to be freed |
||||
* @param size the size in bytes for each element to be deallocated |
||||
* @param num the number of elements to be deallocated |
||||
*/ |
||||
void free_memory(const argon2_context *context, uint8_t *memory, |
||||
size_t num, size_t size); |
||||
|
||||
/* Function that securely cleans the memory. This ignores any flags set
|
||||
* regarding clearing memory. Usually one just calls clear_internal_memory. |
||||
* @param mem Pointer to the memory |
||||
* @param s Memory size in bytes |
||||
*/ |
||||
void secure_wipe_memory(void *v, size_t n); |
||||
|
||||
/* Function that securely clears the memory if FLAG_clear_internal_memory is
|
||||
* set. If the flag isn't set, this function does nothing. |
||||
* @param mem Pointer to the memory |
||||
* @param s Memory size in bytes |
||||
*/ |
||||
void clear_internal_memory(void *v, size_t n); |
||||
|
||||
/*
|
||||
* 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 <argon2.h> |
||||
*/ |
||||
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 context current context |
||||
* @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 |
@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <limits.h> |
||||
#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 code was originally written by Thomas Pornin <pornin@bolet.org>, |
||||
* 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<T>[$v=<num>]$m=<num>,t=<num>,p=<num>$<bin>$<bin> |
||||
* |
||||
* where <T> is either 'd', 'id', or 'i', <num> is a decimal integer (positive, |
||||
* fits in an 'unsigned long'), and <bin> is Base64-encoded data (no '=' padding |
||||
* characters, no newline or whitespace). |
||||
* |
||||
* The last two binary chunks (encoded in Base64) are, in that order, |
||||
* the salt and the output. Both are required. The binary salt length and the |
||||
* output length must be in the allowed ranges defined in argon2.h. |
||||
* |
||||
* The ctx struct must contain buffers large enough to hold the salt and pwd |
||||
* when it is fed into decode_string. |
||||
*/ |
||||
|
||||
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) |
||||
|
||||
/* optional 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) |
||||
|
||||
|
||||
/* Decoding prefix into uint32_t decimal */ |
||||
#define DECIMAL_U32(x) \ |
||||
do { \
|
||||
unsigned long dec_x; \
|
||||
str = decode_decimal(str, &dec_x); \
|
||||
if (str == NULL || dec_x > UINT32_MAX) { \
|
||||
return ARGON2_DECODING_FAIL; \
|
||||
} \
|
||||
(x) = (uint32_t)dec_x; \
|
||||
} while ((void)0, 0) |
||||
|
||||
|
||||
/* Decoding base64 into a binary buffer */ |
||||
#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 maxsaltlen = ctx->saltlen; |
||||
size_t maxoutlen = ctx->outlen; |
||||
int validation_result; |
||||
const char* type_string; |
||||
|
||||
/* We should start with the argon2_type we are using */ |
||||
type_string = argon2_type2string(type, 0); |
||||
if (!type_string) { |
||||
return ARGON2_INCORRECT_TYPE; |
||||
} |
||||
|
||||
CC("$"); |
||||
CC(type_string); |
||||
|
||||
/* Reading the version number if the default is suppressed */ |
||||
ctx->version = ARGON2_VERSION_10; |
||||
CC_opt("$v=", DECIMAL_U32(ctx->version)); |
||||
|
||||
CC("$m="); |
||||
DECIMAL_U32(ctx->m_cost); |
||||
CC(",t="); |
||||
DECIMAL_U32(ctx->t_cost); |
||||
CC(",p="); |
||||
DECIMAL_U32(ctx->lanes); |
||||
ctx->threads = ctx->lanes; |
||||
|
||||
CC("$"); |
||||
BIN(ctx->salt, maxsaltlen, ctx->saltlen); |
||||
CC("$"); |
||||
BIN(ctx->out, maxoutlen, ctx->outlen); |
||||
|
||||
/* The rest of the fields get the default values */ |
||||
ctx->secret = NULL; |
||||
ctx->secretlen = 0; |
||||
ctx->ad = NULL; |
||||
ctx->adlen = 0; |
||||
ctx->allocate_cbk = NULL; |
||||
ctx->free_cbk = NULL; |
||||
ctx->flags = ARGON2_DEFAULT_FLAGS; |
||||
|
||||
/* On return, must have valid context */ |
||||
validation_result = validate_inputs(ctx); |
||||
if (validation_result != ARGON2_OK) { |
||||
return validation_result; |
||||
} |
||||
|
||||
/* Can't have any additional characters */ |
||||
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) |
||||
|
||||
const char* type_string = argon2_type2string(type, 0); |
||||
int validation_result = validate_inputs(ctx); |
||||
|
||||
if (!type_string) { |
||||
return ARGON2_ENCODING_FAIL; |
||||
} |
||||
|
||||
if (validation_result != ARGON2_OK) { |
||||
return validation_result; |
||||
} |
||||
|
||||
|
||||
SS("$"); |
||||
SS(type_string); |
||||
|
||||
SS("$v="); |
||||
SX(ctx->version); |
||||
|
||||
SS("$m="); |
||||
SX(ctx->m_cost); |
||||
SS(",t="); |
||||
SX(ctx->t_cost); |
||||
SS(",p="); |
||||
SX(ctx->lanes); |
||||
|
||||
SS("$"); |
||||
SB(ctx->salt, ctx->saltlen); |
||||
|
||||
SS("$"); |
||||
SB(ctx->out, ctx->outlen); |
||||
return ARGON2_OK; |
||||
|
||||
#undef SS |
||||
#undef SX |
||||
#undef SB |
||||
} |
||||
|
||||
size_t b64len(uint32_t len) { |
||||
size_t olen = ((size_t)len / 3) << 2; |
||||
|
||||
switch (len % 3) { |
||||
case 2: |
||||
olen++; |
||||
/* fall through */ |
||||
case 1: |
||||
olen += 2; |
||||
break; |
||||
} |
||||
|
||||
return olen; |
||||
} |
||||
|
||||
size_t numlen(uint32_t num) { |
||||
size_t len = 1; |
||||
while (num >= 10) { |
||||
++len; |
||||
num = num / 10; |
||||
} |
||||
return len; |
||||
} |
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#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. |
||||
* |
||||
* on success, ARGON2_OK is returned. |
||||
*/ |
||||
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 only fields that must be set prior to this call are ctx.saltlen and |
||||
* ctx.outlen (which must be the maximal salt and out length values that are |
||||
* allowed), ctx.salt and ctx.out (which must be buffers of the specified |
||||
* length), and ctx.pwd and ctx.pwdlen which must hold a valid password. |
||||
* |
||||
* Invalid input string causes an error. On success, the ctx is valid and all |
||||
* fields have been initialized. |
||||
* |
||||
* 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 |
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include "argon2.h" |
||||
#include "core.h" |
||||
|
||||
void initial_kat(const uint8_t *blockhash, const argon2_context *context, |
||||
argon2_type type) { |
||||
unsigned i; |
||||
|
||||
if (blockhash != NULL && context != NULL) { |
||||
printf("=======================================\n"); |
||||
|
||||
printf("%s version number %d\n", argon2_type2string(type, 1), |
||||
context->version); |
||||
|
||||
printf("=======================================\n"); |
||||
|
||||
|
||||
printf("Memory: %u KiB, Iterations: %u, Parallelism: %u lanes, Tag " |
||||
"length: %u bytes\n", |
||||
context->m_cost, context->t_cost, context->lanes, |
||||
context->outlen); |
||||
|
||||
printf("Password[%u]: ", context->pwdlen); |
||||
|
||||
if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { |
||||
printf("CLEARED\n"); |
||||
} else { |
||||
for (i = 0; i < context->pwdlen; ++i) { |
||||
printf("%2.2x ", ((unsigned char *)context->pwd)[i]); |
||||
} |
||||
|
||||
printf("\n"); |
||||
} |
||||
|
||||
printf("Salt[%u]: ", context->saltlen); |
||||
|
||||
for (i = 0; i < context->saltlen; ++i) { |
||||
printf("%2.2x ", ((unsigned char *)context->salt)[i]); |
||||
} |
||||
|
||||
printf("\n"); |
||||
|
||||
printf("Secret[%u]: ", context->secretlen); |
||||
|
||||
if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { |
||||
printf("CLEARED\n"); |
||||
} else { |
||||
for (i = 0; i < context->secretlen; ++i) { |
||||
printf("%2.2x ", ((unsigned char *)context->secret)[i]); |
||||
} |
||||
|
||||
printf("\n"); |
||||
} |
||||
|
||||
printf("Associated data[%u]: ", context->adlen); |
||||
|
||||
for (i = 0; i < context->adlen; ++i) { |
||||
printf("%2.2x ", ((unsigned char *)context->ad)[i]); |
||||
} |
||||
|
||||
printf("\n"); |
||||
|
||||
printf("Pre-hashing digest: "); |
||||
|
||||
for (i = 0; i < ARGON2_PREHASH_DIGEST_LENGTH; ++i) { |
||||
printf("%2.2x ", ((unsigned char *)blockhash)[i]); |
||||
} |
||||
|
||||
printf("\n"); |
||||
} |
||||
} |
||||
|
||||
void print_tag(const void *out, uint32_t outlen) { |
||||
unsigned i; |
||||
if (out != NULL) { |
||||
printf("Tag: "); |
||||
|
||||
for (i = 0; i < outlen; ++i) { |
||||
printf("%2.2x ", ((uint8_t *)out)[i]); |
||||
} |
||||
|
||||
printf("\n"); |
||||
} |
||||
} |
||||
|
||||
void internal_kat(const argon2_instance_t *instance, uint32_t pass) { |
||||
|
||||
if (instance != NULL) { |
||||
uint32_t i, j; |
||||
printf("\n After pass %u:\n", pass); |
||||
|
||||
for (i = 0; i < instance->memory_blocks; ++i) { |
||||
uint32_t how_many_words = |
||||
(instance->memory_blocks > ARGON2_QWORDS_IN_BLOCK) |
||||
? 1 |
||||
: ARGON2_QWORDS_IN_BLOCK; |
||||
|
||||
for (j = 0; j < how_many_words; ++j) |
||||
printf("Block %.4u [%3u]: %016llx\n", i, j, |
||||
(unsigned long long)instance->memory[i].v[j]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void fatal(const char *error) { |
||||
fprintf(stderr, "Error: %s\n", error); |
||||
exit(1); |
||||
} |
||||
|
||||
static void generate_testvectors(argon2_type type, const uint32_t version) { |
||||
#define TEST_OUTLEN 32 |
||||
#define TEST_PWDLEN 32 |
||||
#define TEST_SALTLEN 16 |
||||
#define TEST_SECRETLEN 8 |
||||
#define TEST_ADLEN 12 |
||||
argon2_context context; |
||||
|
||||
unsigned char out[TEST_OUTLEN]; |
||||
unsigned char pwd[TEST_PWDLEN]; |
||||
unsigned char salt[TEST_SALTLEN]; |
||||
unsigned char secret[TEST_SECRETLEN]; |
||||
unsigned char ad[TEST_ADLEN]; |
||||
const allocate_fptr myown_allocator = NULL; |
||||
const deallocate_fptr myown_deallocator = NULL; |
||||
|
||||
unsigned t_cost = 3; |
||||
unsigned m_cost = 32; |
||||
unsigned lanes = 4; |
||||
|
||||
memset(pwd, 1, TEST_OUTLEN); |
||||
memset(salt, 2, TEST_SALTLEN); |
||||
memset(secret, 3, TEST_SECRETLEN); |
||||
memset(ad, 4, TEST_ADLEN); |
||||
|
||||
context.out = out; |
||||
context.outlen = TEST_OUTLEN; |
||||
context.version = version; |
||||
context.pwd = pwd; |
||||
context.pwdlen = TEST_PWDLEN; |
||||
context.salt = salt; |
||||
context.saltlen = TEST_SALTLEN; |
||||
context.secret = secret; |
||||
context.secretlen = TEST_SECRETLEN; |
||||
context.ad = ad; |
||||
context.adlen = TEST_ADLEN; |
||||
context.t_cost = t_cost; |
||||
context.m_cost = m_cost; |
||||
context.lanes = lanes; |
||||
context.threads = lanes; |
||||
context.allocate_cbk = myown_allocator; |
||||
context.free_cbk = myown_deallocator; |
||||
context.flags = ARGON2_DEFAULT_FLAGS; |
||||
|
||||
#undef TEST_OUTLEN |
||||
#undef TEST_PWDLEN |
||||
#undef TEST_SALTLEN |
||||
#undef TEST_SECRETLEN |
||||
#undef TEST_ADLEN |
||||
|
||||
argon2_ctx(&context, type); |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) { |
||||
/* Get and check Argon2 type */ |
||||
const char *type_str = (argc > 1) ? argv[1] : "i"; |
||||
argon2_type type = Argon2_i; |
||||
uint32_t version = ARGON2_VERSION_NUMBER; |
||||
if (!strcmp(type_str, "d")) { |
||||
type = Argon2_d; |
||||
} else if (!strcmp(type_str, "i")) { |
||||
type = Argon2_i; |
||||
} else if (!strcmp(type_str, "id")) { |
||||
type = Argon2_id; |
||||
} else { |
||||
fatal("wrong Argon2 type"); |
||||
} |
||||
|
||||
/* Get and check Argon2 version number */ |
||||
if (argc > 2) { |
||||
version = strtoul(argv[2], NULL, 10); |
||||
} |
||||
if (ARGON2_VERSION_10 != version && ARGON2_VERSION_NUMBER != version) { |
||||
fatal("wrong Argon2 version number"); |
||||
} |
||||
|
||||
generate_testvectors(type, version); |
||||
return ARGON2_OK; |
||||
} |
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#ifndef ARGON2_KAT_H |
||||
#define ARGON2_KAT_H |
||||
|
||||
#include "core.h" |
||||
|
||||
/*
|
||||
* Initial KAT function that prints the inputs to the file |
||||
* @param blockhash Array that contains pre-hashing digest |
||||
* @param context Holds inputs |
||||
* @param type Argon2 type |
||||
* @pre blockhash must point to INPUT_INITIAL_HASH_LENGTH bytes |
||||
* @pre context member pointers must point to allocated memory of size according |
||||
* to the length values |
||||
*/ |
||||
void initial_kat(const uint8_t *blockhash, const argon2_context *context, |
||||
argon2_type type); |
||||
|
||||
/*
|
||||
* Function that prints the output tag |
||||
* @param out output array pointer |
||||
* @param outlen digest length |
||||
* @pre out must point to @a outlen bytes |
||||
**/ |
||||
void print_tag(const void *out, uint32_t outlen); |
||||
|
||||
/*
|
||||
* Function that prints the internal state at given moment |
||||
* @param instance pointer to the current instance |
||||
* @param pass current pass number |
||||
* @pre instance must have necessary memory allocated |
||||
**/ |
||||
void internal_kat(const argon2_instance_t *instance, uint32_t pass); |
||||
|
||||
#endif |
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "argon2.h" |
||||
#include "core.h" |
||||
|
||||
#include "blake2/blamka-round-ref.h" |
||||
#include "blake2/blake2-impl.h" |
||||
#include "blake2/blake2.h" |
||||
|
||||
|
||||
/*
|
||||
* Function fills a new memory block and optionally XORs the old block over the new one. |
||||
* @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 |
||||
* @param with_xor Whether to XOR into the new block (1) or just overwrite (0) |
||||
* @pre all block pointers must be valid |
||||
*/ |
||||
static void fill_block(const block *prev_block, const block *ref_block, |
||||
block *next_block, int with_xor) { |
||||
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 block_tmp = ref_block + prev_block */ |
||||
if (with_xor) { |
||||
/* Saving the next block contents for XOR over: */ |
||||
xor_block(&block_tmp, next_block); |
||||
/* Now blockR = ref_block + prev_block and
|
||||
block_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); |
||||
} |
||||
|
||||
static void next_addresses(block *address_block, block *input_block, |
||||
const block *zero_block) { |
||||
input_block->v[6]++; |
||||
fill_block(zero_block, input_block, address_block, 0); |
||||
fill_block(zero_block, address_block, address_block, 0); |
||||
} |
||||
|
||||
void fill_segment(const argon2_instance_t *instance, |
||||
argon2_position_t position) { |
||||
block *ref_block = NULL, *curr_block = NULL; |
||||
block address_block, input_block, zero_block; |
||||
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; |
||||
|
||||
if (instance == NULL) { |
||||
return; |
||||
} |
||||
|
||||
data_independent_addressing = |
||||
(instance->type == Argon2_i) || |
||||
(instance->type == Argon2_id && (position.pass == 0) && |
||||
(position.slice < ARGON2_SYNC_POINTS / 2)); |
||||
|
||||
if (data_independent_addressing) { |
||||
init_block_value(&zero_block, 0); |
||||
init_block_value(&input_block, 0); |
||||
|
||||
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; |
||||
} |
||||
|
||||
starting_index = 0; |
||||
|
||||
if ((0 == position.pass) && (0 == position.slice)) { |
||||
starting_index = 2; /* we have already generated the first two blocks */ |
||||
|
||||
/* Don't forget to generate the first block of addresses: */ |
||||
if (data_independent_addressing) { |
||||
next_addresses(&address_block, &input_block, &zero_block); |
||||
} |
||||
} |
||||
|
||||
/* 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) { |
||||
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { |
||||
next_addresses(&address_block, &input_block, &zero_block); |
||||
} |
||||
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; |
||||
} 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, 0); |
||||
} else { |
||||
if(0 == position.pass) { |
||||
fill_block(instance->memory + prev_offset, ref_block, |
||||
curr_block, 0); |
||||
} else { |
||||
fill_block(instance->memory + prev_offset, ref_block, |
||||
curr_block, 1); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#if !defined(ARGON2_NO_THREADS) |
||||
|
||||
#include "thread.h" |
||||
#if defined(_WIN32) |
||||
#include <windows.h> |
||||
#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 |
||||
} |
||||
|
||||
#endif /* ARGON2_NO_THREADS */ |
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations |
||||
* |
||||
* Copyright 2015 |
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves |
||||
* |
||||
* You may use this work under the terms of a Creative Commons CC0 1.0 |
||||
* License/Waiver or the Apache Public License 2.0, at your option. The terms of |
||||
* these licenses can be found at: |
||||
* |
||||
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* You should have received a copy of both of these licenses along with this |
||||
* software. If not, they may be obtained at the above URLs. |
||||
*/ |
||||
|
||||
#ifndef ARGON2_THREAD_H |
||||
#define ARGON2_THREAD_H |
||||
|
||||
#if !defined(ARGON2_NO_THREADS) |
||||
|
||||
/*
|
||||
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 <process.h> |
||||
typedef unsigned(__stdcall *argon2_thread_func_t)(void *); |
||||
typedef uintptr_t argon2_thread_handle_t; |
||||
#else |
||||
#include <pthread.h> |
||||
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 successfully |
||||
* 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 /* ARGON2_NO_THREADS */ |
||||
#endif |
Loading…
Reference in new issue