diff options
author | aunsane <aunsane@gmail.com> | 2017-12-15 01:05:56 +0300 |
---|---|---|
committer | aunsane <aunsane@gmail.com> | 2017-12-15 01:05:56 +0300 |
commit | e124aa3611f38573898aa79c6eabe77bc874e58f (patch) | |
tree | 819464260f758bbc002b23c0c8a77f93751dcb42 /libs/libsodium/src/crypto_pwhash | |
parent | bbd9647d47f20d10b39570def918a0ac68c305c9 (diff) |
preparing to build tox from sources
Diffstat (limited to 'libs/libsodium/src/crypto_pwhash')
27 files changed, 5666 insertions, 0 deletions
diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.c new file mode 100644 index 0000000000..b52b04d36d --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.c @@ -0,0 +1,549 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#ifdef HAVE_SYS_MMAN_H +# include <sys/mman.h> +#endif + +#include "crypto_generichash_blake2b.h" +#include "private/common.h" +#include "private/implementations.h" +#include "runtime.h" +#include "utils.h" + +#include "argon2-core.h" +#include "blake2b-long.h" + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +# define MAP_ANON MAP_ANONYMOUS +#endif +#ifndef MAP_NOCORE +# define MAP_NOCORE 0 +#endif +#ifndef MAP_POPULATE +# define MAP_POPULATE 0 +#endif + +static fill_segment_fn fill_segment = fill_segment_ref; + +static void +load_block(block *dst, const void *input) +{ + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] = LOAD64_LE((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_LE((uint8_t *) output + i * sizeof(src->v[i]), src->v[i]); + } +} + +/***************Memory allocators*****************/ +/* Allocates memory to the given pointer + * @param memory pointer to the pointer to the memory + * @param m_cost number of blocks to allocate in the memory + * @return ARGON2_OK if @memory is a valid pointer and memory is allocated + */ +static int allocate_memory(block_region **memory, uint32_t m_cost); + +static int +allocate_memory(block_region **region, uint32_t m_cost) +{ + void * base; + block *memory; + size_t memory_size; + + if (region == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */ + } + memory_size = sizeof(block) * m_cost; + if (m_cost == 0 || + memory_size / m_cost != + sizeof(block)) { /*1. Check for multiplication overflow*/ + return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */ + } + *region = (block_region *) malloc( + sizeof(block_region)); /*2. Try to allocate region*/ + if (!*region) { + return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */ + } + (*region)->base = (*region)->memory = NULL; + +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if ((base = mmap(NULL, memory_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_NOCORE | MAP_POPULATE, + -1, 0)) == MAP_FAILED) { + base = NULL; /* LCOV_EXCL_LINE */ + } /* LCOV_EXCL_LINE */ + memcpy(&memory, &base, sizeof memory); +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **) &base, 64, memory_size)) != 0) { + base = NULL; + } + memcpy(&memory, &base, sizeof memory); +#else + memory = NULL; + if (memory_size + 63 < memory_size) { + base = NULL; + errno = ENOMEM; + } else if ((base = malloc(memory_size + 63)) != NULL) { + uint8_t *aligned = ((uint8_t *) base) + 63; + aligned -= (uintptr_t) aligned & 63; + memcpy(&memory, &aligned, sizeof memory); + } +#endif + if (base == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */ + } + (*region)->base = base; + (*region)->memory = memory; + (*region)->size = memory_size; + + return ARGON2_OK; +} + +/*********Memory functions*/ + +/* Clears memory + * @param instance pointer to the current instance + * @param clear_memory indicates if we clear the memory with zeros. + */ +static void clear_memory(argon2_instance_t *instance, int clear); + +static void +clear_memory(argon2_instance_t *instance, int clear) +{ + /* LCOV_EXCL_START */ + if (clear) { + if (instance->region != NULL) { + sodium_memzero(instance->region->memory, + sizeof(block) * instance->memory_blocks); + } + if (instance->pseudo_rands != NULL) { + sodium_memzero(instance->pseudo_rands, + sizeof(uint64_t) * instance->segment_length); + } + } + /* LCOV_EXCL_STOP */ +} + +/* Deallocates memory + * @param memory pointer to the blocks + */ +static void free_memory(block_region *memory); + +static void +free_memory(block_region *region) +{ + if (region && region->base) { +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if (munmap(region->base, region->size)) { + return; /* LCOV_EXCL_LINE */ + } +#else + free(region->base); +#endif + } + free(region); +} + +void +free_instance(argon2_instance_t *instance, int flags) +{ + /* Clear memory */ + clear_memory(instance, flags & ARGON2_FLAG_CLEAR_MEMORY); + + /* Deallocate the memory */ + free(instance->pseudo_rands); + instance->pseudo_rands = NULL; + free_memory(instance->region); + instance->region = NULL; +} + +void +finalize(const argon2_context *context, argon2_instance_t *instance) +{ + if (context != NULL && instance != NULL) { + block blockhash; + uint32_t l; + + copy_block(&blockhash, + instance->region->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->region->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); + sodium_memzero(blockhash.v, + ARGON2_BLOCK_SIZE); /* clear blockhash */ + sodium_memzero(blockhash_bytes, + ARGON2_BLOCK_SIZE); /* clear blockhash_bytes */ + } + + free_instance(instance, context->flags); + } +} + +void +fill_memory_blocks(argon2_instance_t *instance, uint32_t pass) +{ + argon2_position_t position; + uint32_t l; + uint32_t s; + + if (instance == NULL || instance->lanes == 0) { + return; /* LCOV_EXCL_LINE */ + } + + position.pass = pass; + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + position.slice = (uint8_t) s; + for (l = 0; l < instance->lanes; ++l) { + position.lane = l; + position.index = 0; + fill_segment(instance, position); + } + } +} + +int +validate_inputs(const argon2_context *context) +{ + /* LCOV_EXCL_START */ + 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; + } + /* LCOV_EXCL_STOP */ + + return ARGON2_OK; +} + +void +fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) +{ + uint32_t l; + /* Make the first and second block in each lane as G(H0||i||0) or + G(H0||i||1) */ + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + for (l = 0; l < instance->lanes; ++l) { + STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0); + STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->region->memory[l * instance->lane_length + 0], + blockhash_bytes); + + STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->region->memory[l * instance->lane_length + 1], + blockhash_bytes); + } + sodium_memzero(blockhash_bytes, ARGON2_BLOCK_SIZE); +} + +void +initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type type) +{ + crypto_generichash_blake2b_state BlakeHash; + uint8_t value[4U /* sizeof(uint32_t) */]; + + if (NULL == context || NULL == blockhash) { + return; /* LCOV_EXCL_LINE */ + } + + crypto_generichash_blake2b_init(&BlakeHash, NULL, 0U, + ARGON2_PREHASH_DIGEST_LENGTH); + + STORE32_LE(value, context->lanes); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, context->outlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, context->m_cost); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, context->t_cost); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, ARGON2_VERSION_NUMBER); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, (uint32_t) type); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, context->pwdlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + if (context->pwd != NULL) { + crypto_generichash_blake2b_update( + &BlakeHash, (const uint8_t *) context->pwd, context->pwdlen); + + /* LCOV_EXCL_START */ + if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { + sodium_memzero(context->pwd, context->pwdlen); + context->pwdlen = 0; + } + /* LCOV_EXCL_STOP */ + } + + STORE32_LE(value, context->saltlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + if (context->salt != NULL) { + crypto_generichash_blake2b_update( + &BlakeHash, (const uint8_t *) context->salt, context->saltlen); + } + + STORE32_LE(value, context->secretlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + /* LCOV_EXCL_START */ + if (context->secret != NULL) { + crypto_generichash_blake2b_update( + &BlakeHash, (const uint8_t *) context->secret, context->secretlen); + + if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { + sodium_memzero(context->secret, context->secretlen); + context->secretlen = 0; + } + } + /* LCOV_EXCL_STOP */ + + STORE32_LE(value, context->adlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + /* LCOV_EXCL_START */ + if (context->ad != NULL) { + crypto_generichash_blake2b_update( + &BlakeHash, (const uint8_t *) context->ad, context->adlen); + } + /* LCOV_EXCL_STOP */ + + crypto_generichash_blake2b_final(&BlakeHash, blockhash, + ARGON2_PREHASH_DIGEST_LENGTH); +} + +int +initialize(argon2_instance_t *instance, argon2_context *context) +{ + uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; + int result = ARGON2_OK; + + if (instance == NULL || context == NULL) { + return ARGON2_INCORRECT_PARAMETER; + } + + /* 1. Memory allocation */ + + if ((instance->pseudo_rands = (uint64_t *) + malloc(sizeof(uint64_t) * instance->segment_length)) == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + result = allocate_memory(&(instance->region), instance->memory_blocks); + if (ARGON2_OK != result) { + free_instance(instance, context->flags); + 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 */ + sodium_memzero(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, + ARGON2_PREHASH_SEED_LENGTH - ARGON2_PREHASH_DIGEST_LENGTH); + + /* 3. Creating first blocks, we always have at least two blocks in a slice + */ + fill_first_blocks(blockhash, instance); + /* Clearing the hash */ + sodium_memzero(blockhash, ARGON2_PREHASH_SEED_LENGTH); + + return ARGON2_OK; +} + +int +argon2_pick_best_implementation(void) +{ +/* LCOV_EXCL_START */ +#if defined(HAVE_AVX512FINTRIN_H) && defined(HAVE_AVX2INTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + if (sodium_runtime_has_avx512f()) { + fill_segment = fill_segment_avx512f; + return 0; + } +#endif +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_TMMINTRIN_H) && \ + defined(HAVE_SMMINTRIN_H) + if (sodium_runtime_has_avx2()) { + fill_segment = fill_segment_avx2; + return 0; + } +#endif +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) + if (sodium_runtime_has_ssse3()) { + fill_segment = fill_segment_ssse3; + return 0; + } +#endif + fill_segment = fill_segment_ref; + + return 0; + /* LCOV_EXCL_STOP */ +} + +int +_crypto_pwhash_argon2_pick_best_implementation(void) +{ + return argon2_pick_best_implementation(); +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.h b/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.h new file mode 100644 index 0000000000..caab103891 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.h @@ -0,0 +1,297 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#ifndef argon2_core_H +#define argon2_core_H + +#include <string.h> + +#include "argon2.h" + +/*************************Argon2 internal + * constants**************************************************/ + +enum argon2_ctx_constants { + /* Version of the algorithm */ + ARGON2_VERSION_NUMBER = 0x13, + + /* 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; + +typedef struct block_region_ { + void * base; + block *memory; + size_t size; +} block_region; + +/*****************Functions that work with the block******************/ + +/* Initialize each byte of the block with @in */ +static inline void +init_block_value(block *b, uint8_t in) +{ + memset(b->v, in, sizeof(b->v)); +} + +/* Copy block @src to block @dst */ +static inline void +copy_block(block *dst, const block *src) +{ + memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK); +} + +/* XOR @src onto @dst bytewise */ +static inline 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]; + } +} + +/* + * 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_region *region; /* Memory region pointer */ + uint64_t *pseudo_rands; + uint32_t passes; /* Number of passes */ + uint32_t current_pass; + uint32_t memory_blocks; /* Number of blocks in memory */ + uint32_t segment_length; + uint32_t lane_length; + uint32_t lanes; + uint32_t threads; + argon2_type type; + int print_internals; /* whether to print the memory blocks */ +} argon2_instance_t; + +/* + * Argon2 position: where we construct the block right now. Used to distribute + * work between threads. + */ +typedef struct Argon2_position_t { + uint32_t pass; + uint32_t lane; + uint8_t slice; + uint32_t index; +} argon2_position_t; + +/*Struct that holds the inputs for thread handling FillSegment*/ +typedef struct Argon2_thread_data { + argon2_instance_t *instance_ptr; + argon2_position_t pos; +} argon2_thread_data; + +/*************************Argon2 core + * functions**************************************************/ + +/* + * 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 + */ +static 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 (position->pass == 0) { + /* First pass */ + if (position->slice == 0) { + /* 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 (position->pass != 0) { + 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; +} + +/* + * 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); + +/* + * Deallocates memory. Used on error path. + */ +void free_instance(argon2_instance_t *instance, int flags); + +/* + * XORing the last block of each lane, hashing it, making the tag. Deallocates + * the memory. + * @param context Pointer to current Argon2 context (use only the out parameters + * from it) + * @param instance Pointer to current instance of Argon2 + * @pre instance->state must point to necessary amount of memory + * @pre context->out must point to outlen bytes of memory + * @pre if context->free_cbk is not NULL, it should point to a function that + * deallocates memory + */ +void finalize(const argon2_context *context, argon2_instance_t *instance); + +/* + * Function that fills the segment using previous segments also from other + * threads + * @param instance Pointer to the current instance + * @param position Current position + * @pre all block pointers must be valid + */ +typedef void (*fill_segment_fn)(const argon2_instance_t *instance, + argon2_position_t position); +int argon2_pick_best_implementation(void); +void fill_segment_avx512f(const argon2_instance_t *instance, + argon2_position_t position); +void fill_segment_avx2(const argon2_instance_t *instance, + argon2_position_t position); +void fill_segment_ssse3(const argon2_instance_t *instance, + argon2_position_t position); +void fill_segment_ref(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 Zero if successful, -1 if memory failed to allocate + */ +void fill_memory_blocks(argon2_instance_t *instance, uint32_t pass); + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.c new file mode 100644 index 0000000000..a08acdda80 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.c @@ -0,0 +1,305 @@ +#include "argon2-encoding.h" +#include "argon2-core.h" +#include "utils.h" +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* + * Example code for a decoder and encoder of "hash strings", with Argon2 + * parameters. + * + * 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 + */ + +/* ==================================================================== */ + +/* + * 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 '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. + */ + +/* + * Decode an Argon2i hash string into the provided structure 'ctx'. + * Returned value is ARGON2_OK on success. + */ +int +decode_string(argon2_context *ctx, const char *str, argon2_type type) +{ +/* Prefix checking */ +#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); \ + const char *str_end; \ + if (sodium_base642bin((buf), (max_len), str, strlen(str), NULL, \ + &bin_len, &str_end, \ + sodium_base64_VARIANT_ORIGINAL_NO_PADDING) != 0 || \ + bin_len > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (len) = (uint32_t) bin_len; \ + str = str_end; \ + } while ((void) 0, 0) + + size_t maxsaltlen = ctx->saltlen; + size_t maxoutlen = ctx->outlen; + int validation_result; + uint32_t version = 0; + + ctx->saltlen = 0; + ctx->outlen = 0; + + if (type == Argon2_id) { + CC("$argon2id"); + } else if (type == Argon2_i) { + CC("$argon2i"); + } else { + return ARGON2_INCORRECT_TYPE; + } + CC("$v="); + DECIMAL_U32(version); + if (version != ARGON2_VERSION_NUMBER) { + return ARGON2_INCORRECT_TYPE; + } + CC("$m="); + DECIMAL_U32(ctx->m_cost); + if (ctx->m_cost > UINT32_MAX) { + return ARGON2_INCORRECT_TYPE; + } + CC(",t="); + DECIMAL_U32(ctx->t_cost); + if (ctx->t_cost > UINT32_MAX) { + return ARGON2_INCORRECT_TYPE; + } + CC(",p="); + DECIMAL_U32(ctx->lanes); + if (ctx->lanes > UINT32_MAX) { + return ARGON2_INCORRECT_TYPE; + } + ctx->threads = ctx->lanes; + + CC("$"); + BIN(ctx->salt, maxsaltlen, ctx->saltlen); + CC("$"); + BIN(ctx->out, maxoutlen, ctx->outlen); + validation_result = validate_inputs(ctx); + if (validation_result != ARGON2_OK) { + return validation_result; + } + if (*str == 0) { + return ARGON2_OK; + } + return ARGON2_DECODING_FAIL; + +#undef CC +#undef CC_opt +#undef DECIMAL +#undef BIN +} + +#define U32_STR_MAXSIZE 11U + +static void +u32_to_string(char *str, uint32_t x) +{ + char tmp[U32_STR_MAXSIZE - 1U]; + size_t i; + + i = sizeof tmp; + do { + tmp[--i] = (x % (uint32_t) 10U) + '0'; + x /= (uint32_t) 10U; + } while (x != 0U && i != 0U); + memcpy(str, &tmp[i], (sizeof tmp) - i); + str[(sizeof tmp) - i] = 0; +} + +/* + * Encode an argon2i 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 0. + * + * If pp->output_len is 0, then the hash string will be a salt string + * (no output). if pp->salt_len is also 0, then the string will be a + * parameter-only string (no salt and no output). + * + * On success, ARGON2_OK is returned. + */ +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[U32_STR_MAXSIZE]; \ + u32_to_string(tmp, x); \ + SS(tmp); \ + } while ((void) 0, 0) + +#define SB(buf, len) \ + do { \ + size_t sb_len; \ + if (sodium_bin2base64(dst, dst_len, (buf), (len), \ + sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == NULL) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + sb_len = strlen(dst); \ + dst += sb_len; \ + dst_len -= sb_len; \ + } while ((void) 0, 0) + + int validation_result; + + switch (type) { + case Argon2_id: + SS("$argon2id$v="); break; + case Argon2_i: + SS("$argon2i$v="); break; + default: + return ARGON2_ENCODING_FAIL; + } + validation_result = validate_inputs(ctx); + if (validation_result != ARGON2_OK) { + return validation_result; + } + SX(ARGON2_VERSION_NUMBER); + 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 +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.h b/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.h new file mode 100644 index 0000000000..e929b31dc3 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.h @@ -0,0 +1,33 @@ +#ifndef argon2_encoding_H +#define argon2_encoding_H + +#include "argon2.h" + +/* + * 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 0. + * + * if ctx->outlen is 0, then the hash string will be a salt string + * (no output). if ctx->saltlen is also 0, then the string will be a + * parameter-only string (no salt and no output). + * + * On success, ARGON2_OK is returned. + * + * No other parameters are checked + */ +int encode_string(char *dst, size_t dst_len, argon2_context *ctx, + argon2_type type); + +/* + * Decodes an Argon2 hash string into the provided structure 'ctx'. + * The fields ctx.saltlen, ctx.adlen, ctx.outlen set the maximal salt, ad, out + * length values + * that are allowed; invalid input string causes an error + * + * Returned value is ARGON2_OK on success. + */ +int decode_string(argon2_context *ctx, const char *str, argon2_type type); + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx2.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx2.c new file mode 100644 index 0000000000..8acb42ca4d --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx2.c @@ -0,0 +1,239 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "argon2-core.h" +#include "argon2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# pragma GCC target("sse4.1") +# pragma GCC target("avx2") +# endif + +# ifdef _MSC_VER +# include <intrin.h> /* for _mm_set_epi64x */ +# endif +#include <emmintrin.h> +#include <immintrin.h> +#include <smmintrin.h> +#include <tmmintrin.h> + +# include "blamka-round-avx2.h" + +static void +fill_block(__m256i *state, const uint8_t *ref_block, uint8_t *next_block) +{ + __m256i block_XY[ARGON2_HWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + block_XY[i] = state[i] = _mm256_xor_si256( + state[i], _mm256_loadu_si256((__m256i const *) (&ref_block[32 * i]))); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5], + state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i], + state[16 + i], state[20 + i], state[24 + i], state[28 + i]); + } + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + state[i] = _mm256_xor_si256(state[i], block_XY[i]); + _mm256_storeu_si256((__m256i *) (&next_block[32 * i]), state[i]); + } +} + +static void +fill_block_with_xor(__m256i *state, const uint8_t *ref_block, + uint8_t *next_block) +{ + __m256i block_XY[ARGON2_HWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + state[i] = _mm256_xor_si256( + state[i], _mm256_loadu_si256((__m256i const *) (&ref_block[32 * i]))); + block_XY[i] = _mm256_xor_si256( + state[i], _mm256_loadu_si256((__m256i const *) (&next_block[32 * i]))); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5], + state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i], + state[16 + i], state[20 + i], state[24 + i], state[28 + i]); + } + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + state[i] = _mm256_xor_si256(state[i], block_XY[i]); + _mm256_storeu_si256((__m256i *) (&next_block[32 * i]), state[i]); + } +} + +static void +generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, uint64_t *pseudo_rands) +{ + block address_block, input_block, tmp_block; + uint32_t i; + + init_block_value(&address_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + /* Temporary zero-initialized blocks */ + __m256i zero_block[ARGON2_HWORDS_IN_BLOCK]; + __m256i zero2_block[ARGON2_HWORDS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + init_block_value(&address_block, 0); + init_block_value(&tmp_block, 0); + /* Increasing index counter */ + input_block.v[6]++; + /* First iteration of G */ + fill_block_with_xor(zero_block, (uint8_t *) &input_block.v, + (uint8_t *) &tmp_block.v); + /* Second iteration of G */ + fill_block_with_xor(zero2_block, (uint8_t *) &tmp_block.v, + (uint8_t *) &address_block.v); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void +fill_segment_avx2(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m256i state[ARGON2_HWORDS_IN_BLOCK]; + int data_independent_addressing = 1; + + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + + if (instance == NULL) { + return; + } + + if (instance->type == Argon2_id && + (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { + data_independent_addressing = 0; + } + + pseudo_rands = instance->pseudo_rands; + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->region->memory + prev_offset)->v), + ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { +#pragma warning(push) +#pragma warning(disable : 6385) + pseudo_rand = pseudo_rands[i]; +#pragma warning(pop) + } else { + pseudo_rand = instance->region->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->region->memory + + instance->lane_length * ref_lane + ref_index; + curr_block = instance->region->memory + curr_offset; + if (position.pass != 0) { + fill_block_with_xor(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } else { + fill_block(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } + } +} +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx512f.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx512f.c new file mode 100644 index 0000000000..1f1ec8b3b4 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx512f.c @@ -0,0 +1,244 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "argon2-core.h" +#include "argon2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_AVX512FINTRIN_H) && defined(HAVE_AVX2INTRIN_H) && \ + defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# pragma GCC target("sse4.1") +# pragma GCC target("avx2") +# pragma GCC target("avx512f") +# endif + +# ifdef _MSC_VER +# include <intrin.h> /* for _mm_set_epi64x */ +# endif +#include <emmintrin.h> +#include <immintrin.h> +#include <smmintrin.h> +#include <tmmintrin.h> + +# include "blamka-round-avx512f.h" + +static void +fill_block(__m512i *state, const uint8_t *ref_block, uint8_t *next_block) +{ + __m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) { + block_XY[i] = state[i] = _mm512_xor_si512( + state[i], _mm512_loadu_si512((__m512i const *) (&ref_block[64 * i]))); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND_1( + state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], + state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND_2( + state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i], + state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]); + } + + for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) { + state[i] = _mm512_xor_si512(state[i], block_XY[i]); + _mm512_storeu_si512((__m512i *) (&next_block[64 * i]), state[i]); + } +} + +static void +fill_block_with_xor(__m512i *state, const uint8_t *ref_block, + uint8_t *next_block) +{ + __m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) { + state[i] = _mm512_xor_si512( + state[i], _mm512_loadu_si512((__m512i const *) (&ref_block[64 * i]))); + block_XY[i] = _mm512_xor_si512( + state[i], _mm512_loadu_si512((__m512i const *) (&next_block[64 * i]))); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND_1( + state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], + state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND_2( + state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i], + state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]); + } + + for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) { + state[i] = _mm512_xor_si512(state[i], block_XY[i]); + _mm512_storeu_si512((__m512i *) (&next_block[64 * i]), state[i]); + } +} + +static void +generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, uint64_t *pseudo_rands) +{ + block address_block, input_block, tmp_block; + uint32_t i; + + init_block_value(&address_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + /* Temporary zero-initialized blocks */ + __m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK]; + __m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + init_block_value(&address_block, 0); + init_block_value(&tmp_block, 0); + /* Increasing index counter */ + input_block.v[6]++; + /* First iteration of G */ + fill_block_with_xor(zero_block, (uint8_t *) &input_block.v, + (uint8_t *) &tmp_block.v); + /* Second iteration of G */ + fill_block_with_xor(zero2_block, (uint8_t *) &tmp_block.v, + (uint8_t *) &address_block.v); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void +fill_segment_avx512f(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m512i state[ARGON2_512BIT_WORDS_IN_BLOCK]; + int data_independent_addressing = 1; + + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + + if (instance == NULL) { + return; + } + + if (instance->type == Argon2_id && + (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { + data_independent_addressing = 0; + } + + pseudo_rands = instance->pseudo_rands; + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->region->memory + prev_offset)->v), + ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { +#pragma warning(push) +#pragma warning(disable : 6385) + pseudo_rand = pseudo_rands[i]; +#pragma warning(pop) + } else { + pseudo_rand = instance->region->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->region->memory + + instance->lane_length * ref_lane + ref_index; + curr_block = instance->region->memory + curr_offset; + if (position.pass != 0) { + fill_block_with_xor(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } else { + fill_block(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } + } +} +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ref.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ref.c new file mode 100644 index 0000000000..75e8d8f5ea --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ref.c @@ -0,0 +1,233 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "argon2-core.h" +#include "argon2.h" +#include "blamka-round-ref.h" +#include "private/common.h" + +static void +fill_block(const block *prev_block, const block *ref_block, block *next_block) +{ + block blockR, block_tmp; + unsigned i; + + copy_block(&blockR, ref_block); + xor_block(&blockR, prev_block); + copy_block(&block_tmp, &blockR); + /* Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block + Apply Blake2 on columns of 64-bit words: (0,1,...,15), then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + copy_block(next_block, &block_tmp); + xor_block(next_block, &blockR); +} + +static void +fill_block_with_xor(const block *prev_block, const block *ref_block, + block *next_block) +{ + block blockR, block_tmp; + unsigned i; + + copy_block(&blockR, ref_block); + xor_block(&blockR, prev_block); + copy_block(&block_tmp, &blockR); + xor_block(&block_tmp, + next_block); /* Saving the next block contents for XOR over */ + /* Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block + * + next_block */ + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + copy_block(next_block, &block_tmp); + xor_block(next_block, &blockR); +} + +/* + * Generate pseudo-random values to reference blocks in the segment and puts + * them into the array + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rands Pointer to the array of 64-bit values + * @pre pseudo_rands must point to @a instance->segment_length allocated values + */ +static void +generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, uint64_t *pseudo_rands) +{ + block zero_block, input_block, address_block, tmp_block; + uint32_t i; + + init_block_value(&zero_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + input_block.v[6]++; + init_block_value(&tmp_block, 0); + init_block_value(&address_block, 0); + fill_block_with_xor(&zero_block, &input_block, &tmp_block); + fill_block_with_xor(&zero_block, &tmp_block, &address_block); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void +fill_segment_ref(const argon2_instance_t *instance, argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index; + uint32_t i; + int data_independent_addressing = 1; + + if (instance == NULL) { + return; + } + + if (instance->type == Argon2_id && + (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { + data_independent_addressing = 0; + } + + pseudo_rands = instance->pseudo_rands; + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { +#pragma warning(push) +#pragma warning(disable : 6385) + pseudo_rand = pseudo_rands[i]; +#pragma warning(pop) + } else { + pseudo_rand = instance->region->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->region->memory + + instance->lane_length * ref_lane + ref_index; + curr_block = instance->region->memory + curr_offset; + if (position.pass != 0) { + fill_block_with_xor(instance->region->memory + prev_offset, + ref_block, curr_block); + } else { + fill_block(instance->region->memory + prev_offset, ref_block, + curr_block); + } + } +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ssse3.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ssse3.c new file mode 100644 index 0000000000..796c445560 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ssse3.c @@ -0,0 +1,238 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "argon2-core.h" +#include "argon2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# endif + +# ifdef _MSC_VER +# include <intrin.h> /* for _mm_set_epi64x */ +# endif +# include <emmintrin.h> +# include <tmmintrin.h> + +# include "blamka-round-ssse3.h" + +static void +fill_block(__m128i *state, const uint8_t *ref_block, uint8_t *next_block) +{ + __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + block_XY[i] = state[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *) (&ref_block[16 * i]))); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], + state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], + state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], + state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], + state[8 * 6 + i], state[8 * 7 + i]); + } + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128(state[i], block_XY[i]); + _mm_storeu_si128((__m128i *) (&next_block[16 * i]), state[i]); + } +} + +static void +fill_block_with_xor(__m128i *state, const uint8_t *ref_block, + uint8_t *next_block) +{ + __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *) (&ref_block[16 * i]))); + block_XY[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *) (&next_block[16 * i]))); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], + state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], + state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], + state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], + state[8 * 6 + i], state[8 * 7 + i]); + } + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128(state[i], block_XY[i]); + _mm_storeu_si128((__m128i *) (&next_block[16 * i]), state[i]); + } +} + +static void +generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, uint64_t *pseudo_rands) +{ + block address_block, input_block, tmp_block; + uint32_t i; + + init_block_value(&address_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + /* Temporary zero-initialized blocks */ + __m128i zero_block[ARGON2_OWORDS_IN_BLOCK]; + __m128i zero2_block[ARGON2_OWORDS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + init_block_value(&address_block, 0); + init_block_value(&tmp_block, 0); + /* Increasing index counter */ + input_block.v[6]++; + /* First iteration of G */ + fill_block_with_xor(zero_block, (uint8_t *) &input_block.v, + (uint8_t *) &tmp_block.v); + /* Second iteration of G */ + fill_block_with_xor(zero2_block, (uint8_t *) &tmp_block.v, + (uint8_t *) &address_block.v); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void +fill_segment_ssse3(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m128i state[ARGON2_OWORDS_IN_BLOCK]; + int data_independent_addressing = 1; + + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + + if (instance == NULL) { + return; + } + + if (instance->type == Argon2_id && + (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { + data_independent_addressing = 0; + } + + pseudo_rands = instance->pseudo_rands; + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->region->memory + prev_offset)->v), + ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { +#pragma warning(push) +#pragma warning(disable : 6385) + pseudo_rand = pseudo_rands[i]; +#pragma warning(pop) + } else { + pseudo_rand = instance->region->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->region->memory + + instance->lane_length * ref_lane + ref_index; + curr_block = instance->region->memory + curr_offset; + if (position.pass != 0) { + fill_block_with_xor(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } else { + fill_block(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } + } +} +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2.c new file mode 100644 index 0000000000..ac1628c991 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2.c @@ -0,0 +1,277 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" + +#include "argon2-core.h" +#include "argon2-encoding.h" +#include "argon2.h" + +int +argon2_ctx(argon2_context *context, argon2_type type) +{ + /* 1. Validate all inputs */ + int result = validate_inputs(context); + uint32_t memory_blocks, segment_length; + uint32_t pass; + argon2_instance_t instance; + + if (ARGON2_OK != result) { + return result; + } + + if (type != Argon2_id && type != Argon2_i) { + 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.region = NULL; + instance.passes = context->t_cost; + instance.current_pass = ~ 0U; + instance.memory_blocks = memory_blocks; + instance.segment_length = segment_length; + instance.lane_length = segment_length * ARGON2_SYNC_POINTS; + instance.lanes = context->lanes; + instance.threads = context->threads; + instance.type = type; + + /* 3. Initialization: Hashing inputs, allocating memory, filling first + * blocks + */ + result = initialize(&instance, context); + + if (ARGON2_OK != result) { + return result; + } + + /* 4. Filling memory */ + for (pass = 0; pass < instance.passes; pass++) { + fill_memory_blocks(&instance, pass); + } + + /* 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) +{ + argon2_context context; + int result; + uint8_t *out; + + if (pwdlen > ARGON2_MAX_PWD_LENGTH) { + return ARGON2_PWD_TOO_LONG; + } + + if (hashlen > ARGON2_MAX_OUTLEN) { + return ARGON2_OUTPUT_TOO_LONG; + } + + if (saltlen > ARGON2_MAX_SALT_LENGTH) { + return ARGON2_SALT_TOO_LONG; + } + + out = (uint8_t *) malloc(hashlen); + if (!out) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + context.out = (uint8_t *) out; + context.outlen = (uint32_t) hashlen; + context.pwd = (uint8_t *) pwd; + context.pwdlen = (uint32_t) pwdlen; + context.salt = (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.flags = ARGON2_DEFAULT_FLAGS; + + result = argon2_ctx(&context, type); + + if (result != ARGON2_OK) { + sodium_memzero(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) { + sodium_memzero(out, hashlen); + sodium_memzero(encoded, encodedlen); + free(out); + return ARGON2_ENCODING_FAIL; + } + } + + sodium_memzero(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); +} + +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); +} + +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); +} + +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); +} + +int +argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, + argon2_type type) +{ + argon2_context ctx; + uint8_t *out; + int decode_result; + int ret; + size_t encoded_len; + + memset(&ctx, 0, sizeof ctx); + + ctx.pwd = NULL; + ctx.pwdlen = 0; + ctx.secret = NULL; + ctx.secretlen = 0; + + /* max values, to be updated in decode_string */ + encoded_len = strlen(encoded); + if (encoded_len > UINT32_MAX) { + return ARGON2_DECODING_LENGTH_FAIL; + } + ctx.adlen = (uint32_t) encoded_len; + ctx.saltlen = (uint32_t) encoded_len; + ctx.outlen = (uint32_t) encoded_len; + + ctx.ad = (uint8_t *) malloc(ctx.adlen); + ctx.salt = (uint8_t *) malloc(ctx.saltlen); + ctx.out = (uint8_t *) malloc(ctx.outlen); + if (!ctx.out || !ctx.salt || !ctx.ad) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + out = (uint8_t *) malloc(ctx.outlen); + if (!out) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + decode_result = decode_string(&ctx, encoded, type); + if (decode_result != ARGON2_OK) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + free(out); + return decode_result; + } + + ret = argon2_hash(ctx.t_cost, ctx.m_cost, ctx.threads, pwd, pwdlen, + ctx.salt, ctx.saltlen, out, ctx.outlen, NULL, 0, type); + + free(ctx.ad); + free(ctx.salt); + + if (ret != ARGON2_OK || sodium_memcmp(out, ctx.out, ctx.outlen) != 0) { + ret = ARGON2_VERIFY_MISMATCH; + } + free(out); + free(ctx.out); + + return ret; +} + +int +argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) +{ + return argon2_verify(encoded, pwd, pwdlen, Argon2_i); +} + +int +argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) +{ + return argon2_verify(encoded, pwd, pwdlen, Argon2_id); +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2.h b/libs/libsodium/src/crypto_pwhash/argon2/argon2.h new file mode 100644 index 0000000000..85ca4dd373 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2.h @@ -0,0 +1,305 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef argon2_H +#define argon2_H + +#include <limits.h> +#include <stddef.h> +#include <stdint.h> + +/* + * 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(16) +#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 half the addressing space, topping at 2^32 blocks (4 TB) + */ +#define ARGON2_MAX_MEMORY_BITS \ + ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1)) +#define ARGON2_MAX_MEMORY \ + ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS) + +/* Minimum and maximum number of passes */ +#define ARGON2_MIN_TIME UINT32_C(1) +#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum password length in bytes */ +#define ARGON2_MIN_PWD_LENGTH UINT32_C(0) +#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum associated data length in bytes */ +#define ARGON2_MIN_AD_LENGTH UINT32_C(0) +#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum salt length in bytes */ +#define ARGON2_MIN_SALT_LENGTH UINT32_C(8) +#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum key length in bytes */ +#define ARGON2_MIN_SECRET UINT32_C(0) +#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) + +#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) +#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) +#define ARGON2_FLAG_CLEAR_MEMORY (UINT32_C(1) << 2) +#define ARGON2_DEFAULT_FLAGS (UINT32_C(0)) + +/* 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; + +/* 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 Argon2 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 flags; /* array of bool options */ +} argon2_context; + +/* Argon2 primitive type */ +typedef enum Argon2_type { Argon2_i = 1, Argon2_id = 2 } argon2_type; + +/* + * 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 + */ +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 + */ +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 Argon2id, 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 + */ +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); + +/** + * Hashes a password with Argon2i, producing a raw 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 + * @param hashlen Desired length of the hash in bytes + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +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); + +/** + * Hashes a password with Argon2id, producing a raw 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 + * @param hashlen Desired length of the hash in bytes + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +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 */ +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); + +/** + * 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 + */ +int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen); + +/** + * 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 + */ +int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen); + +/* generic function underlying the above ones */ +int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, + argon2_type type); +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.c b/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.c new file mode 100644 index 0000000000..f0364aca87 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.c @@ -0,0 +1,79 @@ +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "crypto_generichash_blake2b.h" +#include "private/common.h" +#include "utils.h" + +#include "blake2b-long.h" + +int +blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) +{ + uint8_t *out = (uint8_t *) pout; + crypto_generichash_blake2b_state blake_state; + uint8_t outlen_bytes[4 /* sizeof(uint32_t) */] = { 0 }; + int ret = -1; + + if (outlen > UINT32_MAX) { + goto fail; /* LCOV_EXCL_LINE */ + } + + /* Ensure little-endian byte order! */ + STORE32_LE(outlen_bytes, (uint32_t) outlen); + +#define TRY(statement) \ + do { \ + ret = statement; \ + if (ret < 0) { \ + goto fail; \ + } \ + } while ((void) 0, 0) + + if (outlen <= crypto_generichash_blake2b_BYTES_MAX) { + TRY(crypto_generichash_blake2b_init(&blake_state, NULL, 0U, outlen)); + TRY(crypto_generichash_blake2b_update(&blake_state, outlen_bytes, + sizeof(outlen_bytes))); + TRY(crypto_generichash_blake2b_update( + &blake_state, (const unsigned char *) in, inlen)); + TRY(crypto_generichash_blake2b_final(&blake_state, out, outlen)); + } else { + uint32_t toproduce; + uint8_t out_buffer[crypto_generichash_blake2b_BYTES_MAX]; + uint8_t in_buffer[crypto_generichash_blake2b_BYTES_MAX]; + TRY(crypto_generichash_blake2b_init( + &blake_state, NULL, 0U, crypto_generichash_blake2b_BYTES_MAX)); + TRY(crypto_generichash_blake2b_update(&blake_state, outlen_bytes, + sizeof(outlen_bytes))); + TRY(crypto_generichash_blake2b_update( + &blake_state, (const unsigned char *) in, inlen)); + TRY(crypto_generichash_blake2b_final( + &blake_state, out_buffer, crypto_generichash_blake2b_BYTES_MAX)); + memcpy(out, out_buffer, crypto_generichash_blake2b_BYTES_MAX / 2); + out += crypto_generichash_blake2b_BYTES_MAX / 2; + toproduce = + (uint32_t) outlen - crypto_generichash_blake2b_BYTES_MAX / 2; + + while (toproduce > crypto_generichash_blake2b_BYTES_MAX) { + memcpy(in_buffer, out_buffer, crypto_generichash_blake2b_BYTES_MAX); + TRY(crypto_generichash_blake2b( + out_buffer, crypto_generichash_blake2b_BYTES_MAX, in_buffer, + crypto_generichash_blake2b_BYTES_MAX, NULL, 0U)); + memcpy(out, out_buffer, crypto_generichash_blake2b_BYTES_MAX / 2); + out += crypto_generichash_blake2b_BYTES_MAX / 2; + toproduce -= crypto_generichash_blake2b_BYTES_MAX / 2; + } + + memcpy(in_buffer, out_buffer, crypto_generichash_blake2b_BYTES_MAX); + TRY(crypto_generichash_blake2b(out_buffer, toproduce, in_buffer, + crypto_generichash_blake2b_BYTES_MAX, + NULL, 0U)); + memcpy(out, out_buffer, toproduce); + } +fail: + sodium_memzero(&blake_state, sizeof(blake_state)); + return ret; +#undef TRY +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.h b/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.h new file mode 100644 index 0000000000..3d6d775521 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.h @@ -0,0 +1,8 @@ +#ifndef blake2b_long_H +#define blake2b_long_H + +#include <stddef.h> + +int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen); + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx2.h b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx2.h new file mode 100644 index 0000000000..f3dfa0f506 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx2.h @@ -0,0 +1,150 @@ +#ifndef blamka_round_avx2_H +#define blamka_round_avx2_H + +#include "private/common.h" +#include "private/sse2_64_32.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 diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx512f.h b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx512f.h new file mode 100644 index 0000000000..9a822402d8 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx512f.h @@ -0,0 +1,145 @@ +#ifndef blamka_round_avx512f_H +#define blamka_round_avx512f_H + +#include "private/common.h" +#include "private/sse2_64_32.h" + +#define ror64(x, n) _mm512_ror_epi64((x), (n)) + +static inline __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_AVX512F(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_AVX512F(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_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + G1_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2_AVX512F(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 diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ref.h b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ref.h new file mode 100644 index 0000000000..7a2c6eb20e --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ref.h @@ -0,0 +1,40 @@ +#ifndef blamka_round_ref_H +#define blamka_round_ref_H + +#include "private/common.h" + +/*designed by the Lyra PHC team */ +static inline uint64_t +fBlaMka(uint64_t x, uint64_t y) +{ + const uint64_t m = UINT64_C(0xFFFFFFFF); + const uint64_t xy = (x & m) * (y & m); + return x + y + 2 * xy; +} + +#define G(a, b, c, d) \ + do { \ + a = fBlaMka(a, b); \ + d = ROTR64(d ^ a, 32); \ + c = fBlaMka(c, d); \ + b = ROTR64(b ^ c, 24); \ + a = fBlaMka(a, b); \ + d = ROTR64(d ^ a, 16); \ + c = fBlaMka(c, d); \ + b = ROTR64(b ^ c, 63); \ + } while ((void) 0, 0) + +#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \ + v12, v13, v14, v15) \ + do { \ + G(v0, v4, v8, v12); \ + G(v1, v5, v9, v13); \ + G(v2, v6, v10, v14); \ + G(v3, v7, v11, v15); \ + G(v0, v5, v10, v15); \ + G(v1, v6, v11, v12); \ + G(v2, v7, v8, v13); \ + G(v3, v4, v9, v14); \ + } while ((void) 0, 0) + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ssse3.h b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ssse3.h new file mode 100644 index 0000000000..98a47b93f8 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ssse3.h @@ -0,0 +1,120 @@ +#ifndef blamka_round_ssse3_H +#define blamka_round_ssse3_H + +#include "private/common.h" +#include "private/sse2_64_32.h" + +#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)))) + +static 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) + +#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) + +#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void) 0, 0) + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2i.c b/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2i.c new file mode 100644 index 0000000000..0515bd6135 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2i.c @@ -0,0 +1,290 @@ + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "argon2-core.h" +#include "argon2-encoding.h" +#include "argon2.h" +#include "crypto_pwhash.h" +#include "crypto_pwhash_argon2i.h" +#include "crypto_pwhash_argon2id.h" +#include "private/common.h" +#include "randombytes.h" +#include "utils.h" + +#define STR_HASHBYTES 32U + +int +crypto_pwhash_argon2i_alg_argon2i13(void) +{ + return crypto_pwhash_argon2i_ALG_ARGON2I13; +} + +size_t +crypto_pwhash_argon2i_bytes_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_BYTES_MIN >= ARGON2_MIN_OUTLEN); + return crypto_pwhash_argon2i_BYTES_MIN; +} + +size_t +crypto_pwhash_argon2i_bytes_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_BYTES_MAX <= ARGON2_MAX_OUTLEN); + return crypto_pwhash_argon2i_BYTES_MAX; +} + +size_t +crypto_pwhash_argon2i_passwd_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_PASSWD_MIN >= ARGON2_MIN_PWD_LENGTH); + return crypto_pwhash_argon2i_PASSWD_MIN; +} + +size_t +crypto_pwhash_argon2i_passwd_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_PASSWD_MAX <= ARGON2_MAX_PWD_LENGTH); + return crypto_pwhash_argon2i_PASSWD_MAX; +} + +size_t +crypto_pwhash_argon2i_saltbytes(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_SALTBYTES >= ARGON2_MIN_SALT_LENGTH); + COMPILER_ASSERT(crypto_pwhash_argon2i_SALTBYTES <= ARGON2_MAX_SALT_LENGTH); + return crypto_pwhash_argon2i_SALTBYTES; +} + +size_t +crypto_pwhash_argon2i_strbytes(void) +{ + return crypto_pwhash_argon2i_STRBYTES; +} + +const char* +crypto_pwhash_argon2i_strprefix(void) +{ + return crypto_pwhash_argon2i_STRPREFIX; +} + +size_t +crypto_pwhash_argon2i_opslimit_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_OPSLIMIT_MIN >= ARGON2_MIN_TIME); + return crypto_pwhash_argon2i_OPSLIMIT_MIN; +} + +size_t +crypto_pwhash_argon2i_opslimit_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_OPSLIMIT_MAX <= ARGON2_MAX_TIME); + return crypto_pwhash_argon2i_OPSLIMIT_MAX; +} + +size_t +crypto_pwhash_argon2i_memlimit_min(void) +{ + COMPILER_ASSERT((crypto_pwhash_argon2i_MEMLIMIT_MIN / 1024U) >= ARGON2_MIN_MEMORY); + return crypto_pwhash_argon2i_MEMLIMIT_MIN; +} + +size_t +crypto_pwhash_argon2i_memlimit_max(void) +{ + COMPILER_ASSERT((crypto_pwhash_argon2i_MEMLIMIT_MAX / 1024U) <= ARGON2_MAX_MEMORY); + return crypto_pwhash_argon2i_MEMLIMIT_MAX; +} + +size_t +crypto_pwhash_argon2i_opslimit_interactive(void) +{ + return crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_argon2i_memlimit_interactive(void) +{ + return crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_argon2i_opslimit_moderate(void) +{ + return crypto_pwhash_argon2i_OPSLIMIT_MODERATE; +} + +size_t +crypto_pwhash_argon2i_memlimit_moderate(void) +{ + return crypto_pwhash_argon2i_MEMLIMIT_MODERATE; +} + +size_t +crypto_pwhash_argon2i_opslimit_sensitive(void) +{ + return crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_argon2i_memlimit_sensitive(void) +{ + return crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash_argon2i(unsigned char *const out, unsigned long long outlen, + const char *const passwd, unsigned long long passwdlen, + const unsigned char *const salt, + unsigned long long opslimit, size_t memlimit, int alg) +{ + memset(out, 0, outlen); + if (outlen > crypto_pwhash_argon2i_BYTES_MAX) { + errno = EFBIG; + return -1; + } + if (outlen < crypto_pwhash_argon2i_BYTES_MIN) { + errno = EINVAL; + return -1; + } + if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX || + opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX || + memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX) { + errno = EFBIG; + return -1; + } + if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN || + opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN || + memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN) { + errno = EINVAL; + return -1; + } + switch (alg) { + case crypto_pwhash_argon2i_ALG_ARGON2I13: + if (argon2i_hash_raw((uint32_t) opslimit, (uint32_t) (memlimit / 1024U), + (uint32_t) 1U, passwd, (size_t) passwdlen, salt, + (size_t) crypto_pwhash_argon2i_SALTBYTES, out, + (size_t) outlen) != ARGON2_OK) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; + default: + errno = EINVAL; + return -1; + } +} + +int +crypto_pwhash_argon2i_str(char out[crypto_pwhash_argon2i_STRBYTES], + const char *const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) +{ + unsigned char salt[crypto_pwhash_argon2i_SALTBYTES]; + + memset(out, 0, crypto_pwhash_argon2i_STRBYTES); + if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX || + opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX || + memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX) { + errno = EFBIG; + return -1; + } + if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN || + opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN || + memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN) { + errno = EINVAL; + return -1; + } + randombytes_buf(salt, sizeof salt); + if (argon2i_hash_encoded((uint32_t) opslimit, (uint32_t) (memlimit / 1024U), + (uint32_t) 1U, passwd, (size_t) passwdlen, salt, + sizeof salt, STR_HASHBYTES, out, + crypto_pwhash_argon2i_STRBYTES) != ARGON2_OK) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; +} + +int +crypto_pwhash_argon2i_str_verify(const char str[crypto_pwhash_argon2i_STRBYTES], + const char *const passwd, + unsigned long long passwdlen) +{ + int verify_ret; + + if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX) { + errno = EFBIG; + return -1; + } + /* LCOV_EXCL_START */ + if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN) { + errno = EINVAL; + return -1; + } + /* LCOV_EXCL_STOP */ + + verify_ret = argon2i_verify(str, passwd, (size_t) passwdlen); + if (verify_ret == ARGON2_OK) { + return 0; + } + if (verify_ret == ARGON2_VERIFY_MISMATCH) { + errno = EINVAL; + } + return -1; +} + +static int +_needs_rehash(const char *str, unsigned long long opslimit, size_t memlimit, + argon2_type type) +{ + unsigned char *fodder; + argon2_context ctx; + size_t fodder_len; + int ret = -1; + + fodder_len = strlen(str); + memlimit /= 1024U; + if (opslimit > UINT32_MAX || memlimit > UINT32_MAX || + fodder_len >= crypto_pwhash_STRBYTES) { + errno = EINVAL; + return -1; + } + memset(&ctx, 0, sizeof ctx); + if ((fodder = (unsigned char *) calloc(fodder_len, 1U)) == NULL) { + return -1; /* LCOV_EXCL_LINE */ + } + ctx.out = ctx.pwd = ctx.salt = fodder; + ctx.outlen = ctx.pwdlen = ctx.saltlen = (uint32_t) fodder_len; + ctx.ad = ctx.secret = NULL; + ctx.adlen = ctx.secretlen = 0U; + if (decode_string(&ctx, str, type) != 0) { + errno = EINVAL; + ret = -1; + } else if (ctx.t_cost != (uint32_t) opslimit || + ctx.m_cost != (uint32_t) memlimit) { + ret = 1; + } else { + ret = 0; + } + free(fodder); + + return ret; +} + +int +crypto_pwhash_argon2i_str_needs_rehash(const char str[crypto_pwhash_argon2i_STRBYTES], + unsigned long long opslimit, size_t memlimit) +{ + return _needs_rehash(str, opslimit, memlimit, Argon2_i); +} + +int +crypto_pwhash_argon2id_str_needs_rehash(const char str[crypto_pwhash_argon2id_STRBYTES], + unsigned long long opslimit, size_t memlimit) +{ + return _needs_rehash(str, opslimit, memlimit, Argon2_id); +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2id.c b/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2id.c new file mode 100644 index 0000000000..99d3e219bf --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2id.c @@ -0,0 +1,234 @@ + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "argon2-core.h" +#include "argon2.h" +#include "crypto_pwhash_argon2id.h" +#include "private/common.h" +#include "randombytes.h" +#include "utils.h" + +#define STR_HASHBYTES 32U + +int +crypto_pwhash_argon2id_alg_argon2id13(void) +{ + return crypto_pwhash_argon2id_ALG_ARGON2ID13; +} + +size_t +crypto_pwhash_argon2id_bytes_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_BYTES_MIN >= ARGON2_MIN_OUTLEN); + return crypto_pwhash_argon2id_BYTES_MIN; +} + +size_t +crypto_pwhash_argon2id_bytes_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_BYTES_MAX <= ARGON2_MAX_OUTLEN); + return crypto_pwhash_argon2id_BYTES_MAX; +} + +size_t +crypto_pwhash_argon2id_passwd_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_PASSWD_MIN >= ARGON2_MIN_PWD_LENGTH); + return crypto_pwhash_argon2id_PASSWD_MIN; +} + +size_t +crypto_pwhash_argon2id_passwd_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_PASSWD_MAX <= ARGON2_MAX_PWD_LENGTH); + return crypto_pwhash_argon2id_PASSWD_MAX; +} + +size_t +crypto_pwhash_argon2id_saltbytes(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_SALTBYTES >= ARGON2_MIN_SALT_LENGTH); + COMPILER_ASSERT(crypto_pwhash_argon2id_SALTBYTES <= ARGON2_MAX_SALT_LENGTH); + return crypto_pwhash_argon2id_SALTBYTES; +} + +size_t +crypto_pwhash_argon2id_strbytes(void) +{ + return crypto_pwhash_argon2id_STRBYTES; +} + +const char* +crypto_pwhash_argon2id_strprefix(void) +{ + return crypto_pwhash_argon2id_STRPREFIX; +} + +size_t +crypto_pwhash_argon2id_opslimit_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_OPSLIMIT_MIN >= ARGON2_MIN_TIME); + return crypto_pwhash_argon2id_OPSLIMIT_MIN; +} + +size_t +crypto_pwhash_argon2id_opslimit_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_OPSLIMIT_MAX <= ARGON2_MAX_TIME); + return crypto_pwhash_argon2id_OPSLIMIT_MAX; +} + +size_t +crypto_pwhash_argon2id_memlimit_min(void) +{ + COMPILER_ASSERT((crypto_pwhash_argon2id_MEMLIMIT_MIN / 1024U) >= ARGON2_MIN_MEMORY); + return crypto_pwhash_argon2id_MEMLIMIT_MIN; +} + +size_t +crypto_pwhash_argon2id_memlimit_max(void) +{ + COMPILER_ASSERT((crypto_pwhash_argon2id_MEMLIMIT_MAX / 1024U) <= ARGON2_MAX_MEMORY); + return crypto_pwhash_argon2id_MEMLIMIT_MAX; +} + +size_t +crypto_pwhash_argon2id_opslimit_interactive(void) +{ + return crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_argon2id_memlimit_interactive(void) +{ + return crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_argon2id_opslimit_moderate(void) +{ + return crypto_pwhash_argon2id_OPSLIMIT_MODERATE; +} + +size_t +crypto_pwhash_argon2id_memlimit_moderate(void) +{ + return crypto_pwhash_argon2id_MEMLIMIT_MODERATE; +} + +size_t +crypto_pwhash_argon2id_opslimit_sensitive(void) +{ + return crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_argon2id_memlimit_sensitive(void) +{ + return crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash_argon2id(unsigned char *const out, unsigned long long outlen, + const char *const passwd, unsigned long long passwdlen, + const unsigned char *const salt, + unsigned long long opslimit, size_t memlimit, int alg) +{ + memset(out, 0, outlen); + if (outlen > crypto_pwhash_argon2id_BYTES_MAX) { + errno = EFBIG; + return -1; + } + if (outlen < crypto_pwhash_argon2id_BYTES_MIN) { + errno = EINVAL; + return -1; + } + if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX || + opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX || + memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) { + errno = EFBIG; + return -1; + } + if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN || + opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN || + memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) { + errno = EINVAL; + return -1; + } + switch (alg) { + case crypto_pwhash_argon2id_ALG_ARGON2ID13: + if (argon2id_hash_raw((uint32_t) opslimit, (uint32_t) (memlimit / 1024U), + (uint32_t) 1U, passwd, (size_t) passwdlen, salt, + (size_t) crypto_pwhash_argon2id_SALTBYTES, out, + (size_t) outlen) != ARGON2_OK) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; + default: + errno = EINVAL; + return -1; + } +} + +int +crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES], + const char *const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) +{ + unsigned char salt[crypto_pwhash_argon2id_SALTBYTES]; + + memset(out, 0, crypto_pwhash_argon2id_STRBYTES); + if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX || + opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX || + memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) { + errno = EFBIG; + return -1; + } + if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN || + opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN || + memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) { + errno = EINVAL; + return -1; + } + randombytes_buf(salt, sizeof salt); + if (argon2id_hash_encoded((uint32_t) opslimit, (uint32_t) (memlimit / 1024U), + (uint32_t) 1U, passwd, (size_t) passwdlen, salt, + sizeof salt, STR_HASHBYTES, out, + crypto_pwhash_argon2id_STRBYTES) != ARGON2_OK) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; +} + +int +crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES], + const char *const passwd, + unsigned long long passwdlen) +{ + int verify_ret; + + if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX) { + errno = EFBIG; + return -1; + } + /* LCOV_EXCL_START */ + if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN) { + errno = EINVAL; + return -1; + } + /* LCOV_EXCL_STOP */ + + verify_ret = argon2id_verify(str, passwd, (size_t) passwdlen); + if (verify_ret == ARGON2_OK) { + return 0; + } + if (verify_ret == ARGON2_VERIFY_MISMATCH) { + errno = EINVAL; + } + return -1; +} diff --git a/libs/libsodium/src/crypto_pwhash/crypto_pwhash.c b/libs/libsodium/src/crypto_pwhash/crypto_pwhash.c new file mode 100644 index 0000000000..8168f96216 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/crypto_pwhash.c @@ -0,0 +1,211 @@ + +#include <errno.h> +#include <string.h> + +#include "core.h" +#include "crypto_pwhash.h" + +int +crypto_pwhash_alg_argon2i13(void) +{ + return crypto_pwhash_ALG_ARGON2I13; +} + +int +crypto_pwhash_alg_argon2id13(void) +{ + return crypto_pwhash_ALG_ARGON2ID13; +} + +int +crypto_pwhash_alg_default(void) +{ + return crypto_pwhash_ALG_DEFAULT; +} + +size_t +crypto_pwhash_bytes_min(void) +{ + return crypto_pwhash_BYTES_MIN; +} + +size_t +crypto_pwhash_bytes_max(void) +{ + return crypto_pwhash_BYTES_MAX; +} + +size_t +crypto_pwhash_passwd_min(void) +{ + return crypto_pwhash_PASSWD_MIN; +} + +size_t +crypto_pwhash_passwd_max(void) +{ + return crypto_pwhash_PASSWD_MAX; +} + +size_t +crypto_pwhash_saltbytes(void) +{ + return crypto_pwhash_SALTBYTES; +} + +size_t +crypto_pwhash_strbytes(void) +{ + return crypto_pwhash_STRBYTES; +} + +const char * +crypto_pwhash_strprefix(void) +{ + return crypto_pwhash_STRPREFIX; +} + +size_t +crypto_pwhash_opslimit_min(void) +{ + return crypto_pwhash_OPSLIMIT_MIN; +} + +size_t +crypto_pwhash_opslimit_max(void) +{ + return crypto_pwhash_OPSLIMIT_MAX; +} + +size_t +crypto_pwhash_memlimit_min(void) +{ + return crypto_pwhash_MEMLIMIT_MIN; +} + +size_t +crypto_pwhash_memlimit_max(void) +{ + return crypto_pwhash_MEMLIMIT_MAX; +} + +size_t +crypto_pwhash_opslimit_interactive(void) +{ + return crypto_pwhash_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_memlimit_interactive(void) +{ + return crypto_pwhash_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_opslimit_moderate(void) +{ + return crypto_pwhash_OPSLIMIT_MODERATE; +} + +size_t +crypto_pwhash_memlimit_moderate(void) +{ + return crypto_pwhash_MEMLIMIT_MODERATE; +} + +size_t +crypto_pwhash_opslimit_sensitive(void) +{ + return crypto_pwhash_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_memlimit_sensitive(void) +{ + return crypto_pwhash_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash(unsigned char * const out, unsigned long long outlen, + const char * const passwd, unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, size_t memlimit, int alg) +{ + switch (alg) { + case crypto_pwhash_ALG_ARGON2I13: + return crypto_pwhash_argon2i(out, outlen, passwd, passwdlen, salt, + opslimit, memlimit, alg); + case crypto_pwhash_ALG_ARGON2ID13: + return crypto_pwhash_argon2id(out, outlen, passwd, passwdlen, salt, + opslimit, memlimit, alg); + default: + errno = EINVAL; + return -1; + } +} + +int +crypto_pwhash_str(char out[crypto_pwhash_STRBYTES], + const char * const passwd, unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) +{ + return crypto_pwhash_argon2id_str(out, passwd, passwdlen, + opslimit, memlimit); +} + +int +crypto_pwhash_str_alg(char out[crypto_pwhash_STRBYTES], + const char * const passwd, unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit, int alg) +{ + switch (alg) { + case crypto_pwhash_ALG_ARGON2I13: + return crypto_pwhash_argon2i_str(out, passwd, passwdlen, + opslimit, memlimit); + case crypto_pwhash_ALG_ARGON2ID13: + return crypto_pwhash_argon2id_str(out, passwd, passwdlen, + opslimit, memlimit); + } + sodium_misuse(); + /* NOTREACHED */ +} + +int +crypto_pwhash_str_verify(const char str[crypto_pwhash_STRBYTES], + const char * const passwd, + unsigned long long passwdlen) +{ + if (strncmp(str, crypto_pwhash_argon2id_STRPREFIX, + sizeof crypto_pwhash_argon2id_STRPREFIX - 1) == 0) { + return crypto_pwhash_argon2id_str_verify(str, passwd, passwdlen); + } + if (strncmp(str, crypto_pwhash_argon2i_STRPREFIX, + sizeof crypto_pwhash_argon2i_STRPREFIX - 1) == 0) { + return crypto_pwhash_argon2i_str_verify(str, passwd, passwdlen); + } + errno = EINVAL; + + return -1; +} + +int +crypto_pwhash_str_needs_rehash(const char str[crypto_pwhash_STRBYTES], + unsigned long long opslimit, size_t memlimit) +{ + if (strncmp(str, crypto_pwhash_argon2id_STRPREFIX, + sizeof crypto_pwhash_argon2id_STRPREFIX - 1) == 0) { + return crypto_pwhash_argon2id_str_needs_rehash(str, opslimit, memlimit); + } + if (strncmp(str, crypto_pwhash_argon2i_STRPREFIX, + sizeof crypto_pwhash_argon2i_STRPREFIX - 1) == 0) { + return crypto_pwhash_argon2i_str_needs_rehash(str, opslimit, memlimit); + } + errno = EINVAL; + + return -1; +} + +const char * +crypto_pwhash_primitive(void) { + return crypto_pwhash_PRIMITIVE; +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c new file mode 100644 index 0000000000..e15e12b294 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c @@ -0,0 +1,263 @@ +/*- + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdint.h> +#include <string.h> + +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "crypto_scrypt.h" +#include "private/common.h" +#include "runtime.h" +#include "utils.h" + +static const char *const itoa64 = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static uint8_t * +encode64_uint32(uint8_t *dst, size_t dstlen, uint32_t src, uint32_t srcbits) +{ + uint32_t bit; + + for (bit = 0; bit < srcbits; bit += 6) { + if (dstlen < 1) { + return NULL; /* LCOV_EXCL_LINE */ + } + *dst++ = itoa64[src & 0x3f]; + dstlen--; + src >>= 6; + } + return dst; +} + +static uint8_t * +encode64(uint8_t *dst, size_t dstlen, const uint8_t *src, size_t srclen) +{ + size_t i; + + for (i = 0; i < srclen;) { + uint8_t *dnext; + uint32_t value = 0, bits = 0; + + do { + value |= (uint32_t) src[i++] << bits; + bits += 8; + } while (bits < 24 && i < srclen); + + dnext = encode64_uint32(dst, dstlen, value, bits); + if (!dnext) { + return NULL; /* LCOV_EXCL_LINE */ + } + dstlen -= dnext - dst; + dst = dnext; + } + return dst; +} + +static int +decode64_one(uint32_t *dst, uint8_t src) +{ + const char *ptr = strchr(itoa64, src); + + if (ptr) { + *dst = (uint32_t)(ptr - itoa64); + return 0; + } + *dst = 0; + + return -1; +} + +static const uint8_t * +decode64_uint32(uint32_t *dst, uint32_t dstbits, const uint8_t *src) +{ + uint32_t bit; + uint32_t value; + + value = 0; + for (bit = 0; bit < dstbits; bit += 6) { + uint32_t one; + if (decode64_one(&one, *src)) { + *dst = 0; + return NULL; + } + src++; + value |= one << bit; + } + *dst = value; + + return src; +} + +const uint8_t * +escrypt_parse_setting(const uint8_t *setting, + uint32_t *N_log2_p, uint32_t *r_p, uint32_t *p_p) +{ + const uint8_t *src; + + if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') { + return NULL; + } + src = setting + 3; + + if (decode64_one(N_log2_p, *src)) { + return NULL; + } + src++; + + src = decode64_uint32(r_p, 30, src); + if (!src) { + return NULL; + } + + src = decode64_uint32(p_p, 30, src); + if (!src) { + return NULL; + } + return src; +} + +uint8_t * +escrypt_r(escrypt_local_t *local, const uint8_t *passwd, size_t passwdlen, + const uint8_t *setting, uint8_t *buf, size_t buflen) +{ + uint8_t hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES]; + escrypt_kdf_t escrypt_kdf; + const uint8_t *src; + const uint8_t *salt; + uint8_t *dst; + size_t prefixlen; + size_t saltlen; + size_t need; + uint64_t N; + uint32_t N_log2; + uint32_t r; + uint32_t p; + + src = escrypt_parse_setting(setting, &N_log2, &r, &p); + if (!src) { + return NULL; + } + N = (uint64_t) 1 << N_log2; + prefixlen = src - setting; + + salt = src; + src = (uint8_t *) strrchr((char *) salt, '$'); + if (src) { + saltlen = src - salt; + } else { + saltlen = strlen((char *) salt); + } + need = prefixlen + saltlen + 1 + + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1; + if (need > buflen || need < saltlen) { + return NULL; + } +#ifdef HAVE_EMMINTRIN_H + escrypt_kdf = + sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; +#else + escrypt_kdf = escrypt_kdf_nosse; +#endif + if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen, N, r, p, hash, + sizeof(hash))) { + return NULL; + } + dst = buf; + memcpy(dst, setting, prefixlen + saltlen); + dst += prefixlen + saltlen; + *dst++ = '$'; + + dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash)); + sodium_memzero(hash, sizeof hash); + if (!dst || dst >= buf + buflen) { + return NULL; /* Can't happen LCOV_EXCL_LINE */ + } + *dst = 0; /* NUL termination */ + + return buf; +} + +uint8_t * +escrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, const uint8_t *src, + size_t srclen, uint8_t *buf, size_t buflen) +{ + uint8_t *dst; + size_t prefixlen = + (sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */); + size_t saltlen = BYTES2CHARS(srclen); + size_t need; + + need = prefixlen + saltlen + 1; + if (need > buflen || need < saltlen || saltlen < srclen) { + return NULL; /* LCOV_EXCL_LINE */ + } + if (N_log2 > 63 || ((uint64_t) r * (uint64_t) p >= (1U << 30))) { + return NULL; /* LCOV_EXCL_LINE */ + } + dst = buf; + *dst++ = '$'; + *dst++ = '7'; + *dst++ = '$'; + + *dst++ = itoa64[N_log2]; + + dst = encode64_uint32(dst, buflen - (dst - buf), r, 30); + if (!dst) { + return NULL; /* Can't happen LCOV_EXCL_LINE */ + } + dst = encode64_uint32(dst, buflen - (dst - buf), p, 30); + if (!dst) { + return NULL; /* Can't happen LCOV_EXCL_LINE */ + } + dst = encode64(dst, buflen - (dst - buf), src, srclen); + if (!dst || dst >= buf + buflen) { + return NULL; /* Can't happen LCOV_EXCL_LINE */ + } + *dst = 0; /* NUL termination */ + + return buf; +} + +int +crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t *passwd, size_t passwdlen, + const uint8_t *salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, + uint8_t *buf, size_t buflen) +{ + escrypt_kdf_t escrypt_kdf; + escrypt_local_t local; + int retval; + + if (escrypt_init_local(&local)) { + return -1; /* LCOV_EXCL_LINE */ + } +#if defined(HAVE_EMMINTRIN_H) + escrypt_kdf = + sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; +#else + escrypt_kdf = escrypt_kdf_nosse; +#endif + retval = escrypt_kdf(&local, passwd, passwdlen, salt, saltlen, N, r, p, buf, + buflen); + if (escrypt_free_local(&local)) { + return -1; /* LCOV_EXCL_LINE */ + } + return retval; +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h new file mode 100644 index 0000000000..83101967c3 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h @@ -0,0 +1,98 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef crypto_scrypt_H +#define crypto_scrypt_H + +#include <limits.h> +#include <stddef.h> +#include <stdint.h> + +#if SIZE_MAX > 0xffffffffULL +#define ARCH_BITS 64 +#else +#define ARCH_BITS 32 +#endif + +#define crypto_pwhash_scryptsalsa208sha256_STRPREFIXBYTES 14 +#define crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES 57 +#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES 32 +#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES_ENCODED 43 +#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES 32 +#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED 43 + +#define BYTES2CHARS(bytes) ((((bytes) *8) + 5) / 6) + +typedef struct { + void * base, *aligned; + size_t size; +} escrypt_region_t; + +typedef union { + uint64_t d[8]; + uint32_t w[16]; +} escrypt_block_t; + +typedef escrypt_region_t escrypt_local_t; + +extern int escrypt_init_local(escrypt_local_t *__local); + +extern int escrypt_free_local(escrypt_local_t *__local); + +extern void *alloc_region(escrypt_region_t *region, size_t size); +extern int free_region(escrypt_region_t *region); + +typedef int (*escrypt_kdf_t)(escrypt_local_t *__local, const uint8_t *__passwd, + size_t __passwdlen, const uint8_t *__salt, + size_t __saltlen, uint64_t __N, uint32_t __r, + uint32_t __p, uint8_t *__buf, size_t __buflen); + +extern int escrypt_kdf_nosse(escrypt_local_t *__local, const uint8_t *__passwd, + size_t __passwdlen, const uint8_t *__salt, + size_t __saltlen, uint64_t __N, uint32_t __r, + uint32_t __p, uint8_t *__buf, size_t __buflen); + +extern int escrypt_kdf_sse(escrypt_local_t *__local, const uint8_t *__passwd, + size_t __passwdlen, const uint8_t *__salt, + size_t __saltlen, uint64_t __N, uint32_t __r, + uint32_t __p, uint8_t *__buf, size_t __buflen); + +extern uint8_t *escrypt_r(escrypt_local_t *__local, const uint8_t *__passwd, + size_t __passwdlen, const uint8_t *__setting, + uint8_t *__buf, size_t __buflen); + +extern uint8_t *escrypt_gensalt_r(uint32_t __N_log2, uint32_t __r, uint32_t __p, + const uint8_t *__src, size_t __srclen, + uint8_t *__buf, size_t __buflen); + +extern const uint8_t *escrypt_parse_setting(const uint8_t *setting, + uint32_t *N_log2_p, uint32_t *r_p, + uint32_t *p_p); + +#endif /* !_CRYPTO_SCRYPT_H_ */ diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c new file mode 100644 index 0000000000..9e31352dc2 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c @@ -0,0 +1,375 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "../crypto_scrypt.h" +#include "../pbkdf2-sha256.h" +#include "private/common.h" + +static inline void +blkcpy_64(escrypt_block_t *dest, const escrypt_block_t *src) +{ + int i; + +#if (ARCH_BITS == 32) + for (i = 0; i < 16; ++i) { + dest->w[i] = src->w[i]; + } +#else + for (i = 0; i < 8; ++i) { + dest->d[i] = src->d[i]; + } +#endif +} + +static inline void +blkxor_64(escrypt_block_t *dest, const escrypt_block_t *src) +{ + int i; + +#if (ARCH_BITS == 32) + for (i = 0; i < 16; ++i) { + dest->w[i] ^= src->w[i]; + } +#else + for (i = 0; i < 8; ++i) { + dest->d[i] ^= src->d[i]; + } +#endif +} + +static inline void +blkcpy(escrypt_block_t *dest, const escrypt_block_t *src, size_t len) +{ + size_t i, L; + +#if (ARCH_BITS == 32) + L = (len >> 2); + for (i = 0; i < L; ++i) { + dest->w[i] = src->w[i]; + } +#else + L = (len >> 3); + for (i = 0; i < L; ++i) { + dest->d[i] = src->d[i]; + } +#endif +} + +static inline void +blkxor(escrypt_block_t *dest, const escrypt_block_t *src, size_t len) +{ + size_t i, L; + +#if (ARCH_BITS == 32) + L = (len >> 2); + for (i = 0; i < L; ++i) { + dest->w[i] ^= src->w[i]; + } +#else + L = (len >> 3); + for (i = 0; i < L; ++i) { + dest->d[i] ^= src->d[i]; + } +#endif +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + escrypt_block_t X; + uint32_t *x = X.w; + size_t i; + + blkcpy_64(&X, (escrypt_block_t *) B); + for (i = 0; i < 8; i += 2) { +#define R(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[4] ^= R(x[0] + x[12], 7); + x[8] ^= R(x[4] + x[0], 9); + x[12] ^= R(x[8] + x[4], 13); + x[0] ^= R(x[12] + x[8], 18); + + x[9] ^= R(x[5] + x[1], 7); + x[13] ^= R(x[9] + x[5], 9); + x[1] ^= R(x[13] + x[9], 13); + x[5] ^= R(x[1] + x[13], 18); + + x[14] ^= R(x[10] + x[6], 7); + x[2] ^= R(x[14] + x[10], 9); + x[6] ^= R(x[2] + x[14], 13); + x[10] ^= R(x[6] + x[2], 18); + + x[3] ^= R(x[15] + x[11], 7); + x[7] ^= R(x[3] + x[15], 9); + x[11] ^= R(x[7] + x[3], 13); + x[15] ^= R(x[11] + x[7], 18); + + /* Operate on rows. */ + x[1] ^= R(x[0] + x[3], 7); + x[2] ^= R(x[1] + x[0], 9); + x[3] ^= R(x[2] + x[1], 13); + x[0] ^= R(x[3] + x[2], 18); + + x[6] ^= R(x[5] + x[4], 7); + x[7] ^= R(x[6] + x[5], 9); + x[4] ^= R(x[7] + x[6], 13); + x[5] ^= R(x[4] + x[7], 18); + + x[11] ^= R(x[10] + x[9], 7); + x[8] ^= R(x[11] + x[10], 9); + x[9] ^= R(x[8] + x[11], 13); + x[10] ^= R(x[9] + x[8], 18); + + x[12] ^= R(x[15] + x[14], 7); + x[13] ^= R(x[12] + x[15], 9); + x[14] ^= R(x[13] + x[12], 13); + x[15] ^= R(x[14] + x[13], 18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const uint32_t *Bin, uint32_t *Bout, uint32_t *X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy_64((escrypt_block_t *) X, + (escrypt_block_t *) &Bin[(2 * r - 1) * 16]); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor_64((escrypt_block_t *) X, (escrypt_block_t *) &Bin[i * 16]); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy_64((escrypt_block_t *) &Bout[i * 8], (escrypt_block_t *) X); + + /* 3: X <-- H(X \xor B_i) */ + blkxor_64((escrypt_block_t *) X, (escrypt_block_t *) &Bin[i * 16 + 16]); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy_64((escrypt_block_t *) &Bout[i * 8 + r * 16], + (escrypt_block_t *) X); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint64_t +integerify(const void *B, size_t r) +{ + const uint32_t *X = (const uint32_t *) ((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t *B, size_t r, uint64_t N, uint32_t *V, uint32_t *XY) +{ + uint32_t *X = XY; + uint32_t *Y = &XY[32 * r]; + uint32_t *Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) { + X[k] = LOAD32_LE(&B[4 * k]); + } + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy((escrypt_block_t *) &V[i * (32 * r)], (escrypt_block_t *) X, + 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy((escrypt_block_t *) &V[(i + 1) * (32 * r)], + (escrypt_block_t *) Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor((escrypt_block_t *) X, (escrypt_block_t *) &V[j * (32 * r)], + 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor((escrypt_block_t *) Y, (escrypt_block_t *) &V[j * (32 * r)], + 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) { + STORE32_LE(&B[4 * k], X[k]); + } +} + +/** + * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + * N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +escrypt_kdf_nosse(escrypt_local_t *local, const uint8_t *passwd, + size_t passwdlen, const uint8_t *salt, size_t saltlen, + uint64_t N, uint32_t _r, uint32_t _p, uint8_t *buf, + size_t buflen) +{ + size_t B_size, V_size, XY_size, need; + uint8_t * B; + uint32_t *V, *XY; + size_t r = _r, p = _p; + uint32_t i; + +/* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= ((uint64_t) 1 << 30)) { + errno = EFBIG; + return -1; + } + if (N > UINT32_MAX) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + return -1; + } + if (r == 0 || p == 0) { + errno = EINVAL; + return -1; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } + + /* Allocate memory. */ + B_size = (size_t) 128 * r * p; + V_size = (size_t) 128 * r * (size_t) N; + need = B_size + V_size; + if (need < V_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t) 256 * r + 64; + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (local->size < need) { + if (free_region(local)) { + return -1; + } + if (!alloc_region(local, need)) { + return -1; + } + } + B = (uint8_t *) local->aligned; + V = (uint32_t *) ((uint8_t *) B + B_size); + XY = (uint32_t *) ((uint8_t *) V + V_size); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[(size_t) 128 * i * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* Success! */ + return 0; +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c new file mode 100644 index 0000000000..42cab61fe2 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c @@ -0,0 +1,95 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> + +#include "core.h" +#include "crypto_auth_hmacsha256.h" +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "pbkdf2-sha256.h" +#include "private/common.h" +#include "utils.h" + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, + size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen) +{ + crypto_auth_hmacsha256_state PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + +#if SIZE_MAX > 0x1fffffffe0ULL + COMPILER_ASSERT(crypto_pwhash_scryptsalsa208sha256_BYTES_MAX + <= 0x1fffffffe0ULL); + if (dkLen > 0x1fffffffe0ULL) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#endif + crypto_auth_hmacsha256_init(&PShctx, passwd, passwdlen); + crypto_auth_hmacsha256_update(&PShctx, salt, saltlen); + + for (i = 0; i * 32 < dkLen; i++) { + STORE32_BE(ivec, (uint32_t)(i + 1)); + memcpy(&hctx, &PShctx, sizeof(crypto_auth_hmacsha256_state)); + crypto_auth_hmacsha256_update(&hctx, ivec, 4); + crypto_auth_hmacsha256_final(&hctx, U); + + memcpy(T, U, 32); + /* LCOV_EXCL_START */ + for (j = 2; j <= c; j++) { + crypto_auth_hmacsha256_init(&hctx, passwd, passwdlen); + crypto_auth_hmacsha256_update(&hctx, U, 32); + crypto_auth_hmacsha256_final(&hctx, U); + + for (k = 0; k < 32; k++) { + T[k] ^= U[k]; + } + } + /* LCOV_EXCL_STOP */ + + clen = dkLen - i * 32; + if (clen > 32) { + clen = 32; + } + memcpy(&buf[i * 32], T, clen); + } + sodium_memzero((void *) &PShctx, sizeof PShctx); +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h new file mode 100644 index 0000000000..f9598c87aa --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h @@ -0,0 +1,45 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef pbkdf2_sha256_H +#define pbkdf2_sha256_H + +#include <stdint.h> + +#include <sys/types.h> + +#include "crypto_auth_hmacsha256.h" + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, + uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c new file mode 100644 index 0000000000..d1afd91afe --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c @@ -0,0 +1,285 @@ + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "crypto_scrypt.h" +#include "private/common.h" +#include "randombytes.h" +#include "utils.h" + +#define SETTING_SIZE(saltbytes) \ + ((sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */) + \ + BYTES2CHARS(saltbytes)) + +static int +pickparams(unsigned long long opslimit, const size_t memlimit, + uint32_t *const N_log2, uint32_t *const p, uint32_t *const r) +{ + unsigned long long maxN; + unsigned long long maxrp; + + if (opslimit < 32768) { + opslimit = 32768; + } + *r = 8; + if (opslimit < memlimit / 32) { + *p = 1; + maxN = opslimit / (*r * 4); + for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { + if ((uint64_t)(1) << *N_log2 > maxN / 2) { + break; + } + } + } else { + maxN = memlimit / ((size_t) *r * 128); + for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { + if ((uint64_t)(1) << *N_log2 > maxN / 2) { + break; + } + } + maxrp = (opslimit / 4) / ((uint64_t)(1) << *N_log2); + /* LCOV_EXCL_START */ + if (maxrp > 0x3fffffff) { + maxrp = 0x3fffffff; + } + /* LCOV_EXCL_STOP */ + *p = (uint32_t)(maxrp) / *r; + } + return 0; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_bytes_min(void) +{ + return crypto_pwhash_scryptsalsa208sha256_BYTES_MIN; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_bytes_max(void) +{ + return crypto_pwhash_scryptsalsa208sha256_BYTES_MAX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_passwd_min(void) +{ + return crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_passwd_max(void) +{ + return crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_saltbytes(void) +{ + return crypto_pwhash_scryptsalsa208sha256_SALTBYTES; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_strbytes(void) +{ + return crypto_pwhash_scryptsalsa208sha256_STRBYTES; +} + +const char * +crypto_pwhash_scryptsalsa208sha256_strprefix(void) +{ + return crypto_pwhash_scryptsalsa208sha256_STRPREFIX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_min(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_max(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_min(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_max(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash_scryptsalsa208sha256(unsigned char *const out, + unsigned long long outlen, + const char *const passwd, + unsigned long long passwdlen, + const unsigned char *const salt, + unsigned long long opslimit, size_t memlimit) +{ + uint32_t N_log2; + uint32_t p; + uint32_t r; + + memset(out, 0, outlen); + if (passwdlen > crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX || + outlen > crypto_pwhash_scryptsalsa208sha256_BYTES_MAX) { + errno = EFBIG; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + if (outlen < crypto_pwhash_scryptsalsa208sha256_BYTES_MIN || + pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + return crypto_pwhash_scryptsalsa208sha256_ll( + (const uint8_t *) passwd, (size_t) passwdlen, (const uint8_t *) salt, + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, (uint64_t)(1) << N_log2, + r, p, out, (size_t) outlen); +} + +int +crypto_pwhash_scryptsalsa208sha256_str( + char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char *const passwd, unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) +{ + uint8_t salt[crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES]; + char setting[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U]; + escrypt_local_t escrypt_local; + uint32_t N_log2; + uint32_t p; + uint32_t r; + + memset(out, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES); + if (passwdlen > crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX) { + errno = EFBIG; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + if (passwdlen < crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN || + pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + randombytes_buf(salt, sizeof salt); + if (escrypt_gensalt_r(N_log2, r, p, salt, sizeof salt, (uint8_t *) setting, + sizeof setting) == NULL) { + errno = EINVAL; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + if (escrypt_init_local(&escrypt_local) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, + (const uint8_t *) setting, (uint8_t *) out, + crypto_pwhash_scryptsalsa208sha256_STRBYTES) == NULL) { + /* LCOV_EXCL_START */ + escrypt_free_local(&escrypt_local); + errno = EINVAL; + return -1; + /* LCOV_EXCL_STOP */ + } + escrypt_free_local(&escrypt_local); + + COMPILER_ASSERT( + SETTING_SIZE(crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES) == + crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES); + COMPILER_ASSERT( + crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U + + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1U == + crypto_pwhash_scryptsalsa208sha256_STRBYTES); + + return 0; +} + +int +crypto_pwhash_scryptsalsa208sha256_str_verify( + const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char *const passwd, unsigned long long passwdlen) +{ + char wanted[crypto_pwhash_scryptsalsa208sha256_STRBYTES]; + escrypt_local_t escrypt_local; + int ret = -1; + + if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) != + &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) { + return -1; + } + if (escrypt_init_local(&escrypt_local) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + memset(wanted, 0, sizeof wanted); + if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, + (const uint8_t *) str, (uint8_t *) wanted, + sizeof wanted) == NULL) { + escrypt_free_local(&escrypt_local); + return -1; + } + escrypt_free_local(&escrypt_local); + ret = sodium_memcmp(wanted, str, sizeof wanted); + sodium_memzero(wanted, sizeof wanted); + + return ret; +} + +int +crypto_pwhash_scryptsalsa208sha256_str_needs_rehash( + const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + unsigned long long opslimit, size_t memlimit) +{ + uint32_t N_log2, N_log2_; + uint32_t p, p_; + uint32_t r, r_; + + if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; + return -1; + } + if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) != + &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) { + errno = EINVAL; + return -1; + } + if (escrypt_parse_setting((const uint8_t *) str, + &N_log2_, &r_, &p_) == NULL) { + errno = EINVAL; + return -1; + } + if (N_log2 != N_log2_ || r != r_ || p != p_) { + return 1; + } + return 0; +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c new file mode 100644 index 0000000000..139a7df286 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c @@ -0,0 +1,108 @@ +/*- + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <errno.h> +#include <stdlib.h> + +#include "crypto_scrypt.h" +#include "runtime.h" + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +# define MAP_ANON MAP_ANONYMOUS +#endif +#ifndef MAP_NOCORE +# define MAP_NOCORE 0 +#endif +#ifndef MAP_POPULATE +# define MAP_POPULATE 0 +#endif + +void * +alloc_region(escrypt_region_t *region, size_t size) +{ + uint8_t *base, *aligned; +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if ((base = (uint8_t *) mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_NOCORE | MAP_POPULATE, + -1, 0)) == MAP_FAILED) { + base = NULL; /* LCOV_EXCL_LINE */ + } /* LCOV_EXCL_LINE */ + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **) &base, 64, size)) != 0) { + base = NULL; + } + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) + errno = ENOMEM; + else if ((base = (uint8_t *) malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t) aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->size = base ? size : 0; + + return aligned; +} + +static inline void +init_region(escrypt_region_t *region) +{ + region->base = region->aligned = NULL; + region->size = 0; +} + +int +free_region(escrypt_region_t *region) +{ + if (region->base) { +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if (munmap(region->base, region->size)) { + return -1; /* LCOV_EXCL_LINE */ + } +#else + free(region->base); +#endif + } + init_region(region); + + return 0; +} + +int +escrypt_init_local(escrypt_local_t *local) +{ + init_region(local); + + return 0; +} + +int +escrypt_free_local(escrypt_local_t *local) +{ + return free_region(local); +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c new file mode 100644 index 0000000000..754a19fdb8 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c @@ -0,0 +1,400 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2012,2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "private/common.h" +#include "private/sse2_64_32.h" + +#ifdef HAVE_EMMINTRIN_H + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# endif +# include <emmintrin.h> +# if defined(__XOP__) && defined(DISABLED) +# include <x86intrin.h> +# endif + +# include "../crypto_scrypt.h" +# include "../pbkdf2-sha256.h" + +# if defined(__XOP__) && defined(DISABLED) +# define ARX(out, in1, in2, s) \ + out = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s)); +# else +# define ARX(out, in1, in2, s) \ + { \ + __m128i T = _mm_add_epi32(in1, in2); \ + out = _mm_xor_si128(out, _mm_slli_epi32(T, s)); \ + out = _mm_xor_si128(out, _mm_srli_epi32(T, 32 - s)); \ + } +# endif + +# define SALSA20_2ROUNDS \ + /* Operate on "columns". */ \ + ARX(X1, X0, X3, 7) \ + ARX(X2, X1, X0, 9) \ + ARX(X3, X2, X1, 13) \ + ARX(X0, X3, X2, 18) \ + \ + /* Rearrange data. */ \ + X1 = _mm_shuffle_epi32(X1, 0x93); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x39); \ + \ + /* Operate on "rows". */ \ + ARX(X3, X0, X1, 7) \ + ARX(X2, X3, X0, 9) \ + ARX(X1, X2, X3, 13) \ + ARX(X0, X1, X2, 18) \ + \ + /* Rearrange data. */ \ + X1 = _mm_shuffle_epi32(X1, 0x39); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x93); + +/** + * Apply the salsa20/8 core to the block provided in (X0 ... X3) ^ (Z0 ... Z3). + */ +# define SALSA20_8_XOR(in, out) \ + { \ + __m128i Y0 = X0 = _mm_xor_si128(X0, (in)[0]); \ + __m128i Y1 = X1 = _mm_xor_si128(X1, (in)[1]); \ + __m128i Y2 = X2 = _mm_xor_si128(X2, (in)[2]); \ + __m128i Y3 = X3 = _mm_xor_si128(X3, (in)[3]); \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS(out)[0] = X0 = _mm_add_epi32(X0, Y0); \ + (out)[1] = X1 = _mm_add_epi32(X1, Y1); \ + (out)[2] = X2 = _mm_add_epi32(X2, Y2); \ + (out)[3] = X3 = _mm_add_epi32(X3, Y3); \ + } + +/** + * blockmix_salsa8(Bin, Bout, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. + */ +static inline void +blockmix_salsa8(const __m128i *Bin, __m128i *Bout, size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + X0 = Bin[8 * r - 4]; + X1 = Bin[8 * r - 3]; + X2 = Bin[8 * r - 2]; + X3 = Bin[8 * r - 1]; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(Bin, Bout) + + /* 2: for i = 0 to 2r - 1 do */ + r--; + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8], &Bout[i * 4]) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) +} + +# define XOR4(in) \ + X0 = _mm_xor_si128(X0, (in)[0]); \ + X1 = _mm_xor_si128(X1, (in)[1]); \ + X2 = _mm_xor_si128(X2, (in)[2]); \ + X3 = _mm_xor_si128(X3, (in)[3]); + +# define XOR4_2(in1, in2) \ + X0 = _mm_xor_si128((in1)[0], (in2)[0]); \ + X1 = _mm_xor_si128((in1)[1], (in2)[1]); \ + X2 = _mm_xor_si128((in1)[2], (in2)[2]); \ + X3 = _mm_xor_si128((in1)[3], (in2)[3]); + +static inline uint32_t +blockmix_salsa8_xor(const __m128i *Bin1, const __m128i *Bin2, __m128i *Bout, + size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + XOR4_2(&Bin1[8 * r - 4], &Bin2[8 * r - 4]) + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1) + SALSA20_8_XOR(Bin2, Bout) + + /* 2: for i = 0 to 2r - 1 do */ + r--; + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8 + 4]) + SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8]) + SALSA20_8_XOR(&Bin2[i * 8], &Bout[i * 4]) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8 + 4]) + SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + return _mm_cvtsi128_si32(X0); +} + +# undef ARX +# undef SALSA20_2ROUNDS +# undef SALSA20_8_XOR +# undef XOR4 +# undef XOR4_2 + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + * Note that B's layout is permuted compared to the generic implementation. + */ +static inline uint32_t +integerify(const void *B, size_t r) +{ + return *(const uint32_t *) ((uintptr_t)(B) + (2 * r - 1) * 64); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t *B, size_t r, uint32_t N, void *V, void *XY) +{ + size_t s = 128 * r; + __m128i * X = (__m128i *) V, *Y; + uint32_t *X32 = (uint32_t *) V; + uint32_t i, j; + size_t k; + + /* 1: X <-- B */ + /* 3: V_i <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X32[k * 16 + i] = LOAD32_LE(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 1; i < N - 1; i += 2) { + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = (__m128i *) ((uintptr_t)(V) + i * s); + blockmix_salsa8(X, Y, r); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = (__m128i *) ((uintptr_t)(V) + (i + 1) * s); + blockmix_salsa8(Y, X, r); + } + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = (__m128i *) ((uintptr_t)(V) + i * s); + blockmix_salsa8(X, Y, r); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = (__m128i *) XY; + blockmix_salsa8(Y, X, r); + + X32 = (uint32_t *) XY; + Y = (__m128i *) ((uintptr_t)(XY) + s); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + __m128i *V_j = (__m128i *) ((uintptr_t)(V) + j * s); + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1); + V_j = (__m128i *) ((uintptr_t)(V) + j * s); + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + STORE32_LE(&B[(k * 16 + (i * 5 % 16)) * 4], X32[k * 16 + i]); + } + } +} + +/** + * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + * N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +escrypt_kdf_sse(escrypt_local_t *local, const uint8_t *passwd, size_t passwdlen, + const uint8_t *salt, size_t saltlen, uint64_t N, uint32_t _r, + uint32_t _p, uint8_t *buf, size_t buflen) +{ + size_t B_size, V_size, XY_size, need; + uint8_t * B; + uint32_t *V, *XY; + size_t r = _r, p = _p; + uint32_t i; + +/* Sanity-check parameters. */ +# if SIZE_MAX > UINT32_MAX +/* LCOV_EXCL_START */ + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +/* LCOV_EXCL_END */ +# endif + if ((uint64_t)(r) * (uint64_t)(p) >= ((uint64_t) 1 << 30)) { + errno = EFBIG; + return -1; + } + if (N > UINT32_MAX) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + return -1; + } + if (r == 0 || p == 0) { + errno = EINVAL; + return -1; + } +/* LCOV_EXCL_START */ + if ((r > SIZE_MAX / 128 / p) || +# if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +# endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } +/* LCOV_EXCL_END */ + + /* Allocate memory. */ + B_size = (size_t) 128 * r * p; + V_size = (size_t) 128 * r * N; + need = B_size + V_size; +/* LCOV_EXCL_START */ + if (need < V_size) { + errno = ENOMEM; + return -1; + } +/* LCOV_EXCL_END */ + XY_size = (size_t) 256 * r + 64; + need += XY_size; +/* LCOV_EXCL_START */ + if (need < XY_size) { + errno = ENOMEM; + return -1; + } +/* LCOV_EXCL_END */ + if (local->size < need) { + if (free_region(local)) { + return -1; /* LCOV_EXCL_LINE */ + } + if (!alloc_region(local, need)) { + return -1; /* LCOV_EXCL_LINE */ + } + } + B = (uint8_t *) local->aligned; + V = (uint32_t *) ((uint8_t *) B + B_size); + XY = (uint32_t *) ((uint8_t *) V + V_size); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[(size_t) 128 * i * r], r, (uint32_t) N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* Success! */ + return 0; +} +#endif |