hf mf fchk - output style
[RRG-proxmark3.git] / tools / hitag2crack / crack2 / ht2crack2search.c
blobd339f878f380dfc6052dd4f8c57b60f7750bfd76
1 /*
2 * ht2crack2search.c
3 * this searches the sorted tables for the given RNG data, retrieves the matching
4 * PRNG state, checks it is correct, and then rolls back the PRNG to recover the key
5 */
7 #include "ht2crackutils.h"
9 #define INPUTFILE "sorted/%02x/%02x.bin"
10 #define DATASIZE 10
12 struct rngdata {
13 unsigned char *data;
14 int len;
19 static int datacmp(const void *p1, const void *p2) {
20 unsigned char *d1 = (unsigned char *)p1;
21 unsigned char *d2 = (unsigned char *)p2;
23 return memcmp(d1, d2, DATASIZE - 6);
26 static int loadrngdata(struct rngdata *r, char *file) {
27 int fd;
28 int i, j;
29 int nibble;
30 struct stat filestat;
31 unsigned char *data;
33 if (!r || !file) {
34 printf("loadrngdata: invalid params\n");
35 return 0;
38 fd = open(file, O_RDONLY);
40 if (fd <= 0) {
41 printf("cannot open file %s\n", file);
42 exit(1);
45 if (fstat(fd, &filestat)) {
46 printf("cannot stat file %s\n", file);
47 exit(1);
50 if (filestat.st_size < 6) {
51 printf("file %s is too small\n", file);
52 exit(1);
55 data = mmap((caddr_t)0, filestat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
56 if (data == MAP_FAILED) {
57 printf("cannot mmap file %s\n", file);
58 exit(1);
61 r->len = filestat.st_size / 2;
62 // printf("r->len = %d\n", r->len);
64 r->data = (unsigned char *)malloc(r->len);
65 if (!(r->data)) {
66 printf("cannot malloc\n");
67 exit(1);
70 j = 0;
71 nibble = 0;
72 for (i = 0; (i < filestat.st_size) && (j < r->len); i++) {
73 if ((data[i] != 0x0a) && (data[i] != 0x0d) && (data[i] != 0x20)) {
74 if (!nibble) {
75 r->data[j] = hex2bin(data[i]) << 4;
76 nibble = 1;
77 } else {
78 r->data[j] |= hex2bin(data[i]);
79 nibble = 0;
80 j++;
85 r->len = j;
87 munmap(data, filestat.st_size);
88 close(fd);
90 return 1;
93 static int makecand(unsigned char *c, struct rngdata *r, int bitoffset) {
94 int bytenum;
95 int bitnum;
96 int i;
98 if (!c || !r || (bitoffset > ((r->len * 8) - 48))) {
99 printf("makecand: invalid params\n");
100 return 0;
103 bytenum = bitoffset / 8;
104 bitnum = bitoffset % 8;
106 for (i = 0; i < 6; i++) {
107 if (!bitnum) {
108 c[i] = r->data[bytenum + i];
109 } else {
110 c[i] = (r->data[bytenum + i] << bitnum) | (r->data[bytenum + i + 1] >> (8 - bitnum));
114 return 1;
118 // test the candidate against the next or previous rng data
119 static int testcand(unsigned char *f, unsigned char *rt, int fwd) {
120 Hitag_State hstate;
121 int i;
122 uint32_t ks1;
123 uint32_t ks2;
124 unsigned char buf[6];
126 // build the prng state at the candidate
127 hstate.shiftreg = 0;
128 for (i = 0; i < 6; i++) {
129 hstate.shiftreg = (hstate.shiftreg << 8) | f[i + 4];
131 buildlfsr(&hstate);
133 if (fwd) {
134 // roll forwards 48 bits
135 hitag2_nstep(&hstate, 48);
136 } else {
137 // roll backwards 48 bits
138 rollback(&hstate, 48);
139 buildlfsr(&hstate);
142 // get 48 bits of RNG from the rolled to state
143 ks1 = hitag2_nstep(&hstate, 24);
144 ks2 = hitag2_nstep(&hstate, 24);
146 writebuf(buf, ks1, 3);
147 writebuf(buf + 3, ks2, 3);
149 // compare them
150 if (!memcmp(buf, rt, 6)) {
151 return 1;
152 } else {
153 return 0;
157 static int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, unsigned char *s) {
158 int fd;
159 struct stat filestat;
160 char file[64];
161 unsigned char *data;
162 unsigned char item[10];
163 unsigned char *found = NULL;
166 if (!c || !rt || !m || !s) {
167 printf("searchcand: invalid params\n");
168 return 0;
171 sprintf(file, INPUTFILE, c[0], c[1]);
173 fd = open(file, O_RDONLY);
174 if (fd <= 0) {
175 printf("cannot open table file %s\n", file);
176 exit(1);
179 if (fstat(fd, &filestat)) {
180 printf("cannot stat file %s\n", file);
181 exit(1);
184 data = mmap((caddr_t)0, filestat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
185 if (data == MAP_FAILED) {
186 printf("cannot mmap file %s\n", file);
187 exit(1);
190 memcpy(item, c + 2, 4);
192 found = (unsigned char *)bsearch(item, data, filestat.st_size / DATASIZE, DATASIZE, datacmp);
194 if (found) {
196 // our candidate is in the table
197 // go backwards and see if there are other matches
198 while (((found - data) >= DATASIZE) && (!memcmp(found - DATASIZE, item, 4))) {
199 found = found - DATASIZE;
202 // now test all matches
203 while (((found - data) <= (filestat.st_size - DATASIZE)) && (!memcmp(found, item, 4))) {
204 if (testcand(found, rt, fwd)) {
205 memcpy(m, c, 2);
206 memcpy(m + 2, found, 4);
207 memcpy(s, found + 4, 6);
209 munmap(data, filestat.st_size);
210 close(fd);
211 return 1;
214 found = found + DATASIZE;
218 munmap(data, filestat.st_size);
219 close(fd);
221 return 0;
225 static int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstate, int *bitoffset) {
226 int i;
227 int bitlen;
228 unsigned char cand[6];
229 unsigned char rngtest[6];
230 int fwd;
232 if (!r || !outmatch || !outstate || !bitoffset) {
233 printf("findmatch: invalid params\n");
234 return 0;
237 bitlen = r->len * 8;
239 for (i = 0; i <= bitlen - 48; i++) {
240 // print progress
241 if ((i % 100) == 0) {
242 printf("searching on bit %d\n", i);
245 if (!makecand(cand, r, i)) {
246 printf("cannot makecand, %d\n", i);
247 return 0;
249 // printf("cand: %02x %02x %02x %02x %02x %02x : ", cand[0], cand[1], cand[2], cand[3], cand[4], cand[5]);
250 // printbin(cand);
252 /* make following or preceding RNG test data to confirm match */
253 if (i < (bitlen - 96)) {
254 if (!makecand(rngtest, r, i + 48)) {
255 printf("cannot makecand rngtest %d + 48\n", i);
256 return 0;
258 fwd = 1;
259 } else {
260 if (!makecand(rngtest, r, i - 48)) {
261 printf("cannot makecand rngtest %d - 48\n", i);
262 return 0;
264 fwd = 0;
267 if (searchcand(cand, rngtest, fwd, outmatch, outstate)) {
268 *bitoffset = i;
269 return 1;
273 return 0;
279 static void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset) {
280 int i;
282 if (!s) {
283 printf("rollbackrng: invalid params\n");
284 return;
287 // build prng at recovered offset
288 hstate->shiftreg = 0;
289 for (i = 0; i < 6; i++) {
290 hstate->shiftreg = (hstate->shiftreg << 8) | s[i];
293 printf("recovered prng state at offset %d:\n", offset);
294 printstate(hstate);
296 // rollback to state after auth
297 rollback(hstate, offset);
299 // rollback through auth (aR, p3)
300 rollback(hstate, 64);
302 printf("prng state after initialisation:\n");
303 printstate(hstate);
308 static uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr) {
309 uint64_t key;
310 uint64_t keyupper;
311 uint32_t uid;
312 uint32_t uidtmp;
313 uint32_t nRenc;
314 uint32_t nR;
315 uint32_t nRxork;
316 uint32_t b = 0;
317 int i;
319 // key lower 16 bits are lower 16 bits of prng state
320 key = hstate->shiftreg & 0xffff;
321 nRxork = (hstate->shiftreg >> 16) & 0xffffffff;
322 uid = rev32(hexreversetoulong(uidstr));
323 nRenc = rev32(hexreversetoulong(nRstr));
325 uidtmp = uid;
326 // rollback and extract bits b
327 for (i = 0; i < 32; i++) {
328 hstate->shiftreg = ((hstate->shiftreg) << 1) | ((uidtmp >> 31) & 0x1);
329 uidtmp = uidtmp << 1;
330 b = (b << 1) | fnf(hstate->shiftreg);
333 printf("end state:\n");
334 printstate(hstate);
335 printf("b:\t\t");
336 printbin2(b, 32);
337 printf("\n");
338 printf("nRenc:\t\t");
339 printbin2(nRenc, 32);
340 printf("\n");
342 nR = nRenc ^ b;
344 printf("nR:\t\t");
345 printbin2(nR, 32);
346 printf("\n");
348 keyupper = nRxork ^ nR;
349 key = key | (keyupper << 16);
350 printf("key:\t\t");
351 printbin2(key, 48);
352 printf("\n");
354 return key;
358 int main(int argc, char *argv[]) {
359 Hitag_State hstate;
360 struct rngdata rng;
361 int bitoffset = 0;
362 unsigned char rngmatch[6];
363 unsigned char rngstate[6];
364 char *uidstr;
365 char *nRstr;
366 uint64_t keyrev;
367 uint64_t key;
368 int i;
370 if (argc < 4) {
371 printf("%s rngdatafile UID nR\n", argv[0]);
372 exit(1);
375 if (!loadrngdata(&rng, argv[1])) {
376 printf("loadrngdata failed\n");
377 exit(1);
380 if (!strncmp(argv[2], "0x", 2)) {
381 uidstr = argv[2] + 2;
382 } else {
383 uidstr = argv[2];
386 if (!strncmp(argv[3], "0x", 2)) {
387 nRstr = argv[3] + 2;
388 } else {
389 nRstr = argv[3];
393 if (!findmatch(&rng, rngmatch, rngstate, &bitoffset)) {
394 printf("couldn't find a match\n");
395 exit(1);
398 printf("found match:\n");
399 printf("rngmatch = %02x %02x %02x %02x %02x %02x\n", rngmatch[0], rngmatch[1], rngmatch[2], rngmatch[3], rngmatch[4], rngmatch[5]);
400 printf("rngstate = %02x %02x %02x %02x %02x %02x\n", rngstate[0], rngstate[1], rngstate[2], rngstate[3], rngstate[4], rngstate[5]);
401 printf("bitoffset = %d\n", bitoffset);
403 rollbackrng(&hstate, rngstate, bitoffset);
405 keyrev = recoverkey(&hstate, uidstr, nRstr);
406 key = rev64(keyrev);
408 printf("keyrev:\t\t");
409 printbin2(key, 48);
410 printf("\n");
412 printf("KEY:\t\t");
413 for (i = 0; i < 6; i++) {
414 printf("%02X", (int)(key & 0xff));
415 key = key >> 8;
417 printf("\n");
419 return 0;