Merge pull request #2664 from piotrva/hf-mf-ultimatecard-script-max-rw-blocks
[RRG-proxmark3.git] / tools / hitag2crack / crack2 / ht2crack2buildtable.c
blob625a0f1753d58fda8da580cf03ac1040ba9d2d8a
1 /*
2 * ht2crack2buildtable.c
3 * This builds the 1.2TB table and sorts it.
4 */
6 #include "ht2crackutils.h"
7 #include <stdlib.h>
9 // DATAMAX is the size of each bucket (bytes). There are 65536 buckets so choose a value such that
10 // DATAMAX * 65536 < RAM available. For ex, if you want to use 12GB of RAM (for a 16GB machine
11 // leaving some RAM free for OS and other stuff), DATAMAX = 12GB / 65536 = 196608. Round this down
12 // to a power of 10; DATAMAX = 196600.
13 #define DATAMAX 196600 // around 192K rounded down to a power of 10
15 // NUM_BUILD_THREADS and NUM_SORT_THREADS are the number of threads to run concurrently. These should
16 // ideally be equal to the number of virtual cores you have available. A quad-core machine will
17 // likely have 8 virtual cores, so set them to 8.
19 // If sorting fails with a 'bus error' then that is likely because your disk I/O can't keep up with
20 // the read/write demands of the multi-threaded sorting. In this case, reduce the number of sorting
21 // threads. This will most likely only be a problem with network disks; SATA should be okay;
22 // USB2/3 should keep up.
24 // These MUST be a power of 2 for the maths to work - you have been warned!
25 // Also, sort threads MUST be <= build threads or a horrible buffer overflow will happen!
26 #define NUM_BUILD_THREADS 8
27 #define NUM_SORT_THREADS 8
29 // DATASIZE is the number of bytes in an entry. This is 10; 4 bytes of keystream (2 are in the filepath) +
30 // 6 bytes of PRNG state.
31 #define DATASIZE 10
33 int debug = 0;
35 // table entry for a bucket
36 struct table {
37 char path[32];
38 pthread_mutex_t mutex;
39 unsigned char *data;
40 unsigned char *ptr;
44 // actual table
45 struct table *t;
47 // jump table 1
48 uint64_t d[48];
49 int nsteps;
51 // jump table 2
52 uint64_t d2[48];
53 int nsteps2;
55 // create table entry
56 static void create_table(struct table *tt, int d_1, int d_2) {
57 if (!tt) {
58 printf("create_table: t is NULL\n");
59 exit(1);
62 // create some space
63 tt->data = (unsigned char *)calloc(1, DATAMAX);
64 if (!(tt->data)) {
65 printf("create_table: cannot calloc data\n");
66 exit(1);
69 // set data ptr to start of data table
70 tt->ptr = tt->data;
72 // init the mutex
73 if (pthread_mutex_init(&(tt->mutex), NULL)) {
74 printf("create_table: cannot init mutex\n");
75 exit(1);
78 // create the path
79 // snprintf(tt->path, sizeof(tt->path), "/Volumes/2tb/%02X/%02X.bin", d_1 & 0xff, d_2 & 0xff);
80 snprintf(tt->path, sizeof(tt->path), "table/%02x/%02x.bin", d_1 & 0xff, d_2 & 0xff);
84 // create all table entries
85 static void create_tables(struct table *tt) {
86 int i, j;
88 if (!tt) {
89 printf("create_tables: t is NULL\n");
90 exit(1);
93 for (i = 0; i < 0x100; i++) {
94 for (j = 0; j < 0x100; j++) {
95 create_table(tt + ((i * 0x100) + j), i, j);
101 // free the table memory
102 static void free_tables(struct table *tt) {
103 if (!tt) {
104 printf("free_tables: tt is NULL\n");
105 exit(1);
108 for (int i = 0; i < 0x10000; i++) {
109 struct table *ttmp = tt + i;
110 free(ttmp->data);
116 // write (partial) table to file
117 static void writetable(struct table *t1) {
118 int fd;
120 if (debug) printf("writetable %s\n", t1->path);
122 fd = open(t1->path, O_WRONLY | O_CREAT | O_APPEND, 0644);
123 if (fd <= 0) {
124 printf("writetable cannot open file %s for appending\n", t1->path);
125 exit(1);
128 if (debug) printf("writetable %s opened\n", t1->path);
130 if (write(fd, t1->data, t1->ptr - t1->data) < (t1->ptr - t1->data)) {
131 printf("writetable cannot write all of the data\n");
132 exit(1);
135 if (debug) printf("writetable %s written\n", t1->path);
137 close(fd);
141 // store value in table
142 static void store(unsigned char *data) {
143 unsigned char d_1, d_2;
144 int offset;
145 struct table *t1;
147 // use the first two bytes as an index
148 d_1 = data[0];
149 d_2 = data[1];
150 offset = (d_1 * 0x100) + d_2;
152 if (debug) printf("store, d1=%02X, d2=%02X, offset = %d\n", d_1, d_2, offset);
154 // get pointer to table entry
155 t1 = t + offset;
157 // wait for a lock on this entry
158 if (pthread_mutex_lock(&(t1->mutex))) {
159 printf("store: cannot lock mutex at offset %d\n", offset);
160 exit(1);
163 if (debug) printf("store, offset = %d, got lock\n", offset);
165 // store the entry
166 memcpy(t1->ptr, data + 2, 10);
168 if (debug) printf("store, offset = %d, copied data\n", offset);
170 // update the ptr
171 t1->ptr += 10;
173 // check if table is full
174 if ((t1->ptr - t1->data) >= DATAMAX) {
175 // write the table to disk
176 writetable(t1);
177 // reset ptr
178 t1->ptr = t1->data;
181 if (debug) printf("store, offset = %d, after possible write\n", offset);
183 // release the lock
184 if (pthread_mutex_unlock(&(t1->mutex))) {
185 printf("store: cannot unlock mutex at offset %d\n", offset);
186 exit(1);
189 if (debug) printf("store, offset = %d, unlocked\n", offset);
193 // writes the ks (keystream) and s (state)
194 static void write_ks_s(uint32_t ks1, uint32_t ks2, uint64_t shiftreg) {
195 unsigned char buf[16];
197 // create buffer
198 writebuf(buf, ks1, 3);
199 writebuf(buf + 3, ks2, 3);
200 writebuf(buf + 6, shiftreg, 6);
202 // store buffer
203 store(buf);
207 // builds the di table for jumping
208 static void builddi(int steps, int table) {
209 uint64_t statemask;
210 int i;
211 Hitag_State mystate;
212 uint64_t *thisd = NULL;
214 statemask = 1;
216 // select jump table
217 if (table == 1) {
218 nsteps = steps;
219 thisd = d;
220 } else if (table == 2) {
221 nsteps2 = steps;
222 thisd = d2;
223 } else {
224 printf("builddi: invalid table num\n");
225 exit(1);
228 // build di states
229 for (i = 0; i < 48; i++) {
230 mystate.shiftreg = statemask;
231 buildlfsr(&mystate);
232 hitag2_nstep(&mystate, steps);
233 thisd[i] = mystate.shiftreg;
235 statemask = statemask << 1;
239 // jump function - quickly jumps a load of steps
240 static void jumpnsteps(Hitag_State *hstate, int table) {
241 uint64_t output = 0;
242 uint64_t bitmask;
243 int i;
244 uint64_t *thisd = NULL;
247 // select jump table
248 if (table == 1) {
249 thisd = d;
250 } else if (table == 2) {
251 thisd = d2;
252 } else {
253 printf("jumpnsteps: invalid table num\n");
254 exit(1);
257 // xor all di.si where di is a d state and si is a bit
258 // we do this by multiplying di by si:
259 // if si is 1, di.si = di; if si is 0, di.si = 0
261 bitmask = 1;
262 for (i = 0; i < 48; i++) {
263 if (hstate->shiftreg & bitmask) {
264 output = output ^ thisd[i];
267 bitmask = bitmask << 1;
270 hstate->shiftreg = output;
271 buildlfsr(hstate);
275 // thread to build a part of the table
276 static void *buildtable(void *dd) {
277 Hitag_State hstate;
278 Hitag_State hstate2;
279 unsigned long maxentries = 1;
280 int index = (int)(long)dd;
281 int tnum = NUM_BUILD_THREADS;
283 /* set random state */
284 hstate.shiftreg = 0x123456789abc;
285 buildlfsr(&hstate);
287 /* jump to offset using jump table 2 (2048) */
288 for (unsigned long i = 0; i < index; i++) {
289 jumpnsteps(&hstate, 2);
292 /* set max entries - this is a fraction of 2^37 depending on how many threads we are running.
293 1 thread = 2^37
294 2 threads = 2^36
295 4 threads = 2^35
296 8 threads = 2^34
299 maxentries = maxentries << 37;
300 while (!(tnum & 0x1)) {
301 maxentries = maxentries >> 1;
302 tnum = tnum >> 1;
305 /* make the entries */
306 for (unsigned long i = 0; i < maxentries; i++) {
308 // copy the current state
309 hstate2.shiftreg = hstate.shiftreg;
310 hstate2.lfsr = hstate.lfsr;
312 // get 48 bits of keystream from hstate2
313 // this is split into 2 x 24 bit
314 uint32_t ks1 = hitag2_nstep(&hstate2, 24);
315 uint32_t ks2 = hitag2_nstep(&hstate2, 24);
317 write_ks_s(ks1, ks2, hstate.shiftreg);
319 // jump hstate forward 2048 * NUM_BUILD_THREADS states using di table
320 // this is because we're running NUM_BUILD_THREADS threads at once, from NUM_BUILD_THREADS
321 // different offsets that are 2048 states apart.
322 jumpnsteps(&hstate, 1);
325 return NULL;
329 // make 'table/' (unsorted) and 'sorted/' dir structures
330 static void makedirs(void) {
331 char path[32];
332 int i;
334 if (mkdir("table", 0755)) {
335 printf("cannot make dir table\n");
336 exit(1);
338 if (mkdir("sorted", 0755)) {
339 printf("cannot make dir sorted\n");
340 exit(1);
343 for (i = 0; i < 0x100; i++) {
344 snprintf(path, sizeof(path), "table/%02x", i);
345 if (mkdir(path, 0755)) {
346 printf("cannot make dir %s\n", path);
347 exit(1);
349 snprintf(path, sizeof(path), "sorted/%02x", i);
350 if (mkdir(path, 0755)) {
351 printf("cannot make dir %s\n", path);
352 exit(1);
357 static int datacmp(const void *p1, const void *p2, void *dummy) {
358 unsigned char *d_1 = (unsigned char *)p1;
359 unsigned char *d_2 = (unsigned char *)p2;
361 return memcmp(d_1, d_2, DATASIZE);
364 static void *sorttable(void *dd) {
365 int i, j;
366 int fdin;
367 int fdout;
368 char infile[64];
369 char outfile[64];
370 unsigned char *data = NULL;
371 struct stat filestat;
372 int index = (int)(long)dd;
373 int space = 0x100 / NUM_SORT_THREADS;
375 // create table - 50MB should be enough
376 unsigned char *table = (unsigned char *)calloc(1, 50UL * 1024UL * 1024UL);
377 if (!table) {
378 printf("sorttable: cannot calloc table\n");
379 exit(1);
382 // loop over our first byte values
383 for (i = (index * space); i < ((index + 1) * space); i++) {
384 // loop over all second byte values
385 for (j = 0; j < 0x100; j++) {
387 printf("sorttable: processing bytes 0x%02x/0x%02x\n", i, j);
389 // open file, stat it and mmap it
390 snprintf(infile, sizeof(infile), "table/%02x/%02x.bin", i, j);
392 fdin = open(infile, O_RDONLY);
393 if (fdin <= 0) {
394 printf("cannot open file %s\n", infile);
395 exit(1);
398 if (fstat(fdin, &filestat)) {
399 printf("cannot stat file %s\n", infile);
400 exit(1);
403 data = mmap((caddr_t)0, filestat.st_size, PROT_READ, MAP_PRIVATE, fdin, 0);
404 if (data == MAP_FAILED) {
405 printf("cannot mmap file %s\n", infile);
406 exit(1);
409 // copy data into table
410 memcpy(table, data, filestat.st_size);
412 uint64_t numentries = filestat.st_size / DATASIZE;
414 // unmap file and close it
415 if (munmap(data, filestat.st_size)) {
416 printf("cannot munmap %s\n", infile);
417 exit(1);
420 close(fdin);
422 // sort it
423 void *dummy = NULL; // clang
424 qsort_r(table, numentries, DATASIZE, datacmp, dummy);
426 // write to file
427 snprintf(outfile, sizeof(outfile), "sorted/%02x/%02x.bin", i, j);
428 fdout = open(outfile, O_WRONLY | O_CREAT, 0644);
429 if (fdout <= 0) {
430 printf("cannot create outfile %s\n", outfile);
431 exit(1);
433 if (write(fdout, table, numentries * DATASIZE) != (numentries * DATASIZE)) {
434 printf("writetable cannot write all of the data\n");
435 exit(1);
437 close(fdout);
439 // remove input file
440 if (unlink(infile)) {
441 printf("cannot remove file %s\n", infile);
442 exit(1);
447 return NULL;
450 int main(int argc, char *argv[]) {
451 pthread_t threads[NUM_BUILD_THREADS];
452 void *status;
454 // make the table of tables
455 t = (struct table *)calloc(sizeof(struct table) * 65536, sizeof(uint8_t));
456 if (!t) {
457 printf("calloc failed\n");
458 exit(1);
461 // init the table
462 create_tables(t);
464 // create the directories
465 makedirs();
467 // build the jump table for incremental steps
468 builddi(2048 * NUM_BUILD_THREADS, 1);
470 // build the jump table for setting the offset
471 builddi(2048, 2);
473 // start the threads
474 for (long i = 0; i < NUM_BUILD_THREADS; i++) {
475 int ret = pthread_create(&(threads[i]), NULL, buildtable, (void *)(i));
476 if (ret) {
477 printf("cannot start buildtable thread %ld\n", i);
478 exit(1);
482 if (debug) printf("main, started buildtable threads\n");
484 // wait for threads to finish
485 for (long i = 0; i < NUM_BUILD_THREADS; i++) {
486 int ret = pthread_join(threads[i], &status);
487 if (ret) {
488 printf("cannot join buildtable thread %ld\n", i);
489 exit(1);
491 printf("buildtable thread %ld finished\n", i);
494 // write all remaining files
495 for (long i = 0; i < 0x10000; i++) {
496 struct table *t1 = t + i;
497 if (t1->ptr > t1->data) {
498 writetable(t1);
502 // dump the memory
503 free_tables(t);
504 free(t);
506 // now for the sorting
508 // start the threads
509 for (long i = 0; i < NUM_SORT_THREADS; i++) {
510 int ret = pthread_create(&(threads[i]), NULL, sorttable, (void *)(i));
511 if (ret) {
512 printf("cannot start sorttable thread %ld\n", i);
513 exit(1);
517 if (debug) printf("main, started sorttable threads\n");
519 // wait for threads to finish
520 for (long i = 0; i < NUM_SORT_THREADS; i++) {
521 int ret = pthread_join(threads[i], &status);
522 if (ret) {
523 printf("cannot join sorttable thread %ld\n", i);
524 exit(1);
526 printf("sorttable thread %ld finished\n", i);
529 pthread_exit(NULL);
531 return 0;