| 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> |
| 57 | #include <stdlib.h> |
| 58 | #include "proxmark3.h" |
| 59 | #include "cmdhfmfhard.h" |
| 60 | #include "hardnested_bf_core.h" |
| 61 | #include "ui.h" |
| 62 | #include "util.h" |
| 63 | #include "util_posix.h" |
| 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 | |
| 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){ |
| 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 | |