]>
Commit | Line | Data |
---|---|---|
c48c4d78 | 1 | //----------------------------------------------------------------------------- |
2 | // Copyright (C) 2016, 2017 by piwi | |
3 | // | |
4 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, | |
5 | // at your option, any later version. See the LICENSE.txt file for the text of | |
6 | // the license. | |
7 | //----------------------------------------------------------------------------- | |
8 | // Implements a card only attack based on crypto text (encrypted nonces | |
9 | // received during a nested authentication) only. Unlike other card only | |
10 | // attacks this doesn't rely on implementation errors but only on the | |
11 | // inherent weaknesses of the crypto1 cypher. Described in | |
12 | // Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened | |
13 | // Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on | |
14 | // Computer and Communications Security, 2015 | |
15 | //----------------------------------------------------------------------------- | |
16 | // | |
17 | // brute forcing is based on @aczids bitsliced brute forcer | |
18 | // https://github.com/aczid/crypto1_bs with some modifications. Mainly: | |
19 | // - don't rollback. Start with 2nd byte of nonce instead | |
20 | // - reuse results of filter subfunctions | |
21 | // - reuse results of previous nonces if some first bits are identical | |
22 | // | |
23 | //----------------------------------------------------------------------------- | |
24 | // aczid's Copyright notice: | |
25 | // | |
26 | // Bit-sliced Crypto-1 brute-forcing implementation | |
27 | // Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid) | |
28 | /* | |
29 | Copyright (c) 2015-2016 Aram Verstegen | |
30 | ||
31 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
32 | of this software and associated documentation files (the "Software"), to deal | |
33 | in the Software without restriction, including without limitation the rights | |
34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
35 | copies of the Software, and to permit persons to whom the Software is | |
36 | furnished to do so, subject to the following conditions: | |
37 | ||
38 | The above copyright notice and this permission notice shall be included in | |
39 | all copies or substantial portions of the Software. | |
40 | ||
41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
47 | THE SOFTWARE. | |
48 | */ | |
49 | ||
50 | #include "hardnested_bruteforce.h" | |
51 | ||
52 | #include <inttypes.h> | |
53 | #include <stdbool.h> | |
54 | #include <stdio.h> | |
55 | #include <pthread.h> | |
56 | #include <string.h> | |
c3d117a8 | 57 | #include <stdlib.h> |
c48c4d78 | 58 | #include "proxmark3.h" |
59 | #include "cmdhfmfhard.h" | |
60 | #include "hardnested_bf_core.h" | |
61 | #include "ui.h" | |
62 | #include "util.h" | |
ec9c7112 | 63 | #include "util_posix.h" |
c48c4d78 | 64 | #include "crapto1/crapto1.h" |
65 | #include "parity.h" | |
66 | ||
67 | #define NUM_BRUTE_FORCE_THREADS (num_CPUs()) | |
68 | #define DEFAULT_BRUTE_FORCE_RATE (120000000.0) // if benchmark doesn't succeed | |
69 | #define TEST_BENCH_SIZE (6000) // number of odd and even states for brute force benchmark | |
70 | #define TEST_BENCH_FILENAME "hardnested/bf_bench_data.bin" | |
71 | //#define WRITE_BENCH_FILE | |
72 | ||
73 | // debugging options | |
74 | #define DEBUG_KEY_ELIMINATION | |
75 | // #define DEBUG_BRUTE_FORCE | |
76 | ||
77 | typedef enum { | |
78 | EVEN_STATE = 0, | |
79 | ODD_STATE = 1 | |
80 | } odd_even_t; | |
81 | ||
82 | static uint32_t nonces_to_bruteforce = 0; | |
83 | static uint32_t bf_test_nonce[256]; | |
84 | static uint8_t bf_test_nonce_2nd_byte[256]; | |
85 | static uint8_t bf_test_nonce_par[256]; | |
86 | static uint32_t bucket_count = 0; | |
87 | static statelist_t* buckets[128]; | |
88 | static uint32_t keys_found = 0; | |
89 | static uint64_t num_keys_tested; | |
90 | ||
91 | ||
92 | uint8_t trailing_zeros(uint8_t byte) | |
93 | { | |
94 | static const uint8_t trailing_zeros_LUT[256] = { | |
95 | 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
96 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
97 | 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
98 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
99 | 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
100 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
101 | 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
102 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
103 | 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
104 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
105 | 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
106 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
107 | 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
108 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
109 | 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, | |
110 | 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 | |
111 | }; | |
112 | ||
113 | return trailing_zeros_LUT[byte]; | |
114 | } | |
115 | ||
116 | ||
117 | bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even) | |
118 | { | |
119 | struct Crypto1State pcs; | |
120 | for (uint16_t test_first_byte = 1; test_first_byte < 256; test_first_byte++) { | |
121 | noncelistentry_t *test_nonce = nonces[best_first_bytes[test_first_byte]].first; | |
122 | while (test_nonce != NULL) { | |
123 | pcs.odd = odd; | |
124 | pcs.even = even; | |
125 | lfsr_rollback_byte(&pcs, (cuid >> 24) ^ best_first_bytes[0], true); | |
126 | for (int8_t byte_pos = 3; byte_pos >= 0; byte_pos--) { | |
127 | uint8_t test_par_enc_bit = (test_nonce->par_enc >> byte_pos) & 0x01; // the encoded parity bit | |
128 | uint8_t test_byte_enc = (test_nonce->nonce_enc >> (8*byte_pos)) & 0xff; // the encoded nonce byte | |
129 | uint8_t test_byte_dec = crypto1_byte(&pcs, test_byte_enc /* ^ (cuid >> (8*byte_pos)) */, true) ^ test_byte_enc; // decode the nonce byte | |
130 | uint8_t ks_par = filter(pcs.odd); // the keystream bit to encode/decode the parity bit | |
131 | uint8_t test_par_enc2 = ks_par ^ evenparity8(test_byte_dec); // determine the decoded byte's parity and encode it | |
132 | if (test_par_enc_bit != test_par_enc2) { | |
133 | return false; | |
134 | } | |
135 | } | |
136 | test_nonce = test_nonce->next; | |
137 | } | |
138 | } | |
139 | return true; | |
140 | } | |
141 | ||
ec087218 | 142 | static void* |
143 | #ifdef __has_attribute | |
144 | #if __has_attribute(force_align_arg_pointer) | |
145 | __attribute__((force_align_arg_pointer)) | |
146 | #endif | |
147 | #endif | |
148 | crack_states_thread(void* x){ | |
c48c4d78 | 149 | |
150 | struct arg { | |
151 | bool silent; | |
152 | int thread_ID; | |
153 | uint32_t cuid; | |
154 | uint32_t num_acquired_nonces; | |
155 | uint64_t maximum_states; | |
156 | noncelist_t *nonces; | |
157 | uint8_t* best_first_bytes; | |
158 | } *thread_arg; | |
159 | ||
160 | thread_arg = (struct arg *)x; | |
161 | const int thread_id = thread_arg->thread_ID; | |
162 | uint32_t current_bucket = thread_id; | |
163 | while(current_bucket < bucket_count){ | |
164 | statelist_t *bucket = buckets[current_bucket]; | |
165 | if(bucket){ | |
166 | #if defined (DEBUG_BRUTE_FORCE) | |
167 | printf("Thread %u starts working on bucket %u\n", thread_id, current_bucket); | |
168 | #endif | |
169 | const uint64_t key = crack_states_bitsliced(thread_arg->cuid, thread_arg->best_first_bytes, bucket, &keys_found, &num_keys_tested, nonces_to_bruteforce, bf_test_nonce_2nd_byte, thread_arg->nonces); | |
170 | if(key != -1){ | |
171 | __sync_fetch_and_add(&keys_found, 1); | |
172 | char progress_text[80]; | |
173 | sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key); | |
174 | hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0); | |
175 | break; | |
176 | } else if(keys_found){ | |
177 | break; | |
178 | } else { | |
179 | if (!thread_arg->silent) { | |
180 | char progress_text[80]; | |
181 | sprintf(progress_text, "Brute force phase: %6.02f%%", 100.0*(float)num_keys_tested/(float)(thread_arg->maximum_states)); | |
182 | float remaining_bruteforce = thread_arg->nonces[thread_arg->best_first_bytes[0]].expected_num_brute_force - (float)num_keys_tested/2; | |
183 | hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, remaining_bruteforce, 5000); | |
184 | } | |
185 | } | |
186 | } | |
187 | current_bucket += NUM_BRUTE_FORCE_THREADS; | |
188 | } | |
189 | return NULL; | |
190 | } | |
191 | ||
192 | ||
193 | void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte) | |
194 | { | |
195 | // we do bitsliced brute forcing with best_first_bytes[0] only. | |
196 | // Extract the corresponding 2nd bytes | |
197 | noncelistentry_t *test_nonce = nonces[best_first_byte].first; | |
198 | uint32_t i = 0; | |
199 | while (test_nonce != NULL) { | |
200 | bf_test_nonce[i] = test_nonce->nonce_enc; | |
201 | bf_test_nonce_par[i] = test_nonce->par_enc; | |
202 | bf_test_nonce_2nd_byte[i] = (test_nonce->nonce_enc >> 16) & 0xff; | |
203 | test_nonce = test_nonce->next; | |
204 | i++; | |
205 | } | |
206 | nonces_to_bruteforce = i; | |
207 | ||
208 | // printf("Nonces to bruteforce: %d\n", nonces_to_bruteforce); | |
209 | // printf("Common bits of first 4 2nd nonce bytes (before sorting): %u %u %u\n", | |
210 | // trailing_zeros(bf_test_nonce_2nd_byte[1] ^ bf_test_nonce_2nd_byte[0]), | |
211 | // trailing_zeros(bf_test_nonce_2nd_byte[2] ^ bf_test_nonce_2nd_byte[1]), | |
212 | // trailing_zeros(bf_test_nonce_2nd_byte[3] ^ bf_test_nonce_2nd_byte[2])); | |
213 | ||
214 | uint8_t best_4[4] = {0}; | |
215 | int sum_best = -1; | |
216 | for (uint16_t n1 = 0; n1 < nonces_to_bruteforce; n1++) { | |
217 | for (uint16_t n2 = 0; n2 < nonces_to_bruteforce; n2++) { | |
218 | if (n2 != n1) { | |
219 | for (uint16_t n3 = 0; n3 < nonces_to_bruteforce; n3++) { | |
220 | if ((n3 != n2 && n3 != n1) || nonces_to_bruteforce < 3 | |
221 | // && trailing_zeros(bf_test_nonce_2nd_byte[n1] ^ bf_test_nonce_2nd_byte[n2]) | |
222 | // > trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3]) | |
223 | ) { | |
224 | for (uint16_t n4 = 0; n4 < nonces_to_bruteforce; n4++) { | |
225 | if ((n4 != n3 && n4 != n2 && n4 != n1) || nonces_to_bruteforce < 4 | |
226 | // && trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3]) | |
227 | // > trailing_zeros(bf_test_nonce_2nd_byte[n3] ^ bf_test_nonce_2nd_byte[n4]) | |
228 | ) { | |
229 | int sum = nonces_to_bruteforce > 1 ? trailing_zeros(bf_test_nonce_2nd_byte[n1] ^ bf_test_nonce_2nd_byte[n2]) : 0.0 | |
230 | + nonces_to_bruteforce > 2 ? trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3]) : 0.0 | |
231 | + nonces_to_bruteforce > 3 ? trailing_zeros(bf_test_nonce_2nd_byte[n3] ^ bf_test_nonce_2nd_byte[n4]) : 0.0; | |
232 | if (sum > sum_best) { | |
233 | sum_best = sum; | |
234 | best_4[0] = n1; | |
235 | best_4[1] = n2; | |
236 | best_4[2] = n3; | |
237 | best_4[3] = n4; | |
238 | } | |
239 | } | |
240 | } | |
241 | } | |
242 | } | |
243 | } | |
244 | } | |
245 | } | |
246 | ||
247 | uint32_t bf_test_nonce_temp[4]; | |
248 | uint8_t bf_test_nonce_par_temp[4]; | |
249 | uint8_t bf_test_nonce_2nd_byte_temp[4]; | |
250 | for (uint8_t i = 0; i < 4 && i < nonces_to_bruteforce; i++) { | |
251 | bf_test_nonce_temp[i] = bf_test_nonce[best_4[i]]; | |
252 | ||
253 | bf_test_nonce_par_temp[i] = bf_test_nonce_par[best_4[i]]; | |
254 | bf_test_nonce_2nd_byte_temp[i] = bf_test_nonce_2nd_byte[best_4[i]]; | |
255 | } | |
256 | for (uint8_t i = 0; i < 4 && i < nonces_to_bruteforce; i++) { | |
257 | bf_test_nonce[i] = bf_test_nonce_temp[i]; | |
258 | bf_test_nonce_par[i] = bf_test_nonce_par_temp[i]; | |
259 | bf_test_nonce_2nd_byte[i] = bf_test_nonce_2nd_byte_temp[i]; | |
260 | } | |
261 | } | |
262 | ||
263 | ||
264 | #if defined (WRITE_BENCH_FILE) | |
265 | static void write_benchfile(statelist_t *candidates) { | |
266 | ||
267 | printf("Writing brute force benchmark data..."); | |
268 | FILE *benchfile = fopen(TEST_BENCH_FILENAME, "wb"); | |
269 | fwrite(&nonces_to_bruteforce, 1, sizeof(nonces_to_bruteforce), benchfile); | |
270 | for (uint32_t i = 0; i < nonces_to_bruteforce; i++) { | |
271 | fwrite(&(bf_test_nonce[i]), 1, sizeof(bf_test_nonce[i]), benchfile); | |
272 | fwrite(&(bf_test_nonce_par[i]), 1, sizeof(bf_test_nonce_par[i]), benchfile); | |
273 | } | |
274 | uint32_t num_states = MIN(candidates->len[EVEN_STATE], TEST_BENCH_SIZE); | |
275 | fwrite(&num_states, 1, sizeof(num_states), benchfile); | |
276 | for (uint32_t i = 0; i < num_states; i++) { | |
277 | fwrite(&(candidates->states[EVEN_STATE][i]), 1, sizeof(uint32_t), benchfile); | |
278 | } | |
279 | num_states = MIN(candidates->len[ODD_STATE], TEST_BENCH_SIZE); | |
280 | fwrite(&num_states, 1, sizeof(num_states), benchfile); | |
281 | for (uint32_t i = 0; i < num_states; i++) { | |
282 | fwrite(&(candidates->states[ODD_STATE][i]), 1, sizeof(uint32_t), benchfile); | |
283 | } | |
284 | fclose(benchfile); | |
285 | printf("done.\n"); | |
286 | } | |
287 | #endif | |
288 | ||
289 | ||
290 | bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes) | |
291 | { | |
292 | #if defined (WRITE_BENCH_FILE) | |
293 | write_benchfile(candidates); | |
294 | #endif | |
295 | bool silent = (bf_rate != NULL); | |
296 | ||
297 | // if (!silent) { | |
298 | // PrintAndLog("Brute force phase starting."); | |
299 | // PrintAndLog("Using %u-bit bitslices", MAX_BITSLICES); | |
300 | // } | |
301 | ||
302 | keys_found = 0; | |
303 | num_keys_tested = 0; | |
304 | ||
305 | bitslice_test_nonces(nonces_to_bruteforce, bf_test_nonce, bf_test_nonce_par); | |
306 | ||
307 | // count number of states to go | |
308 | bucket_count = 0; | |
309 | for (statelist_t *p = candidates; p != NULL; p = p->next) { | |
310 | if (p->states[ODD_STATE] != NULL && p->states[EVEN_STATE] != NULL) { | |
311 | buckets[bucket_count] = p; | |
312 | bucket_count++; | |
313 | } | |
314 | } | |
315 | ||
316 | uint64_t start_time = msclock(); | |
317 | // enumerate states using all hardware threads, each thread handles one bucket | |
318 | // if (!silent) { | |
319 | // PrintAndLog("Starting %u cracking threads to search %u buckets containing a total of %" PRIu64" states...\n", NUM_BRUTE_FORCE_THREADS, bucket_count, maximum_states); | |
320 | // printf("Common bits of first 4 2nd nonce bytes: %u %u %u\n", | |
321 | // trailing_zeros(bf_test_nonce_2nd_byte[1] ^ bf_test_nonce_2nd_byte[0]), | |
322 | // trailing_zeros(bf_test_nonce_2nd_byte[2] ^ bf_test_nonce_2nd_byte[1]), | |
323 | // trailing_zeros(bf_test_nonce_2nd_byte[3] ^ bf_test_nonce_2nd_byte[2])); | |
324 | // } | |
325 | ||
326 | pthread_t threads[NUM_BRUTE_FORCE_THREADS]; | |
327 | struct args { | |
328 | bool silent; | |
329 | int thread_ID; | |
330 | uint32_t cuid; | |
331 | uint32_t num_acquired_nonces; | |
332 | uint64_t maximum_states; | |
333 | noncelist_t *nonces; | |
334 | uint8_t *best_first_bytes; | |
335 | } thread_args[NUM_BRUTE_FORCE_THREADS]; | |
336 | ||
337 | for(uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++){ | |
338 | thread_args[i].thread_ID = i; | |
339 | thread_args[i].silent = silent; | |
340 | thread_args[i].cuid = cuid; | |
341 | thread_args[i].num_acquired_nonces = num_acquired_nonces; | |
342 | thread_args[i].maximum_states = maximum_states; | |
343 | thread_args[i].nonces = nonces; | |
344 | thread_args[i].best_first_bytes = best_first_bytes; | |
345 | pthread_create(&threads[i], NULL, crack_states_thread, (void*)&thread_args[i]); | |
346 | } | |
347 | for(uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++){ | |
348 | pthread_join(threads[i], 0); | |
349 | } | |
350 | ||
351 | uint64_t elapsed_time = msclock() - start_time; | |
352 | ||
353 | // if (!silent) { | |
354 | // printf("Brute force completed after testing %" PRIu64" (2^%1.1f) keys in %1.1f seconds at a rate of %1.0f (2^%1.1f) keys per second.\n", | |
355 | // num_keys_tested, | |
356 | // log(num_keys_tested) / log(2.0), | |
357 | // (float)elapsed_time/1000.0, | |
358 | // (float)num_keys_tested / ((float)elapsed_time / 1000.0), | |
359 | // log((float)num_keys_tested / ((float)elapsed_time/1000.0)) / log(2.0)); | |
360 | // } | |
361 | ||
362 | if (bf_rate != NULL) { | |
363 | *bf_rate = (float)num_keys_tested / ((float)elapsed_time / 1000.0); | |
364 | } | |
365 | ||
366 | return (keys_found != 0); | |
367 | } | |
368 | ||
369 | ||
370 | static bool read_bench_data(statelist_t *test_candidates) { | |
371 | ||
372 | size_t bytes_read = 0; | |
373 | uint32_t temp = 0; | |
374 | uint32_t num_states = 0; | |
375 | uint32_t states_read = 0; | |
376 | ||
377 | char bench_file_path[strlen(get_my_executable_directory()) + strlen(TEST_BENCH_FILENAME) + 1]; | |
378 | strcpy(bench_file_path, get_my_executable_directory()); | |
379 | strcat(bench_file_path, TEST_BENCH_FILENAME); | |
380 | ||
381 | FILE *benchfile = fopen(bench_file_path, "rb"); | |
382 | if (benchfile == NULL) { | |
383 | return false; | |
384 | } | |
385 | bytes_read = fread(&nonces_to_bruteforce, 1, sizeof(nonces_to_bruteforce), benchfile); | |
386 | if (bytes_read != sizeof(nonces_to_bruteforce)) { | |
387 | fclose(benchfile); | |
388 | return false; | |
389 | } | |
390 | for (uint16_t i = 0; i < nonces_to_bruteforce && i < 256; i++) { | |
391 | bytes_read = fread(&bf_test_nonce[i], 1, sizeof(uint32_t), benchfile); | |
392 | if (bytes_read != sizeof(uint32_t)) { | |
393 | fclose(benchfile); | |
394 | return false; | |
395 | } | |
396 | bf_test_nonce_2nd_byte[i] = (bf_test_nonce[i] >> 16) & 0xff; | |
397 | bytes_read = fread(&bf_test_nonce_par[i], 1, sizeof(uint8_t), benchfile); | |
398 | if (bytes_read != sizeof(uint8_t)) { | |
399 | fclose(benchfile); | |
400 | return false; | |
401 | } | |
402 | } | |
403 | bytes_read = fread(&num_states, 1, sizeof(uint32_t), benchfile); | |
404 | if (bytes_read != sizeof(uint32_t)) { | |
405 | fclose(benchfile); | |
406 | return false; | |
407 | } | |
408 | for (states_read = 0; states_read < MIN(num_states, TEST_BENCH_SIZE); states_read++) { | |
409 | bytes_read = fread(test_candidates->states[EVEN_STATE] + states_read, 1, sizeof(uint32_t), benchfile); | |
410 | if (bytes_read != sizeof(uint32_t)) { | |
411 | fclose(benchfile); | |
412 | return false; | |
413 | } | |
414 | } | |
415 | for (uint32_t i = states_read; i < TEST_BENCH_SIZE; i++) { | |
416 | test_candidates->states[EVEN_STATE][i] = test_candidates->states[EVEN_STATE][i-states_read]; | |
417 | } | |
418 | for (uint32_t i = states_read; i < num_states; i++) { | |
419 | bytes_read = fread(&temp, 1, sizeof(uint32_t), benchfile); | |
420 | if (bytes_read != sizeof(uint32_t)) { | |
421 | fclose(benchfile); | |
422 | return false; | |
423 | } | |
424 | } | |
425 | for (states_read = 0; states_read < MIN(num_states, TEST_BENCH_SIZE); states_read++) { | |
426 | bytes_read = fread(test_candidates->states[ODD_STATE] + states_read, 1, sizeof(uint32_t), benchfile); | |
427 | if (bytes_read != sizeof(uint32_t)) { | |
428 | fclose(benchfile); | |
429 | return false; | |
430 | } | |
431 | } | |
432 | for (uint32_t i = states_read; i < TEST_BENCH_SIZE; i++) { | |
433 | test_candidates->states[ODD_STATE][i] = test_candidates->states[ODD_STATE][i-states_read]; | |
434 | } | |
435 | ||
436 | fclose(benchfile); | |
437 | return true; | |
438 | } | |
439 | ||
440 | ||
441 | float brute_force_benchmark() | |
442 | { | |
443 | statelist_t test_candidates[NUM_BRUTE_FORCE_THREADS]; | |
444 | ||
445 | test_candidates[0].states[ODD_STATE] = malloc((TEST_BENCH_SIZE+1) * sizeof(uint32_t)); | |
446 | test_candidates[0].states[EVEN_STATE] = malloc((TEST_BENCH_SIZE+1) * sizeof(uint32_t)); | |
447 | for (uint8_t i = 0; i < NUM_BRUTE_FORCE_THREADS - 1; i++){ | |
448 | test_candidates[i].next = test_candidates + i + 1; | |
449 | test_candidates[i+1].states[ODD_STATE] = test_candidates[0].states[ODD_STATE]; | |
450 | test_candidates[i+1].states[EVEN_STATE] = test_candidates[0].states[EVEN_STATE]; | |
451 | } | |
452 | test_candidates[NUM_BRUTE_FORCE_THREADS-1].next = NULL; | |
453 | ||
454 | if (!read_bench_data(test_candidates)) { | |
455 | PrintAndLog("Couldn't read benchmark data. Assuming brute force rate of %1.0f states per second", DEFAULT_BRUTE_FORCE_RATE); | |
456 | return DEFAULT_BRUTE_FORCE_RATE; | |
457 | } | |
458 | ||
459 | for (uint8_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) { | |
460 | test_candidates[i].len[ODD_STATE] = TEST_BENCH_SIZE; | |
461 | test_candidates[i].len[EVEN_STATE] = TEST_BENCH_SIZE; | |
462 | test_candidates[i].states[ODD_STATE][TEST_BENCH_SIZE] = -1; | |
463 | test_candidates[i].states[EVEN_STATE][TEST_BENCH_SIZE] = -1; | |
464 | } | |
465 | ||
466 | uint64_t maximum_states = TEST_BENCH_SIZE*TEST_BENCH_SIZE*(uint64_t)NUM_BRUTE_FORCE_THREADS; | |
467 | ||
468 | float bf_rate; | |
469 | brute_force_bs(&bf_rate, test_candidates, 0, 0, maximum_states, NULL, 0); | |
470 | ||
471 | free(test_candidates[0].states[ODD_STATE]); | |
472 | free(test_candidates[0].states[EVEN_STATE]); | |
473 | ||
474 | return bf_rate; | |
475 | } | |
476 | ||
477 |