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#ifndef argon2_core_H
15#define argon2_core_H
16
17#include <string.h>
18
19#include "argon2.h"
20
21/*************************Argon2 internal
22 * constants**************************************************/
23
24enum argon2_ctx_constants {
25    /* Version of the algorithm */
26    ARGON2_VERSION_NUMBER = 0x13,
27
28    /* Memory block size in bytes */
29    ARGON2_BLOCK_SIZE      = 1024,
30    ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
31    ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
32    ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
33    ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
34
35    /* Number of pseudo-random values generated by one call to Blake in Argon2i
36       to
37       generate reference block positions */
38    ARGON2_ADDRESSES_IN_BLOCK = 128,
39
40    /* Pre-hashing digest length and its extension*/
41    ARGON2_PREHASH_DIGEST_LENGTH = 64,
42    ARGON2_PREHASH_SEED_LENGTH   = 72
43};
44
45/*************************Argon2 internal data
46 * types**************************************************/
47
48/*
49 * Structure for the (1KB) memory block implemented as 128 64-bit words.
50 * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no
51 * bounds checking).
52 */
53typedef struct block_ {
54    uint64_t v[ARGON2_QWORDS_IN_BLOCK];
55} block;
56
57typedef struct block_region_ {
58    void * base;
59    block *memory;
60    size_t size;
61} block_region;
62
63/*****************Functions that work with the block******************/
64
65/* Initialize each byte of the block with @in */
66static inline void
67init_block_value(block *b, uint8_t in)
68{
69    memset(b->v, in, sizeof(b->v));
70}
71
72/* Copy block @src to block @dst */
73static inline void
74copy_block(block *dst, const block *src)
75{
76    memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK);
77}
78
79/* XOR @src onto @dst bytewise */
80static inline void
81xor_block(block *dst, const block *src)
82{
83    int i;
84    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
85        dst->v[i] ^= src->v[i];
86    }
87}
88
89/*
90 * Argon2 instance: memory pointer, number of passes, amount of memory, type,
91 * and derived values.
92 * Used to evaluate the number and location of blocks to construct in each
93 * thread
94 */
95typedef struct Argon2_instance_t {
96    block_region *region;        /* Memory region pointer */
97    uint64_t     *pseudo_rands;
98    uint32_t      passes;        /* Number of passes */
99    uint32_t      current_pass;
100    uint32_t      memory_blocks; /* Number of blocks in memory */
101    uint32_t      segment_length;
102    uint32_t      lane_length;
103    uint32_t      lanes;
104    uint32_t      threads;
105    argon2_type   type;
106    int           print_internals; /* whether to print the memory blocks */
107} argon2_instance_t;
108
109/*
110 * Argon2 position: where we construct the block right now. Used to distribute
111 * work between threads.
112 */
113typedef struct Argon2_position_t {
114    uint32_t pass;
115    uint32_t lane;
116    uint8_t  slice;
117    uint32_t index;
118} argon2_position_t;
119
120/*Struct that holds the inputs for thread handling FillSegment*/
121typedef struct Argon2_thread_data {
122    argon2_instance_t *instance_ptr;
123    argon2_position_t  pos;
124} argon2_thread_data;
125
126/*************************Argon2 core
127 * functions**************************************************/
128
129/*
130 * Computes absolute position of reference block in the lane following a skewed
131 * distribution and using a pseudo-random value as input
132 * @param instance Pointer to the current instance
133 * @param position Pointer to the current position
134 * @param pseudo_rand 32-bit pseudo-random value used to determine the position
135 * @param same_lane Indicates if the block will be taken from the current lane.
136 * If so we can reference the current segment
137 * @pre All pointers must be valid
138 */
139static uint32_t index_alpha(const argon2_instance_t *instance,
140                            const argon2_position_t *position, uint32_t pseudo_rand,
141                            int same_lane)
142{
143    /*
144     * Pass 0:
145     *      This lane : all already finished segments plus already constructed
146     * blocks in this segment
147     *      Other lanes : all already finished segments
148     * Pass 1+:
149     *      This lane : (SYNC_POINTS - 1) last segments plus already constructed
150     * blocks in this segment
151     *      Other lanes : (SYNC_POINTS - 1) last segments
152     */
153    uint32_t reference_area_size;
154    uint64_t relative_position;
155    uint32_t start_position, absolute_position;
156
157    if (position->pass == 0) {
158        /* First pass */
159        if (position->slice == 0) {
160            /* First slice */
161            reference_area_size =
162                position->index - 1; /* all but the previous */
163        } else {
164            if (same_lane) {
165                /* The same lane => add current segment */
166                reference_area_size =
167                    position->slice * instance->segment_length +
168                    position->index - 1;
169            } else {
170                reference_area_size =
171                    position->slice * instance->segment_length +
172                    ((position->index == 0) ? (-1) : 0);
173            }
174        }
175    } else {
176        /* Second pass */
177        if (same_lane) {
178            reference_area_size = instance->lane_length -
179                                  instance->segment_length + position->index -
180                                  1;
181        } else {
182            reference_area_size = instance->lane_length -
183                                  instance->segment_length +
184                                  ((position->index == 0) ? (-1) : 0);
185        }
186    }
187
188    /* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce
189     * relative position */
190    relative_position = pseudo_rand;
191    relative_position = relative_position * relative_position >> 32;
192    relative_position = reference_area_size - 1 -
193                        (reference_area_size * relative_position >> 32);
194
195    /* 1.2.5 Computing starting position */
196    start_position = 0;
197
198    if (position->pass != 0) {
199        start_position = (position->slice == ARGON2_SYNC_POINTS - 1)
200                             ? 0
201                             : (position->slice + 1) * instance->segment_length;
202    }
203
204    /* 1.2.6. Computing absolute position */
205    absolute_position = (start_position + relative_position) %
206                        instance->lane_length; /* absolute position */
207    return absolute_position;
208}
209
210/*
211 * Function that validates all inputs against predefined restrictions and return
212 * an error code
213 * @param context Pointer to current Argon2 context
214 * @return ARGON2_OK if everything is all right, otherwise one of error codes
215 * (all defined in <argon2.h>
216 */
217int validate_inputs(const argon2_context *context);
218
219/*
220 * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears
221 * password and secret if needed
222 * @param  context  Pointer to the Argon2 internal structure containing memory
223 * pointer, and parameters for time and space requirements.
224 * @param  blockhash Buffer for pre-hashing digest
225 * @param  type Argon2 type
226 * @pre    @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes
227 * allocated
228 */
229void initial_hash(uint8_t *blockhash, argon2_context *context,
230                  argon2_type type);
231
232/*
233 * Function creates first 2 blocks per lane
234 * @param instance Pointer to the current instance
235 * @param blockhash Pointer to the pre-hashing digest
236 * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values
237 */
238void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance);
239
240/*
241 * Function allocates memory, hashes the inputs with Blake,  and creates first
242 * two blocks. Returns the pointer to the main memory with 2 blocks per lane
243 * initialized
244 * @param  context  Pointer to the Argon2 internal structure containing memory
245 * pointer, and parameters for time and space requirements.
246 * @param  instance Current Argon2 instance
247 * @return Zero if successful, -1 if memory failed to allocate. @context->state
248 * will be modified if successful.
249 */
250int initialize(argon2_instance_t *instance, argon2_context *context);
251
252/*
253 * Deallocates memory. Used on error path.
254 */
255void free_instance(argon2_instance_t *instance, int flags);
256
257/*
258 * XORing the last block of each lane, hashing it, making the tag. Deallocates
259 * the memory.
260 * @param context Pointer to current Argon2 context (use only the out parameters
261 * from it)
262 * @param instance Pointer to current instance of Argon2
263 * @pre instance->state must point to necessary amount of memory
264 * @pre context->out must point to outlen bytes of memory
265 * @pre if context->free_cbk is not NULL, it should point to a function that
266 * deallocates memory
267 */
268void finalize(const argon2_context *context, argon2_instance_t *instance);
269
270/*
271 * Function that fills the segment using previous segments also from other
272 * threads
273 * @param instance Pointer to the current instance
274 * @param position Current position
275 * @pre all block pointers must be valid
276 */
277typedef void (*fill_segment_fn)(const argon2_instance_t *instance,
278                                argon2_position_t        position);
279int argon2_pick_best_implementation(void);
280void fill_segment_avx512f(const argon2_instance_t *instance,
281                          argon2_position_t        position);
282void fill_segment_avx2(const argon2_instance_t *instance,
283                       argon2_position_t        position);
284void fill_segment_ssse3(const argon2_instance_t *instance,
285                        argon2_position_t        position);
286void fill_segment_ref(const argon2_instance_t *instance,
287                      argon2_position_t        position);
288
289/*
290 * Function that fills the entire memory t_cost times based on the first two
291 * blocks in each lane
292 * @param instance Pointer to the current instance
293 * @return Zero if successful, -1 if memory failed to allocate
294 */
295void fill_memory_blocks(argon2_instance_t *instance, uint32_t pass);
296
297#endif
298