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
7 #include "ht2crackutils.h"
9 #define INPUTFILE "sorted/%02x/%02x.bin"
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
) {
34 printf("loadrngdata: invalid params\n");
38 fd
= open(file
, O_RDONLY
);
41 printf("cannot open file %s\n", file
);
45 if (fstat(fd
, &filestat
)) {
46 printf("cannot stat file %s\n", file
);
50 if (filestat
.st_size
< 6) {
51 printf("file %s is too small\n", file
);
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
);
61 r
->len
= filestat
.st_size
/ 2;
62 // printf("r->len = %d\n", r->len);
64 r
->data
= (unsigned char *)malloc(r
->len
);
66 printf("cannot malloc\n");
72 for (i
= 0; (i
< filestat
.st_size
) && (j
< r
->len
); i
++) {
73 if ((data
[i
] != 0x0a) && (data
[i
] != 0x0d) && (data
[i
] != 0x20)) {
75 r
->data
[j
] = hex2bin(data
[i
]) << 4;
78 r
->data
[j
] |= hex2bin(data
[i
]);
87 munmap(data
, filestat
.st_size
);
93 static int makecand(unsigned char *c
, struct rngdata
*r
, int bitoffset
) {
98 if (!c
|| !r
|| (bitoffset
> ((r
->len
* 8) - 48))) {
99 printf("makecand: invalid params\n");
103 bytenum
= bitoffset
/ 8;
104 bitnum
= bitoffset
% 8;
106 for (i
= 0; i
< 6; i
++) {
108 c
[i
] = r
->data
[bytenum
+ i
];
110 c
[i
] = (r
->data
[bytenum
+ i
] << bitnum
) | (r
->data
[bytenum
+ i
+ 1] >> (8 - bitnum
));
118 // test the candidate against the next or previous rng data
119 static int testcand(unsigned char *f
, unsigned char *rt
, int fwd
) {
124 unsigned char buf
[6];
126 // build the prng state at the candidate
128 for (i
= 0; i
< 6; i
++) {
129 hstate
.shiftreg
= (hstate
.shiftreg
<< 8) | f
[i
+ 4];
134 // roll forwards 48 bits
135 hitag2_nstep(&hstate
, 48);
137 // roll backwards 48 bits
138 rollback(&hstate
, 48);
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);
150 if (!memcmp(buf
, rt
, 6)) {
157 static int searchcand(unsigned char *c
, unsigned char *rt
, int fwd
, unsigned char *m
, unsigned char *s
) {
159 struct stat filestat
;
162 unsigned char item
[10];
163 unsigned char *found
= NULL
;
166 if (!c
|| !rt
|| !m
|| !s
) {
167 printf("searchcand: invalid params\n");
171 sprintf(file
, INPUTFILE
, c
[0], c
[1]);
173 fd
= open(file
, O_RDONLY
);
175 printf("cannot open table file %s\n", file
);
179 if (fstat(fd
, &filestat
)) {
180 printf("cannot stat file %s\n", file
);
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
);
190 memcpy(item
, c
+ 2, 4);
192 found
= (unsigned char *)bsearch(item
, data
, filestat
.st_size
/ DATASIZE
, DATASIZE
, datacmp
);
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
)) {
206 memcpy(m
+ 2, found
, 4);
207 memcpy(s
, found
+ 4, 6);
209 munmap(data
, filestat
.st_size
);
214 found
= found
+ DATASIZE
;
218 munmap(data
, filestat
.st_size
);
225 static int findmatch(struct rngdata
*r
, unsigned char *outmatch
, unsigned char *outstate
, int *bitoffset
) {
228 unsigned char cand
[6];
229 unsigned char rngtest
[6];
232 if (!r
|| !outmatch
|| !outstate
|| !bitoffset
) {
233 printf("findmatch: invalid params\n");
239 for (i
= 0; i
<= bitlen
- 48; i
++) {
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
);
249 // printf("cand: %02x %02x %02x %02x %02x %02x : ", cand[0], cand[1], cand[2], cand[3], cand[4], cand[5]);
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
);
260 if (!makecand(rngtest
, r
, i
- 48)) {
261 printf("cannot makecand rngtest %d - 48\n", i
);
267 if (searchcand(cand
, rngtest
, fwd
, outmatch
, outstate
)) {
279 static void rollbackrng(Hitag_State
*hstate
, unsigned char *s
, int offset
) {
283 printf("rollbackrng: invalid params\n");
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
);
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");
308 static uint64_t recoverkey(Hitag_State
*hstate
, char *uidstr
, char *nRstr
) {
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
));
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");
338 printf("nRenc:\t\t");
339 printbin2(nRenc
, 32);
348 keyupper
= nRxork
^ nR
;
349 key
= key
| (keyupper
<< 16);
358 int main(int argc
, char *argv
[]) {
362 unsigned char rngmatch
[6];
363 unsigned char rngstate
[6];
371 printf("%s rngdatafile UID nR\n", argv
[0]);
375 if (!loadrngdata(&rng
, argv
[1])) {
376 printf("loadrngdata failed\n");
380 if (!strncmp(argv
[2], "0x", 2)) {
381 uidstr
= argv
[2] + 2;
386 if (!strncmp(argv
[3], "0x", 2)) {
393 if (!findmatch(&rng
, rngmatch
, rngstate
, &bitoffset
)) {
394 printf("couldn't find a match\n");
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
);
408 printf("keyrev:\t\t");
413 for (i
= 0; i
< 6; i
++) {
414 printf("%02X", (int)(key
& 0xff));