xref: /freebsd/sys/contrib/libsodium/src/libsodium/crypto_pwhash/argon2/argon2-core.h (revision 3611ec604864a7d4dcc9a3ea898c80eb35eef8a0)
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 
24 enum 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  */
53 typedef struct block_ {
54     uint64_t v[ARGON2_QWORDS_IN_BLOCK];
55 } block;
56 
57 typedef 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 */
66 static inline void
init_block_value(block * b,uint8_t in)67 init_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 */
73 static inline void
copy_block(block * dst,const block * src)74 copy_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 */
80 static inline void
xor_block(block * dst,const block * src)81 xor_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  */
95 typedef 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  */
113 typedef 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*/
121 typedef 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  */
index_alpha(const argon2_instance_t * instance,const argon2_position_t * position,uint32_t pseudo_rand,int same_lane)139 static 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  */
217 int 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  */
229 void 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  */
238 void 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  */
250 int initialize(argon2_instance_t *instance, argon2_context *context);
251 
252 /*
253  * Deallocates memory. Used on error path.
254  */
255 void 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  */
268 void 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  */
277 typedef void (*fill_segment_fn)(const argon2_instance_t *instance,
278                                 argon2_position_t        position);
279 int argon2_pick_best_implementation(void);
280 void fill_segment_avx512f(const argon2_instance_t *instance,
281                           argon2_position_t        position);
282 void fill_segment_avx2(const argon2_instance_t *instance,
283                        argon2_position_t        position);
284 void fill_segment_ssse3(const argon2_instance_t *instance,
285                         argon2_position_t        position);
286 void 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  */
295 void fill_memory_blocks(argon2_instance_t *instance, uint32_t pass);
296 
297 #endif
298