]> git.zerfleddert.de Git - proxmark3-svn/blob - client/hardnested/hardnested_bruteforce.c
3218c1aa41a62260dfaee5abdcaa350cf73b2d94
[proxmark3-svn] / client / hardnested / hardnested_bruteforce.c
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 <malloc.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 "crapto1/crapto1.h"
64 #include "parity.h"
65
66 #define NUM_BRUTE_FORCE_THREADS (num_CPUs())
67 #define DEFAULT_BRUTE_FORCE_RATE (120000000.0) // if benchmark doesn't succeed
68 #define TEST_BENCH_SIZE (6000) // number of odd and even states for brute force benchmark
69 #define TEST_BENCH_FILENAME "hardnested/bf_bench_data.bin"
70 //#define WRITE_BENCH_FILE
71
72 // debugging options
73 #define DEBUG_KEY_ELIMINATION
74 // #define DEBUG_BRUTE_FORCE
75
76 typedef enum {
77 EVEN_STATE = 0,
78 ODD_STATE = 1
79 } odd_even_t;
80
81 static uint32_t nonces_to_bruteforce = 0;
82 static uint32_t bf_test_nonce[256];
83 static uint8_t bf_test_nonce_2nd_byte[256];
84 static uint8_t bf_test_nonce_par[256];
85 static uint32_t bucket_count = 0;
86 static statelist_t* buckets[128];
87 static uint32_t keys_found = 0;
88 static uint64_t num_keys_tested;
89
90
91 uint8_t trailing_zeros(uint8_t byte)
92 {
93 static const uint8_t trailing_zeros_LUT[256] = {
94 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
95 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
96 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
97 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
98 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
99 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
100 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
101 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
102 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
103 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
104 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
105 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
106 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
107 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
108 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
109 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
110 };
111
112 return trailing_zeros_LUT[byte];
113 }
114
115
116 bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even)
117 {
118 struct Crypto1State pcs;
119 for (uint16_t test_first_byte = 1; test_first_byte < 256; test_first_byte++) {
120 noncelistentry_t *test_nonce = nonces[best_first_bytes[test_first_byte]].first;
121 while (test_nonce != NULL) {
122 pcs.odd = odd;
123 pcs.even = even;
124 lfsr_rollback_byte(&pcs, (cuid >> 24) ^ best_first_bytes[0], true);
125 for (int8_t byte_pos = 3; byte_pos >= 0; byte_pos--) {
126 uint8_t test_par_enc_bit = (test_nonce->par_enc >> byte_pos) & 0x01; // the encoded parity bit
127 uint8_t test_byte_enc = (test_nonce->nonce_enc >> (8*byte_pos)) & 0xff; // the encoded nonce byte
128 uint8_t test_byte_dec = crypto1_byte(&pcs, test_byte_enc /* ^ (cuid >> (8*byte_pos)) */, true) ^ test_byte_enc; // decode the nonce byte
129 uint8_t ks_par = filter(pcs.odd); // the keystream bit to encode/decode the parity bit
130 uint8_t test_par_enc2 = ks_par ^ evenparity8(test_byte_dec); // determine the decoded byte's parity and encode it
131 if (test_par_enc_bit != test_par_enc2) {
132 return false;
133 }
134 }
135 test_nonce = test_nonce->next;
136 }
137 }
138 return true;
139 }
140
141
142 static void* crack_states_thread(void* x){
143
144 struct arg {
145 bool silent;
146 int thread_ID;
147 uint32_t cuid;
148 uint32_t num_acquired_nonces;
149 uint64_t maximum_states;
150 noncelist_t *nonces;
151 uint8_t* best_first_bytes;
152 } *thread_arg;
153
154 thread_arg = (struct arg *)x;
155 const int thread_id = thread_arg->thread_ID;
156 uint32_t current_bucket = thread_id;
157 while(current_bucket < bucket_count){
158 statelist_t *bucket = buckets[current_bucket];
159 if(bucket){
160 #if defined (DEBUG_BRUTE_FORCE)
161 printf("Thread %u starts working on bucket %u\n", thread_id, current_bucket);
162 #endif
163 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);
164 if(key != -1){
165 __sync_fetch_and_add(&keys_found, 1);
166 char progress_text[80];
167 sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key);
168 hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0);
169 break;
170 } else if(keys_found){
171 break;
172 } else {
173 if (!thread_arg->silent) {
174 char progress_text[80];
175 sprintf(progress_text, "Brute force phase: %6.02f%%", 100.0*(float)num_keys_tested/(float)(thread_arg->maximum_states));
176 float remaining_bruteforce = thread_arg->nonces[thread_arg->best_first_bytes[0]].expected_num_brute_force - (float)num_keys_tested/2;
177 hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, remaining_bruteforce, 5000);
178 }
179 }
180 }
181 current_bucket += NUM_BRUTE_FORCE_THREADS;
182 }
183 return NULL;
184 }
185
186
187 void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte)
188 {
189 // we do bitsliced brute forcing with best_first_bytes[0] only.
190 // Extract the corresponding 2nd bytes
191 noncelistentry_t *test_nonce = nonces[best_first_byte].first;
192 uint32_t i = 0;
193 while (test_nonce != NULL) {
194 bf_test_nonce[i] = test_nonce->nonce_enc;
195 bf_test_nonce_par[i] = test_nonce->par_enc;
196 bf_test_nonce_2nd_byte[i] = (test_nonce->nonce_enc >> 16) & 0xff;
197 test_nonce = test_nonce->next;
198 i++;
199 }
200 nonces_to_bruteforce = i;
201
202 // printf("Nonces to bruteforce: %d\n", nonces_to_bruteforce);
203 // printf("Common bits of first 4 2nd nonce bytes (before sorting): %u %u %u\n",
204 // trailing_zeros(bf_test_nonce_2nd_byte[1] ^ bf_test_nonce_2nd_byte[0]),
205 // trailing_zeros(bf_test_nonce_2nd_byte[2] ^ bf_test_nonce_2nd_byte[1]),
206 // trailing_zeros(bf_test_nonce_2nd_byte[3] ^ bf_test_nonce_2nd_byte[2]));
207
208 uint8_t best_4[4] = {0};
209 int sum_best = -1;
210 for (uint16_t n1 = 0; n1 < nonces_to_bruteforce; n1++) {
211 for (uint16_t n2 = 0; n2 < nonces_to_bruteforce; n2++) {
212 if (n2 != n1) {
213 for (uint16_t n3 = 0; n3 < nonces_to_bruteforce; n3++) {
214 if ((n3 != n2 && n3 != n1) || nonces_to_bruteforce < 3
215 // && trailing_zeros(bf_test_nonce_2nd_byte[n1] ^ bf_test_nonce_2nd_byte[n2])
216 // > trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3])
217 ) {
218 for (uint16_t n4 = 0; n4 < nonces_to_bruteforce; n4++) {
219 if ((n4 != n3 && n4 != n2 && n4 != n1) || nonces_to_bruteforce < 4
220 // && trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3])
221 // > trailing_zeros(bf_test_nonce_2nd_byte[n3] ^ bf_test_nonce_2nd_byte[n4])
222 ) {
223 int sum = nonces_to_bruteforce > 1 ? trailing_zeros(bf_test_nonce_2nd_byte[n1] ^ bf_test_nonce_2nd_byte[n2]) : 0.0
224 + nonces_to_bruteforce > 2 ? trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3]) : 0.0
225 + nonces_to_bruteforce > 3 ? trailing_zeros(bf_test_nonce_2nd_byte[n3] ^ bf_test_nonce_2nd_byte[n4]) : 0.0;
226 if (sum > sum_best) {
227 sum_best = sum;
228 best_4[0] = n1;
229 best_4[1] = n2;
230 best_4[2] = n3;
231 best_4[3] = n4;
232 }
233 }
234 }
235 }
236 }
237 }
238 }
239 }
240
241 uint32_t bf_test_nonce_temp[4];
242 uint8_t bf_test_nonce_par_temp[4];
243 uint8_t bf_test_nonce_2nd_byte_temp[4];
244 for (uint8_t i = 0; i < 4 && i < nonces_to_bruteforce; i++) {
245 bf_test_nonce_temp[i] = bf_test_nonce[best_4[i]];
246
247 bf_test_nonce_par_temp[i] = bf_test_nonce_par[best_4[i]];
248 bf_test_nonce_2nd_byte_temp[i] = bf_test_nonce_2nd_byte[best_4[i]];
249 }
250 for (uint8_t i = 0; i < 4 && i < nonces_to_bruteforce; i++) {
251 bf_test_nonce[i] = bf_test_nonce_temp[i];
252 bf_test_nonce_par[i] = bf_test_nonce_par_temp[i];
253 bf_test_nonce_2nd_byte[i] = bf_test_nonce_2nd_byte_temp[i];
254 }
255 }
256
257
258 #if defined (WRITE_BENCH_FILE)
259 static void write_benchfile(statelist_t *candidates) {
260
261 printf("Writing brute force benchmark data...");
262 FILE *benchfile = fopen(TEST_BENCH_FILENAME, "wb");
263 fwrite(&nonces_to_bruteforce, 1, sizeof(nonces_to_bruteforce), benchfile);
264 for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
265 fwrite(&(bf_test_nonce[i]), 1, sizeof(bf_test_nonce[i]), benchfile);
266 fwrite(&(bf_test_nonce_par[i]), 1, sizeof(bf_test_nonce_par[i]), benchfile);
267 }
268 uint32_t num_states = MIN(candidates->len[EVEN_STATE], TEST_BENCH_SIZE);
269 fwrite(&num_states, 1, sizeof(num_states), benchfile);
270 for (uint32_t i = 0; i < num_states; i++) {
271 fwrite(&(candidates->states[EVEN_STATE][i]), 1, sizeof(uint32_t), benchfile);
272 }
273 num_states = MIN(candidates->len[ODD_STATE], TEST_BENCH_SIZE);
274 fwrite(&num_states, 1, sizeof(num_states), benchfile);
275 for (uint32_t i = 0; i < num_states; i++) {
276 fwrite(&(candidates->states[ODD_STATE][i]), 1, sizeof(uint32_t), benchfile);
277 }
278 fclose(benchfile);
279 printf("done.\n");
280 }
281 #endif
282
283
284 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)
285 {
286 #if defined (WRITE_BENCH_FILE)
287 write_benchfile(candidates);
288 #endif
289 bool silent = (bf_rate != NULL);
290
291 // if (!silent) {
292 // PrintAndLog("Brute force phase starting.");
293 // PrintAndLog("Using %u-bit bitslices", MAX_BITSLICES);
294 // }
295
296 keys_found = 0;
297 num_keys_tested = 0;
298
299 bitslice_test_nonces(nonces_to_bruteforce, bf_test_nonce, bf_test_nonce_par);
300
301 // count number of states to go
302 bucket_count = 0;
303 for (statelist_t *p = candidates; p != NULL; p = p->next) {
304 if (p->states[ODD_STATE] != NULL && p->states[EVEN_STATE] != NULL) {
305 buckets[bucket_count] = p;
306 bucket_count++;
307 }
308 }
309
310 uint64_t start_time = msclock();
311 // enumerate states using all hardware threads, each thread handles one bucket
312 // if (!silent) {
313 // PrintAndLog("Starting %u cracking threads to search %u buckets containing a total of %" PRIu64" states...\n", NUM_BRUTE_FORCE_THREADS, bucket_count, maximum_states);
314 // printf("Common bits of first 4 2nd nonce bytes: %u %u %u\n",
315 // trailing_zeros(bf_test_nonce_2nd_byte[1] ^ bf_test_nonce_2nd_byte[0]),
316 // trailing_zeros(bf_test_nonce_2nd_byte[2] ^ bf_test_nonce_2nd_byte[1]),
317 // trailing_zeros(bf_test_nonce_2nd_byte[3] ^ bf_test_nonce_2nd_byte[2]));
318 // }
319
320 pthread_t threads[NUM_BRUTE_FORCE_THREADS];
321 struct args {
322 bool silent;
323 int thread_ID;
324 uint32_t cuid;
325 uint32_t num_acquired_nonces;
326 uint64_t maximum_states;
327 noncelist_t *nonces;
328 uint8_t *best_first_bytes;
329 } thread_args[NUM_BRUTE_FORCE_THREADS];
330
331 for(uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++){
332 thread_args[i].thread_ID = i;
333 thread_args[i].silent = silent;
334 thread_args[i].cuid = cuid;
335 thread_args[i].num_acquired_nonces = num_acquired_nonces;
336 thread_args[i].maximum_states = maximum_states;
337 thread_args[i].nonces = nonces;
338 thread_args[i].best_first_bytes = best_first_bytes;
339 pthread_create(&threads[i], NULL, crack_states_thread, (void*)&thread_args[i]);
340 }
341 for(uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++){
342 pthread_join(threads[i], 0);
343 }
344
345 uint64_t elapsed_time = msclock() - start_time;
346
347 // if (!silent) {
348 // 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",
349 // num_keys_tested,
350 // log(num_keys_tested) / log(2.0),
351 // (float)elapsed_time/1000.0,
352 // (float)num_keys_tested / ((float)elapsed_time / 1000.0),
353 // log((float)num_keys_tested / ((float)elapsed_time/1000.0)) / log(2.0));
354 // }
355
356 if (bf_rate != NULL) {
357 *bf_rate = (float)num_keys_tested / ((float)elapsed_time / 1000.0);
358 }
359
360 return (keys_found != 0);
361 }
362
363
364 static bool read_bench_data(statelist_t *test_candidates) {
365
366 size_t bytes_read = 0;
367 uint32_t temp = 0;
368 uint32_t num_states = 0;
369 uint32_t states_read = 0;
370
371 char bench_file_path[strlen(get_my_executable_directory()) + strlen(TEST_BENCH_FILENAME) + 1];
372 strcpy(bench_file_path, get_my_executable_directory());
373 strcat(bench_file_path, TEST_BENCH_FILENAME);
374
375 FILE *benchfile = fopen(bench_file_path, "rb");
376 if (benchfile == NULL) {
377 return false;
378 }
379 bytes_read = fread(&nonces_to_bruteforce, 1, sizeof(nonces_to_bruteforce), benchfile);
380 if (bytes_read != sizeof(nonces_to_bruteforce)) {
381 fclose(benchfile);
382 return false;
383 }
384 for (uint16_t i = 0; i < nonces_to_bruteforce && i < 256; i++) {
385 bytes_read = fread(&bf_test_nonce[i], 1, sizeof(uint32_t), benchfile);
386 if (bytes_read != sizeof(uint32_t)) {
387 fclose(benchfile);
388 return false;
389 }
390 bf_test_nonce_2nd_byte[i] = (bf_test_nonce[i] >> 16) & 0xff;
391 bytes_read = fread(&bf_test_nonce_par[i], 1, sizeof(uint8_t), benchfile);
392 if (bytes_read != sizeof(uint8_t)) {
393 fclose(benchfile);
394 return false;
395 }
396 }
397 bytes_read = fread(&num_states, 1, sizeof(uint32_t), benchfile);
398 if (bytes_read != sizeof(uint32_t)) {
399 fclose(benchfile);
400 return false;
401 }
402 for (states_read = 0; states_read < MIN(num_states, TEST_BENCH_SIZE); states_read++) {
403 bytes_read = fread(test_candidates->states[EVEN_STATE] + states_read, 1, sizeof(uint32_t), benchfile);
404 if (bytes_read != sizeof(uint32_t)) {
405 fclose(benchfile);
406 return false;
407 }
408 }
409 for (uint32_t i = states_read; i < TEST_BENCH_SIZE; i++) {
410 test_candidates->states[EVEN_STATE][i] = test_candidates->states[EVEN_STATE][i-states_read];
411 }
412 for (uint32_t i = states_read; i < num_states; i++) {
413 bytes_read = fread(&temp, 1, sizeof(uint32_t), benchfile);
414 if (bytes_read != sizeof(uint32_t)) {
415 fclose(benchfile);
416 return false;
417 }
418 }
419 for (states_read = 0; states_read < MIN(num_states, TEST_BENCH_SIZE); states_read++) {
420 bytes_read = fread(test_candidates->states[ODD_STATE] + states_read, 1, sizeof(uint32_t), benchfile);
421 if (bytes_read != sizeof(uint32_t)) {
422 fclose(benchfile);
423 return false;
424 }
425 }
426 for (uint32_t i = states_read; i < TEST_BENCH_SIZE; i++) {
427 test_candidates->states[ODD_STATE][i] = test_candidates->states[ODD_STATE][i-states_read];
428 }
429
430 fclose(benchfile);
431 return true;
432 }
433
434
435 float brute_force_benchmark()
436 {
437 statelist_t test_candidates[NUM_BRUTE_FORCE_THREADS];
438
439 test_candidates[0].states[ODD_STATE] = malloc((TEST_BENCH_SIZE+1) * sizeof(uint32_t));
440 test_candidates[0].states[EVEN_STATE] = malloc((TEST_BENCH_SIZE+1) * sizeof(uint32_t));
441 for (uint8_t i = 0; i < NUM_BRUTE_FORCE_THREADS - 1; i++){
442 test_candidates[i].next = test_candidates + i + 1;
443 test_candidates[i+1].states[ODD_STATE] = test_candidates[0].states[ODD_STATE];
444 test_candidates[i+1].states[EVEN_STATE] = test_candidates[0].states[EVEN_STATE];
445 }
446 test_candidates[NUM_BRUTE_FORCE_THREADS-1].next = NULL;
447
448 if (!read_bench_data(test_candidates)) {
449 PrintAndLog("Couldn't read benchmark data. Assuming brute force rate of %1.0f states per second", DEFAULT_BRUTE_FORCE_RATE);
450 return DEFAULT_BRUTE_FORCE_RATE;
451 }
452
453 for (uint8_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
454 test_candidates[i].len[ODD_STATE] = TEST_BENCH_SIZE;
455 test_candidates[i].len[EVEN_STATE] = TEST_BENCH_SIZE;
456 test_candidates[i].states[ODD_STATE][TEST_BENCH_SIZE] = -1;
457 test_candidates[i].states[EVEN_STATE][TEST_BENCH_SIZE] = -1;
458 }
459
460 uint64_t maximum_states = TEST_BENCH_SIZE*TEST_BENCH_SIZE*(uint64_t)NUM_BRUTE_FORCE_THREADS;
461
462 float bf_rate;
463 brute_force_bs(&bf_rate, test_candidates, 0, 0, maximum_states, NULL, 0);
464
465 free(test_candidates[0].states[ODD_STATE]);
466 free(test_candidates[0].states[EVEN_STATE]);
467
468 return bf_rate;
469 }
470
471
Impressum, Datenschutz