/src/libsodium/src/libsodium/crypto_pwhash/argon2/argon2-fill-block-ref.c
Line | Count | Source (jump to first uncovered line) |
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 <stdint.h> |
15 | | #include <stdlib.h> |
16 | | #include <string.h> |
17 | | |
18 | | #include "argon2-core.h" |
19 | | #include "argon2.h" |
20 | | #include "blamka-round-ref.h" |
21 | | #include "private/common.h" |
22 | | |
23 | | static void |
24 | | fill_block(const block *prev_block, const block *ref_block, block *next_block) |
25 | 0 | { |
26 | 0 | block blockR, block_tmp; |
27 | 0 | unsigned i; |
28 | |
|
29 | 0 | copy_block(&blockR, ref_block); |
30 | 0 | xor_block(&blockR, prev_block); |
31 | 0 | copy_block(&block_tmp, &blockR); |
32 | | /* Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block |
33 | | Apply Blake2 on columns of 64-bit words: (0,1,...,15), then |
34 | | (16,17,..31)... finally (112,113,...127) */ |
35 | 0 | for (i = 0; i < 8; ++i) { |
36 | 0 | BLAKE2_ROUND_NOMSG( |
37 | 0 | blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], |
38 | 0 | blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], |
39 | 0 | blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], |
40 | 0 | blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], |
41 | 0 | blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], |
42 | 0 | blockR.v[16 * i + 15]); |
43 | 0 | } |
44 | | |
45 | | /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then |
46 | | (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ |
47 | 0 | for (i = 0; i < 8; i++) { |
48 | 0 | BLAKE2_ROUND_NOMSG( |
49 | 0 | blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], |
50 | 0 | blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], |
51 | 0 | blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], |
52 | 0 | blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], |
53 | 0 | blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], |
54 | 0 | blockR.v[2 * i + 113]); |
55 | 0 | } |
56 | |
|
57 | 0 | copy_block(next_block, &block_tmp); |
58 | 0 | xor_block(next_block, &blockR); |
59 | 0 | } |
60 | | |
61 | | static void |
62 | | fill_block_with_xor(const block *prev_block, const block *ref_block, |
63 | | block *next_block) |
64 | 0 | { |
65 | 0 | block blockR, block_tmp; |
66 | 0 | unsigned i; |
67 | |
|
68 | 0 | copy_block(&blockR, ref_block); |
69 | 0 | xor_block(&blockR, prev_block); |
70 | 0 | copy_block(&block_tmp, &blockR); |
71 | 0 | xor_block(&block_tmp, |
72 | 0 | next_block); /* Saving the next block contents for XOR over */ |
73 | | /* Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block |
74 | | * + next_block */ |
75 | | /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then |
76 | | (16,17,..31)... finally (112,113,...127) */ |
77 | 0 | for (i = 0; i < 8; ++i) { |
78 | 0 | BLAKE2_ROUND_NOMSG( |
79 | 0 | blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], |
80 | 0 | blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], |
81 | 0 | blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], |
82 | 0 | blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], |
83 | 0 | blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], |
84 | 0 | blockR.v[16 * i + 15]); |
85 | 0 | } |
86 | | |
87 | | /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then |
88 | | (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ |
89 | 0 | for (i = 0; i < 8; i++) { |
90 | 0 | BLAKE2_ROUND_NOMSG( |
91 | 0 | blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], |
92 | 0 | blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], |
93 | 0 | blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], |
94 | 0 | blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], |
95 | 0 | blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], |
96 | 0 | blockR.v[2 * i + 113]); |
97 | 0 | } |
98 | |
|
99 | 0 | copy_block(next_block, &block_tmp); |
100 | 0 | xor_block(next_block, &blockR); |
101 | 0 | } |
102 | | |
103 | | /* |
104 | | * Generate pseudo-random values to reference blocks in the segment and puts |
105 | | * them into the array |
106 | | * @param instance Pointer to the current instance |
107 | | * @param position Pointer to the current position |
108 | | * @param pseudo_rands Pointer to the array of 64-bit values |
109 | | * @pre pseudo_rands must point to @a instance->segment_length allocated values |
110 | | */ |
111 | | static void |
112 | | generate_addresses(const argon2_instance_t *instance, |
113 | | const argon2_position_t *position, uint64_t *pseudo_rands) |
114 | 0 | { |
115 | 0 | block zero_block, input_block, address_block, tmp_block; |
116 | 0 | uint32_t i; |
117 | |
|
118 | 0 | init_block_value(&zero_block, 0); |
119 | 0 | init_block_value(&input_block, 0); |
120 | |
|
121 | 0 | if (instance != NULL && position != NULL) { |
122 | 0 | input_block.v[0] = position->pass; |
123 | 0 | input_block.v[1] = position->lane; |
124 | 0 | input_block.v[2] = position->slice; |
125 | 0 | input_block.v[3] = instance->memory_blocks; |
126 | 0 | input_block.v[4] = instance->passes; |
127 | 0 | input_block.v[5] = instance->type; |
128 | |
|
129 | 0 | for (i = 0; i < instance->segment_length; ++i) { |
130 | 0 | if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { |
131 | 0 | input_block.v[6]++; |
132 | 0 | init_block_value(&tmp_block, 0); |
133 | 0 | init_block_value(&address_block, 0); |
134 | 0 | fill_block_with_xor(&zero_block, &input_block, &tmp_block); |
135 | 0 | fill_block_with_xor(&zero_block, &tmp_block, &address_block); |
136 | 0 | } |
137 | |
|
138 | 0 | pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; |
139 | 0 | } |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | | void |
144 | | argon2_fill_segment_ref(const argon2_instance_t *instance, |
145 | | argon2_position_t position) |
146 | 0 | { |
147 | 0 | block *ref_block = NULL, *curr_block = NULL; |
148 | | /* Pseudo-random values that determine the reference block position */ |
149 | 0 | uint64_t *pseudo_rands = NULL; |
150 | 0 | uint64_t pseudo_rand, ref_index, ref_lane; |
151 | 0 | uint32_t prev_offset, curr_offset; |
152 | 0 | uint32_t starting_index; |
153 | 0 | uint32_t i; |
154 | 0 | int data_independent_addressing = 1; |
155 | |
|
156 | 0 | if (instance == NULL) { |
157 | 0 | return; |
158 | 0 | } |
159 | | |
160 | 0 | if (instance->type == Argon2_id && |
161 | 0 | (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { |
162 | 0 | data_independent_addressing = 0; |
163 | 0 | } |
164 | |
|
165 | 0 | pseudo_rands = instance->pseudo_rands; |
166 | |
|
167 | 0 | if (data_independent_addressing) { |
168 | 0 | generate_addresses(instance, &position, pseudo_rands); |
169 | 0 | } |
170 | |
|
171 | 0 | starting_index = 0; |
172 | |
|
173 | 0 | if ((0 == position.pass) && (0 == position.slice)) { |
174 | 0 | starting_index = 2; /* we have already generated the first two blocks */ |
175 | 0 | } |
176 | | |
177 | | /* Offset of the current block */ |
178 | 0 | curr_offset = position.lane * instance->lane_length + |
179 | 0 | position.slice * instance->segment_length + starting_index; |
180 | |
|
181 | 0 | if (0 == curr_offset % instance->lane_length) { |
182 | | /* Last block in this lane */ |
183 | 0 | prev_offset = curr_offset + instance->lane_length - 1; |
184 | 0 | } else { |
185 | | /* Previous block */ |
186 | 0 | prev_offset = curr_offset - 1; |
187 | 0 | } |
188 | |
|
189 | 0 | for (i = starting_index; i < instance->segment_length; |
190 | 0 | ++i, ++curr_offset, ++prev_offset) { |
191 | | /*1.1 Rotating prev_offset if needed */ |
192 | 0 | if (curr_offset % instance->lane_length == 1) { |
193 | 0 | prev_offset = curr_offset - 1; |
194 | 0 | } |
195 | | |
196 | | /* 1.2 Computing the index of the reference block */ |
197 | | /* 1.2.1 Taking pseudo-random value from the previous block */ |
198 | 0 | if (data_independent_addressing) { |
199 | 0 | #pragma warning(push) |
200 | 0 | #pragma warning(disable : 6385) |
201 | 0 | pseudo_rand = pseudo_rands[i]; |
202 | 0 | #pragma warning(pop) |
203 | 0 | } else { |
204 | 0 | pseudo_rand = instance->region->memory[prev_offset].v[0]; |
205 | 0 | } |
206 | | |
207 | | /* 1.2.2 Computing the lane of the reference block */ |
208 | 0 | ref_lane = ((pseudo_rand >> 32)) % instance->lanes; |
209 | |
|
210 | 0 | if ((position.pass == 0) && (position.slice == 0)) { |
211 | | /* Can not reference other lanes yet */ |
212 | 0 | ref_lane = position.lane; |
213 | 0 | } |
214 | | |
215 | | /* 1.2.3 Computing the number of possible reference block within the |
216 | | * lane. |
217 | | */ |
218 | 0 | position.index = i; |
219 | 0 | ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, |
220 | 0 | ref_lane == position.lane); |
221 | | |
222 | | /* 2 Creating a new block */ |
223 | 0 | ref_block = instance->region->memory + |
224 | 0 | instance->lane_length * ref_lane + ref_index; |
225 | 0 | curr_block = instance->region->memory + curr_offset; |
226 | 0 | if (position.pass != 0) { |
227 | 0 | fill_block_with_xor(instance->region->memory + prev_offset, |
228 | 0 | ref_block, curr_block); |
229 | 0 | } else { |
230 | 0 | fill_block(instance->region->memory + prev_offset, ref_block, |
231 | 0 | curr_block); |
232 | 0 | } |
233 | 0 | } |
234 | 0 | } |