1/*
2 * Argon2 source code package
3 *
4 * Written by Daniel Dinu and Dmitry Khovratovich, 2015
5 *
6 * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
7 *
8 * You should have received a copy of the CC0 Public Domain Dedication along
9 * with
10 * this software. If not, see
11 * <http://creativecommons.org/publicdomain/zero/1.0/>.
12 */
13
14#include <errno.h>
15#include <stdint.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19
20#include <sys/types.h>
21#ifdef HAVE_SYS_MMAN_H
22# include <sys/mman.h>
23#endif
24
25#include "crypto_generichash_blake2b.h"
26#include "private/common.h"
27#include "private/implementations.h"
28#include "runtime.h"
29#include "utils.h"
30
31#include "argon2-core.h"
32#include "blake2b-long.h"
33
34#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
35# define MAP_ANON MAP_ANONYMOUS
36#endif
37#ifndef MAP_NOCORE
38# define MAP_NOCORE 0
39#endif
40#ifndef MAP_POPULATE
41# define MAP_POPULATE 0
42#endif
43
44static fill_segment_fn fill_segment = fill_segment_ref;
45
46static void
47load_block(block *dst, const void *input)
48{
49    unsigned i;
50    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
51        dst->v[i] = LOAD64_LE((const uint8_t *) input + i * sizeof(dst->v[i]));
52    }
53}
54
55static void
56store_block(void *output, const block *src)
57{
58    unsigned i;
59    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
60        STORE64_LE((uint8_t *) output + i * sizeof(src->v[i]), src->v[i]);
61    }
62}
63
64/***************Memory allocators*****************/
65/* Allocates memory to the given pointer
66 * @param memory pointer to the pointer to the memory
67 * @param m_cost number of blocks to allocate in the memory
68 * @return ARGON2_OK if @memory is a valid pointer and memory is allocated
69 */
70static int allocate_memory(block_region **region, uint32_t m_cost);
71
72static int
73allocate_memory(block_region **region, uint32_t m_cost)
74{
75    void * base;
76    block *memory;
77    size_t memory_size;
78
79    if (region == NULL) {
80        return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */
81    }
82    memory_size = sizeof(block) * m_cost;
83    if (m_cost == 0 ||
84        memory_size / m_cost !=
85            sizeof(block)) { /*1. Check for multiplication overflow*/
86        return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */
87    }
88    *region = (block_region *) malloc(
89        sizeof(block_region)); /*2. Try to allocate region*/
90    if (!*region) {
91        return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */
92    }
93    (*region)->base = (*region)->memory = NULL;
94
95#if defined(MAP_ANON) && defined(HAVE_MMAP)
96    if ((base = mmap(NULL, memory_size, PROT_READ | PROT_WRITE,
97                     MAP_ANON | MAP_PRIVATE | MAP_NOCORE | MAP_POPULATE,
98                     -1, 0)) == MAP_FAILED) {
99        base = NULL; /* LCOV_EXCL_LINE */
100    }                /* LCOV_EXCL_LINE */
101    memcpy(&memory, &base, sizeof memory);
102#elif defined(HAVE_POSIX_MEMALIGN)
103    if ((errno = posix_memalign((void **) &base, 64, memory_size)) != 0) {
104        base = NULL;
105    }
106    memcpy(&memory, &base, sizeof memory);
107#else
108    memory = NULL;
109    if (memory_size + 63 < memory_size) {
110        base  = NULL;
111        errno = ENOMEM;
112    } else if ((base = malloc(memory_size + 63)) != NULL) {
113        uint8_t *aligned = ((uint8_t *) base) + 63;
114        aligned -= (uintptr_t) aligned & 63;
115        memcpy(&memory, &aligned, sizeof memory);
116    }
117#endif
118    if (base == NULL) {
119        return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */
120    }
121    (*region)->base   = base;
122    (*region)->memory = memory;
123    (*region)->size   = memory_size;
124
125    return ARGON2_OK;
126}
127
128/*********Memory functions*/
129
130/* Clears memory
131 * @param instance pointer to the current instance
132 * @param clear_memory indicates if we clear the memory with zeros.
133 */
134static void clear_memory(argon2_instance_t *instance, int clear);
135
136static void
137clear_memory(argon2_instance_t *instance, int clear)
138{
139    /* LCOV_EXCL_START */
140    if (clear) {
141        if (instance->region != NULL) {
142            sodium_memzero(instance->region->memory,
143                           sizeof(block) * instance->memory_blocks);
144        }
145        if (instance->pseudo_rands != NULL) {
146            sodium_memzero(instance->pseudo_rands,
147                           sizeof(uint64_t) * instance->segment_length);
148        }
149    }
150    /* LCOV_EXCL_STOP */
151}
152
153/* Deallocates memory
154 * @param memory pointer to the blocks
155 */
156static void free_memory(block_region *region);
157
158static void
159free_memory(block_region *region)
160{
161    if (region && region->base) {
162#if defined(MAP_ANON) && defined(HAVE_MMAP)
163        if (munmap(region->base, region->size)) {
164            return; /* LCOV_EXCL_LINE */
165        }
166#else
167        free(region->base);
168#endif
169    }
170    free(region);
171}
172
173void
174free_instance(argon2_instance_t *instance, int flags)
175{
176    /* Clear memory */
177    clear_memory(instance, flags & ARGON2_FLAG_CLEAR_MEMORY);
178
179    /* Deallocate the memory */
180    free(instance->pseudo_rands);
181    instance->pseudo_rands = NULL;
182    free_memory(instance->region);
183    instance->region = NULL;
184}
185
186void
187finalize(const argon2_context *context, argon2_instance_t *instance)
188{
189    if (context != NULL && instance != NULL) {
190        block    blockhash;
191        uint32_t l;
192
193        copy_block(&blockhash,
194                   instance->region->memory + instance->lane_length - 1);
195
196        /* XOR the last blocks */
197        for (l = 1; l < instance->lanes; ++l) {
198            uint32_t last_block_in_lane =
199                l * instance->lane_length + (instance->lane_length - 1);
200            xor_block(&blockhash,
201                      instance->region->memory + last_block_in_lane);
202        }
203
204        /* Hash the result */
205        {
206            uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
207            store_block(blockhash_bytes, &blockhash);
208            blake2b_long(context->out, context->outlen, blockhash_bytes,
209                         ARGON2_BLOCK_SIZE);
210            sodium_memzero(blockhash.v,
211                           ARGON2_BLOCK_SIZE); /* clear blockhash */
212            sodium_memzero(blockhash_bytes,
213                           ARGON2_BLOCK_SIZE); /* clear blockhash_bytes */
214        }
215
216        free_instance(instance, context->flags);
217    }
218}
219
220void
221fill_memory_blocks(argon2_instance_t *instance, uint32_t pass)
222{
223    argon2_position_t position;
224    uint32_t l;
225    uint32_t s;
226
227    if (instance == NULL || instance->lanes == 0) {
228        return; /* LCOV_EXCL_LINE */
229    }
230
231    position.pass = pass;
232    for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
233        position.slice = (uint8_t) s;
234        for (l = 0; l < instance->lanes; ++l) {
235            position.lane  = l;
236            position.index = 0;
237            fill_segment(instance, position);
238        }
239    }
240}
241
242int
243validate_inputs(const argon2_context *context)
244{
245    /* LCOV_EXCL_START */
246    if (NULL == context) {
247        return ARGON2_INCORRECT_PARAMETER;
248    }
249
250    if (NULL == context->out) {
251        return ARGON2_OUTPUT_PTR_NULL;
252    }
253
254    /* Validate output length */
255    if (ARGON2_MIN_OUTLEN > context->outlen) {
256        return ARGON2_OUTPUT_TOO_SHORT;
257    }
258
259    if (ARGON2_MAX_OUTLEN < context->outlen) {
260        return ARGON2_OUTPUT_TOO_LONG;
261    }
262
263    /* Validate password (required param) */
264    if (NULL == context->pwd) {
265        if (0 != context->pwdlen) {
266            return ARGON2_PWD_PTR_MISMATCH;
267        }
268    }
269
270    if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) {
271        return ARGON2_PWD_TOO_SHORT;
272    }
273
274    if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
275        return ARGON2_PWD_TOO_LONG;
276    }
277
278    /* Validate salt (required param) */
279    if (NULL == context->salt) {
280        if (0 != context->saltlen) {
281            return ARGON2_SALT_PTR_MISMATCH;
282        }
283    }
284
285    if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {
286        return ARGON2_SALT_TOO_SHORT;
287    }
288
289    if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {
290        return ARGON2_SALT_TOO_LONG;
291    }
292
293    /* Validate secret (optional param) */
294    if (NULL == context->secret) {
295        if (0 != context->secretlen) {
296            return ARGON2_SECRET_PTR_MISMATCH;
297        }
298    } else {
299        if (ARGON2_MIN_SECRET > context->secretlen) {
300            return ARGON2_SECRET_TOO_SHORT;
301        }
302
303        if (ARGON2_MAX_SECRET < context->secretlen) {
304            return ARGON2_SECRET_TOO_LONG;
305        }
306    }
307
308    /* Validate associated data (optional param) */
309    if (NULL == context->ad) {
310        if (0 != context->adlen) {
311            return ARGON2_AD_PTR_MISMATCH;
312        }
313    } else {
314        if (ARGON2_MIN_AD_LENGTH > context->adlen) {
315            return ARGON2_AD_TOO_SHORT;
316        }
317
318        if (ARGON2_MAX_AD_LENGTH < context->adlen) {
319            return ARGON2_AD_TOO_LONG;
320        }
321    }
322
323    /* Validate memory cost */
324    if (ARGON2_MIN_MEMORY > context->m_cost) {
325        return ARGON2_MEMORY_TOO_LITTLE;
326    }
327
328    if (ARGON2_MAX_MEMORY < context->m_cost) {
329        return ARGON2_MEMORY_TOO_MUCH;
330    }
331
332    if (context->m_cost < 8 * context->lanes) {
333        return ARGON2_MEMORY_TOO_LITTLE;
334    }
335
336    /* Validate time cost */
337    if (ARGON2_MIN_TIME > context->t_cost) {
338        return ARGON2_TIME_TOO_SMALL;
339    }
340
341    if (ARGON2_MAX_TIME < context->t_cost) {
342        return ARGON2_TIME_TOO_LARGE;
343    }
344
345    /* Validate lanes */
346    if (ARGON2_MIN_LANES > context->lanes) {
347        return ARGON2_LANES_TOO_FEW;
348    }
349
350    if (ARGON2_MAX_LANES < context->lanes) {
351        return ARGON2_LANES_TOO_MANY;
352    }
353
354    /* Validate threads */
355    if (ARGON2_MIN_THREADS > context->threads) {
356        return ARGON2_THREADS_TOO_FEW;
357    }
358
359    if (ARGON2_MAX_THREADS < context->threads) {
360        return ARGON2_THREADS_TOO_MANY;
361    }
362    /* LCOV_EXCL_STOP */
363
364    return ARGON2_OK;
365}
366
367void
368fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance)
369{
370    uint32_t l;
371    /* Make the first and second block in each lane as G(H0||i||0) or
372       G(H0||i||1) */
373    uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
374    for (l = 0; l < instance->lanes; ++l) {
375        STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);
376        STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);
377        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
378                     ARGON2_PREHASH_SEED_LENGTH);
379        load_block(&instance->region->memory[l * instance->lane_length + 0],
380                   blockhash_bytes);
381
382        STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);
383        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
384                     ARGON2_PREHASH_SEED_LENGTH);
385        load_block(&instance->region->memory[l * instance->lane_length + 1],
386                   blockhash_bytes);
387    }
388    sodium_memzero(blockhash_bytes, ARGON2_BLOCK_SIZE);
389}
390
391void
392initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type type)
393{
394    crypto_generichash_blake2b_state BlakeHash;
395    uint8_t                          value[4U /* sizeof(uint32_t) */];
396
397    if (NULL == context || NULL == blockhash) {
398        return; /* LCOV_EXCL_LINE */
399    }
400
401    crypto_generichash_blake2b_init(&BlakeHash, NULL, 0U,
402                                    ARGON2_PREHASH_DIGEST_LENGTH);
403
404    STORE32_LE(value, context->lanes);
405    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
406
407    STORE32_LE(value, context->outlen);
408    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
409
410    STORE32_LE(value, context->m_cost);
411    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
412
413    STORE32_LE(value, context->t_cost);
414    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
415
416    STORE32_LE(value, ARGON2_VERSION_NUMBER);
417    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
418
419    STORE32_LE(value, (uint32_t) type);
420    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
421
422    STORE32_LE(value, context->pwdlen);
423    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
424
425    if (context->pwd != NULL) {
426        crypto_generichash_blake2b_update(
427            &BlakeHash, (const uint8_t *) context->pwd, context->pwdlen);
428
429        /* LCOV_EXCL_START */
430        if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) {
431            sodium_memzero(context->pwd, context->pwdlen);
432            context->pwdlen = 0;
433        }
434        /* LCOV_EXCL_STOP */
435    }
436
437    STORE32_LE(value, context->saltlen);
438    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
439
440    if (context->salt != NULL) {
441        crypto_generichash_blake2b_update(
442            &BlakeHash, (const uint8_t *) context->salt, context->saltlen);
443    }
444
445    STORE32_LE(value, context->secretlen);
446    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
447
448    /* LCOV_EXCL_START */
449    if (context->secret != NULL) {
450        crypto_generichash_blake2b_update(
451            &BlakeHash, (const uint8_t *) context->secret, context->secretlen);
452
453        if (context->flags & ARGON2_FLAG_CLEAR_SECRET) {
454            sodium_memzero(context->secret, context->secretlen);
455            context->secretlen = 0;
456        }
457    }
458    /* LCOV_EXCL_STOP */
459
460    STORE32_LE(value, context->adlen);
461    crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value));
462
463    /* LCOV_EXCL_START */
464    if (context->ad != NULL) {
465        crypto_generichash_blake2b_update(
466            &BlakeHash, (const uint8_t *) context->ad, context->adlen);
467    }
468    /* LCOV_EXCL_STOP */
469
470    crypto_generichash_blake2b_final(&BlakeHash, blockhash,
471                                     ARGON2_PREHASH_DIGEST_LENGTH);
472}
473
474int
475initialize(argon2_instance_t *instance, argon2_context *context)
476{
477    uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];
478    int     result = ARGON2_OK;
479
480    if (instance == NULL || context == NULL) {
481        return ARGON2_INCORRECT_PARAMETER;
482    }
483
484    /* 1. Memory allocation */
485
486    if ((instance->pseudo_rands = (uint64_t *)
487         malloc(sizeof(uint64_t) * instance->segment_length)) == NULL) {
488        return ARGON2_MEMORY_ALLOCATION_ERROR;
489    }
490
491    result = allocate_memory(&(instance->region), instance->memory_blocks);
492    if (ARGON2_OK != result) {
493        free_instance(instance, context->flags);
494        return result;
495    }
496
497    /* 2. Initial hashing */
498    /* H_0 + 8 extra bytes to produce the first blocks */
499    /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */
500    /* Hashing all inputs */
501    initial_hash(blockhash, context, instance->type);
502    /* Zeroing 8 extra bytes */
503    sodium_memzero(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,
504                   ARGON2_PREHASH_SEED_LENGTH - ARGON2_PREHASH_DIGEST_LENGTH);
505
506    /* 3. Creating first blocks, we always have at least two blocks in a slice
507     */
508    fill_first_blocks(blockhash, instance);
509    /* Clearing the hash */
510    sodium_memzero(blockhash, ARGON2_PREHASH_SEED_LENGTH);
511
512    return ARGON2_OK;
513}
514
515int
516argon2_pick_best_implementation(void)
517{
518/* LCOV_EXCL_START */
519#if defined(HAVE_AVX512FINTRIN_H) && defined(HAVE_AVX2INTRIN_H) && \
520    defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H)
521    if (sodium_runtime_has_avx512f()) {
522        fill_segment = fill_segment_avx512f;
523        return 0;
524    }
525#endif
526#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_TMMINTRIN_H) && \
527    defined(HAVE_SMMINTRIN_H)
528    if (sodium_runtime_has_avx2()) {
529        fill_segment = fill_segment_avx2;
530        return 0;
531    }
532#endif
533#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H)
534    if (sodium_runtime_has_ssse3()) {
535        fill_segment = fill_segment_ssse3;
536        return 0;
537    }
538#endif
539    fill_segment = fill_segment_ref;
540
541    return 0;
542    /* LCOV_EXCL_STOP */
543}
544
545int
546_crypto_pwhash_argon2_pick_best_implementation(void)
547{
548    return argon2_pick_best_implementation();
549}
550