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