fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdlfhitag.c
blob287f39f069cc2b36ed4aaba4c6021c7166d59863
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2012 Roel Verdult
3 //
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
6 // the license.
7 //-----------------------------------------------------------------------------
8 // Low frequency Hitag support
9 //-----------------------------------------------------------------------------
10 #include "cmdlfhitag.h"
11 #include <ctype.h>
12 #include "cmdparser.h" // command_t
13 #include "comms.h"
14 #include "cmdtrace.h"
15 #include "commonutil.h"
16 #include "hitag.h"
17 #include "fileutils.h" // savefile
18 #include "protocols.h" // defines
19 #include "cliparser.h"
21 static int CmdHelp(const char *Cmd);
23 static const char *getHitagTypeStr(uint32_t uid) {
24 //uid s/n ********
25 uint8_t type = (uid >> 4) & 0xF;
26 switch (type) {
27 case 1:
28 return "PCF 7936";
29 case 2:
30 return "PCF 7946";
31 case 3:
32 return "PCF 7947";
33 case 4:
34 return "PCF 7942/44";
35 case 5:
36 return "PCF 7943";
37 case 6:
38 return "PCF 7941";
39 case 7:
40 return "PCF 7952";
41 case 9:
42 return "PCF 7945";
43 default:
44 return "";
49 static size_t nbytes(size_t nbits) {
50 return (nbits / 8) + ((nbits % 8) > 0);
54 static int CmdLFHitagList(const char *Cmd) {
55 return CmdTraceListAlias(Cmd, "lf hitag", "hitag2");
59 uint8_t *got = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
60 if (!got) {
61 PrintAndLogEx(WARNING, "Cannot allocate memory for trace");
62 return PM3_EMALLOC;
65 // Query for the actual size of the trace
66 PacketResponseNG response;
67 if (!GetFromDevice(BIG_BUF, got, PM3_CMD_DATA_SIZE, 0, NULL, 0, &response, 2500, false)) {
68 PrintAndLogEx(WARNING, "command execution time out");
69 free(got);
70 return PM3_ETIMEOUT;
73 uint16_t traceLen = response.arg[2];
74 if (traceLen > PM3_CMD_DATA_SIZE) {
75 uint8_t *p = realloc(got, traceLen);
76 if (p == NULL) {
77 PrintAndLogEx(WARNING, "Cannot allocate memory for trace");
78 free(got);
79 return PM3_EMALLOC;
81 got = p;
82 if (!GetFromDevice(BIG_BUF, got, traceLen, 0, NULL, 0, NULL, 2500, false)) {
83 PrintAndLogEx(WARNING, "command execution time out");
84 free(got);
85 return PM3_ETIMEOUT;
89 PrintAndLogEx(NORMAL, "recorded activity (TraceLen = %d bytes):");
90 PrintAndLogEx(NORMAL, " ETU :nbits: who bytes");
91 PrintAndLogEx(NORMAL, "---------+-----+----+-----------");
93 int i = 0;
94 int prev = -1;
95 int len = strlen(Cmd);
97 char filename[FILE_PATH_SIZE] = { 0x00 };
98 FILE *f = NULL;
100 if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
102 memcpy(filename, Cmd, len);
104 if (strlen(filename) > 0) {
105 f = fopen(filename, "wb");
106 if (!f) {
107 PrintAndLogEx(ERR, "Error: Could not open file [%s]", filename);
108 return PM3_EFILE;
112 for (;;) {
114 if (i >= traceLen) { break; }
116 bool isResponse;
117 int timestamp = *((uint32_t *)(got + i));
118 if (timestamp & 0x80000000) {
119 timestamp &= 0x7fffffff;
120 isResponse = 1;
121 } else {
122 isResponse = 0;
125 int parityBits = *((uint32_t *)(got + i + 4));
126 // 4 bytes of additional information...
127 // maximum of 32 additional parity bit information
129 // TODO:
130 // at each quarter bit period we can send power level (16 levels)
131 // or each half bit period in 256 levels.
133 int bits = got[i + 8];
134 int len = nbytes(got[i + 8]);
136 if (len > 100) {
137 break;
139 if (i + len > traceLen) { break;}
141 uint8_t *frame = (got + i + 9);
143 // Break and stick with current result if buffer was not completely full
144 if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }
146 char line[1000] = "";
147 int j;
148 for (j = 0; j < len; j++) {
150 //if((parityBits >> (len - j - 1)) & 0x01) {
151 if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) {
152 sprintf(line + (j * 4), "%02x! ", frame[j]);
153 } else {
154 sprintf(line + (j * 4), "%02x ", frame[j]);
158 PrintAndLogEx(NORMAL, " +%7d: %3d: %s %s",
159 (prev < 0 ? 0 : (timestamp - prev)),
160 bits,
161 (isResponse ? "TAG" : " "),
162 line);
164 if (f) {
165 fprintf(f, " +%7d: %3d: %s %s\n",
166 (prev < 0 ? 0 : (timestamp - prev)),
167 bits,
168 (isResponse ? "TAG" : " "),
169 line);
172 prev = timestamp;
173 i += (len + 9);
176 if (f) {
177 fclose(f);
178 PrintAndLogEx(NORMAL, "Recorded activity successfully written to file: %s", filename);
181 free(got);
182 return PM3_SUCCES;
186 static int CmdLFHitagSniff(const char *Cmd) {
187 CLIParserContext *ctx;
188 CLIParserInit(&ctx, "lf hitag sniff",
189 "Sniff traffic between Hitag reader and tag.\n"
190 "Use " _YELLOW_("`lf hitag list`")" to view collected data.",
191 "lf hitag sniff"
194 void *argtable[] = {
195 arg_param_begin,
196 arg_param_end
198 CLIExecWithReturn(ctx, Cmd, argtable, true);
199 CLIParserFree(ctx);
201 clearCommandBuffer();
202 SendCommandNG(CMD_LF_HITAG_SNIFF, NULL, 0);
203 PrintAndLogEx(HINT, "HINT: Try " _YELLOW_("`lf hitag list`")" to view collected data");
204 return PM3_SUCCESS;
208 // eload , to be implemented
209 static int CmdLFHitagEload(const char *Cmd) {
210 CLIParserContext *ctx;
211 CLIParserInit(&ctx, "lf hitag eload",
212 "Loads hitag tag dump into emulator memory on device",
213 "lf hitag eload -2 -f lf-hitag-11223344-dump.bin\n");
215 void *argtable[] = {
216 arg_param_begin,
217 arg_str1("f", "file", "<filename>", "filename of dump"),
218 arg_lit0("1", NULL, "Card type Hitag1"),
219 arg_lit0("2", NULL, "Card type Hitag2"),
220 arg_lit0("s", NULL, "Card type HitagS"),
221 arg_lit0("m", NULL, "Card type HitagM"),
222 arg_param_end
224 CLIExecWithReturn(ctx, Cmd, argtable, false);
226 int fnlen = 0;
227 char filename[FILE_PATH_SIZE] = {0};
228 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
230 bool use_ht1 = arg_get_lit(ctx, 2);
231 bool use_ht2 = arg_get_lit(ctx, 3);
232 bool use_hts = arg_get_lit(ctx, 4);
233 bool use_htm = arg_get_lit(ctx, 5);
234 CLIParserFree(ctx);
236 uint8_t n = (use_ht1 + use_ht2 + use_hts + use_htm);
237 if (n != 1) {
238 PrintAndLogEx(ERR, "error, only specify one Hitag type");
239 return PM3_EINVARG;
242 DumpFileType_t dftype = getfiletype(filename);
243 size_t dumplen = 0;
244 uint8_t *dump = NULL;
245 int res = 0;
246 switch (dftype) {
247 case BIN: {
248 res = loadFile_safe(filename, ".bin", (void **)&dump, &dumplen);
249 break;
251 case EML: {
252 res = loadFileEML_safe(filename, (void **)&dump, &dumplen);
253 break;
255 case JSON: {
256 dumplen = 4 * 64;
257 dump = calloc(dumplen, sizeof(uint8_t));
258 if (dump == NULL) {
259 PrintAndLogEx(ERR, "error, cannot allocate memory");
260 return PM3_EMALLOC;
262 res = loadFileJSON(filename, (void *)dump, dumplen, &dumplen, NULL);
263 break;
265 case DICTIONARY: {
266 PrintAndLogEx(ERR, "error, only BIN/JSON/EML formats allowed");
267 return PM3_EINVARG;
271 if (res != PM3_SUCCESS) {
272 PrintAndLogEx(ERR, "error, something went wrong when loading file");
273 free(dump);
274 return PM3_EFILE;
277 // check dump len..
278 if (dumplen == 48 || dumplen == 4 * 64) {
280 lf_hitag_t *payload = calloc(1, sizeof(lf_hitag_t) + dumplen);
282 if (use_ht1)
283 payload->type = 1;
284 if (use_ht2)
285 payload->type = 2;
286 if (use_hts)
287 payload->type = 3;
288 if (use_htm)
289 payload->type = 4;
291 payload->len = dumplen;
292 memcpy(payload->data, dump, dumplen);
294 clearCommandBuffer();
295 SendCommandNG(CMD_LF_HITAG_ELOAD, (uint8_t *)payload, 3 + dumplen);
296 free(payload);
297 } else {
298 PrintAndLogEx(ERR, "error, wrong dump file size. got %zu", dumplen);
301 free(dump);
302 return PM3_SUCCESS;
305 static int CmdLFHitagSim(const char *Cmd) {
306 CLIParserContext *ctx;
307 CLIParserInit(&ctx, "lf hitag sim",
308 "Simulate Hitag2 / HitagS transponder\n"
309 "You need to `lf hitag eload` first",
310 "lf hitag sim -2"
313 void *argtable[] = {
314 arg_param_begin,
315 arg_lit0("1", NULL, "simulate Hitag1"),
316 arg_lit0("2", NULL, "simulate Hitag2"),
317 arg_lit0("s", NULL, "simulate HitagS"),
318 arg_param_end
320 CLIExecWithReturn(ctx, Cmd, argtable, true);
322 bool use_ht1 = arg_get_lit(ctx, 1);
323 bool use_ht2 = arg_get_lit(ctx, 2);
324 bool use_hts = arg_get_lit(ctx, 3);
325 CLIParserFree(ctx);
327 if ((use_ht1 + use_ht2 + use_hts) > 1) {
328 PrintAndLogEx(ERR, "error, Only specify one Hitag type");
329 return PM3_EINVARG;
332 uint16_t cmd = CMD_LF_HITAG_SIMULATE;
333 // if (use_ht1)
334 // cmd = CMD_LF_HITAG1_SIMULATE;
336 if (use_hts)
337 cmd = CMD_LF_HITAGS_SIMULATE;
339 clearCommandBuffer();
340 SendCommandMIX(cmd, 0, 0, 0, NULL, 0);
341 return PM3_SUCCESS;
344 static void printHitagConfiguration(uint8_t config) {
346 char msg[100];
347 memset(msg, 0, sizeof(msg));
349 char bits[9];
350 char *bs = bits;
351 for (uint8_t i = 0 ; i < 8 ; i++) {
352 snprintf(bs, sizeof(bits) - i, "%1d", (config >> (7 - i)) & 1);
353 bs++;
356 PrintAndLogEx(INFO, "\n\nHitag2 tag information ");
357 PrintAndLogEx(INFO, "------------------------------------");
359 //configuration byte
360 PrintAndLogEx(SUCCESS, "Config byte : 0x%02X [ %s ]", config, bits);
362 // encoding
363 strcat(msg, "Encoding : ");
364 if (config & 0x1) {
365 strcat(msg + strlen(msg), _YELLOW_("Biphase"));
366 } else {
367 strcat(msg + strlen(msg), _YELLOW_("Manchester"));
369 PrintAndLogEx(SUCCESS, "%s", msg);
370 memset(msg, 0, sizeof(msg));
372 // version
373 strcat(msg, "Coding in HITAG 2 operation: %s");
374 uint8_t foo = (config & 0x6) >> 1;
375 switch (foo) {
376 case 0:
377 PrintAndLogEx(SUCCESS, "Version : public mode B, Coding: biphase");
378 PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
379 break;
380 case 1:
381 PrintAndLogEx(SUCCESS, "Version : public mode A, Coding: manchester");
382 PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
383 break;
384 case 2:
385 PrintAndLogEx(SUCCESS, "Version : public mode C, Coding: biphase");
386 PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
387 break;
388 case 3:
389 PrintAndLogEx(SUCCESS, "Version : Hitag2");
390 PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
391 break;
393 memset(msg, 0, sizeof(msg));
395 // mode
396 strcat(msg, "Tag is in : ");
397 if (config & 0x8) {
398 strcat(msg + strlen(msg), _YELLOW_("Crypto mode"));
399 } else {
400 strcat(msg + strlen(msg), _YELLOW_("Password mode"));
402 PrintAndLogEx(SUCCESS, "%s", msg);
403 memset(msg, 0, sizeof(msg));
405 // page access
406 strcat(msg, "Page 6,7 : ");
407 if (config & 0x10) {
408 strcat(msg + strlen(msg), "read only");
409 } else {
410 strcat(msg + strlen(msg), _GREEN_("RW"));
412 PrintAndLogEx(SUCCESS, "%s", msg);
413 memset(msg, 0, sizeof(msg));
415 // page access
416 strcat(msg, "Page 4,5 : ");
417 if (config & 0x20) {
418 strcat(msg + strlen(msg), "read only");
419 } else {
420 strcat(msg + strlen(msg), _GREEN_("RW"));
422 PrintAndLogEx(SUCCESS, "%s", msg);
423 memset(msg, 0, sizeof(msg));
425 // OTP
426 strcat(msg, "Page 3 : ");
427 if (config & 0x40) {
428 strcat(msg + strlen(msg), "read only. Configuration byte and password tag " _RED_("FIXED / IRREVERSIBLE"));
429 } else {
430 strcat(msg + strlen(msg), _GREEN_("RW"));
432 PrintAndLogEx(SUCCESS, "%s", msg);
433 memset(msg, 0, sizeof(msg));
435 // OTP
436 if (config & 0x80) {
437 strcat(msg, "Page 1 : " _RED_("locked") "\n");
439 strcat(msg + strlen(msg), "Page 2 : ");
440 if (config & 0x8) {
441 strcat(msg + strlen(msg), _RED_("locked"));
442 } else {
443 strcat(msg + strlen(msg), "read only");
445 } else {
446 strcat(msg, "Page 1,2 : " _GREEN_("RW"));
448 PrintAndLogEx(SUCCESS, "%s", msg);
449 PrintAndLogEx(INFO, "------------------------------------");
452 static bool getHitagUid(uint32_t *uid) {
453 hitag_data htd;
454 memset(&htd, 0, sizeof(htd));
455 clearCommandBuffer();
456 SendCommandMIX(CMD_LF_HITAG_READER, RHT2F_UID_ONLY, 0, 0, &htd, sizeof(htd));
457 PacketResponseNG resp;
458 if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
459 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
460 return false;
463 if (resp.oldarg[0] == false) {
464 PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID");
465 return false;
468 if (uid)
469 *uid = bytes_to_num(resp.data.asBytes, 4);
471 return true;
474 static int CmdLFHitagInfo(const char *Cmd) {
475 CLIParserContext *ctx;
476 CLIParserInit(&ctx, "lf hitag info",
477 "Sniff traffic between Hitag reader and tag.",
478 "lf hitag info"
481 void *argtable[] = {
482 arg_param_begin,
483 arg_param_end
485 CLIExecWithReturn(ctx, Cmd, argtable, true);
486 CLIParserFree(ctx);
488 // read UID
489 uint32_t uid = 0;
490 if (getHitagUid(&uid) == false)
491 return PM3_ESOFT;
493 PrintAndLogEx(NORMAL, "");
494 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
495 PrintAndLogEx(INFO, "-------------------------------------------------------------");
496 PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%08X"), uid);
497 PrintAndLogEx(SUCCESS, " TYPE: " _GREEN_("%s"), getHitagTypeStr(uid));
499 // how to detemine Hitag types?
500 // read block3, get configuration byte.
502 // common configurations.
503 // printHitagConfiguration(0x06);
504 //printHitagConfiguration( 0x0E );
505 //printHitagConfiguration( 0x02 );
506 //printHitagConfiguration( 0x00 );
507 //printHitagConfiguration( 0x04 );
508 PrintAndLogEx(INFO, "-------------------------------------------------------------");
509 return PM3_SUCCESS;
512 // TODO: iceman
513 // Hitag2 reader, problem is that this command mixes up stuff. So 26 give uid. 21 etc will also give you a memory dump !?
515 static int CmdLFHitagReader(const char *Cmd) {
517 CLIParserContext *ctx;
518 CLIParserInit(&ctx, "lf hitag reader",
519 "Act like a Hitag Reader",
520 "Hitag S\n"
521 " lf hitag reader --01 --nrar 0102030411223344\n"
522 " lf hitag reader --02 -k 4F4E4D494B52\n"
523 "Hitag 2\n"
524 " lf hitag reader --21 -k 4D494B52\n"
525 " lf hitag reader --22 --nrar 0102030411223344\n"
526 " lf hitag reader --23 -k 4F4E4D494B52\n"
527 " lf hitag reader --26\n"
530 void *argtable[] = {
531 arg_param_begin,
532 arg_lit0(NULL, "01", "HitagS, read all pages, challenge mode"),
533 arg_lit0(NULL, "02", "HitagS, read all pages, crypto mode. Set key=0 for no auth"),
534 arg_lit0(NULL, "21", "Hitag2, read all pages, password mode. def 4D494B52 (MIKR)"),
535 arg_lit0(NULL, "22", "Hitag2, read all pages, challenge mode"),
536 arg_lit0(NULL, "23", "Hitag2, read all pages, crypto mode. Key ISK high + ISK low. def 4F4E4D494B52 (ONMIKR)"),
537 arg_lit0(NULL, "25", "Hitag2, test recorded authentications (replay?)"),
538 arg_lit0(NULL, "26", "Hitag2, read UID"),
539 arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
540 arg_str0(NULL, "nrar", "<hex>", "nonce / answer reader, 8 hex bytes"),
541 arg_param_end
543 CLIExecWithReturn(ctx, Cmd, argtable, false);
545 // Hitag S
546 bool s01 = arg_get_lit(ctx, 1);
547 bool s02 = arg_get_lit(ctx, 2);
549 // Hitag 2
550 bool h21 = arg_get_lit(ctx, 3);
551 bool h22 = arg_get_lit(ctx, 4);
552 bool h23 = arg_get_lit(ctx, 5);
553 bool h25 = arg_get_lit(ctx, 6);
554 bool h26 = arg_get_lit(ctx, 7);
556 uint8_t key[6];
557 int keylen = 0;
558 int res = CLIParamHexToBuf(arg_get_str(ctx, 8), key, sizeof(key), &keylen);
559 if (res != 0) {
560 CLIParserFree(ctx);
561 return PM3_EINVARG;
564 uint8_t nrar[8];
565 int nalen = 0;
566 res = CLIParamHexToBuf(arg_get_str(ctx, 9), nrar, sizeof(nrar), &nalen);
567 CLIParserFree(ctx);
568 if (res != 0) {
569 return PM3_EINVARG;
572 // sanity checks
573 if (keylen != 0 && keylen != 4) {
574 PrintAndLogEx(WARNING, "Wrong KEY len expected 0 or 4, got %d", keylen);
575 return PM3_EINVARG;
578 if (nalen != 0 && nalen != 6) {
579 PrintAndLogEx(WARNING, "Wrong NR/AR len expected 0 or 6, got %d", nalen);
580 return PM3_EINVARG;
583 uint8_t foo = (s01 + s02 + h21 + h22 + h23 + h25 + h26);
584 if (foo > 1) {
585 PrintAndLogEx(WARNING, "Only specify one HITAG reader cmd");
586 return PM3_EINVARG;
587 } else if (foo == 0) {
588 PrintAndLogEx(WARNING, "Specify one HITAG reader cms");
589 return PM3_EINVARG;
592 hitag_function htf;
593 hitag_data htd;
594 uint16_t cmd = CMD_LF_HITAG_READER;
595 if (s01) {
596 cmd = CMD_LF_HITAGS_READ;
597 htf = RHTSF_CHALLENGE;
598 memcpy(htd.auth.NrAr, nrar, sizeof(nrar));
600 if (s02) {
601 cmd = CMD_LF_HITAGS_READ;
602 htf = RHTSF_KEY;
603 memcpy(htd.crypto.key, key, sizeof(key));
605 if (h21) {
606 htf = RHT2F_PASSWORD;
607 memcpy(htd.pwd.password, key, 4);
609 if (h22) {
610 htf = RHT2F_AUTHENTICATE;
611 memcpy(htd.auth.NrAr, nrar, sizeof(nrar));
613 if (h23) {
614 htf = RHT2F_CRYPTO;
615 memcpy(htd.crypto.key, key, sizeof(key));
617 if (h25) {
618 htf = RHT2F_TEST_AUTH_ATTEMPTS;
620 if (h26) {
621 htf = RHT2F_UID_ONLY;
624 clearCommandBuffer();
625 SendCommandMIX(cmd, htf, 0, 0, &htd, sizeof(htd));
626 PacketResponseNG resp;
627 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
628 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
629 return PM3_ETIMEOUT;
632 if (resp.oldarg[0] == false) {
633 PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
634 return PM3_ESOFT;
637 uint32_t id = bytes_to_num(resp.data.asBytes, 4);
638 uint8_t *data = resp.data.asBytes;
639 PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id);
641 if (htf != RHT2F_UID_ONLY) {
643 // block3, 1 byte
644 printHitagConfiguration(data[4 * 3]);
646 return PM3_SUCCESS;
649 static int CmdLFHitagCheckChallenges(const char *Cmd) {
651 CLIParserContext *ctx;
652 CLIParserInit(&ctx, "lf hitag cc",
653 "Check challenges, load a file with saved hitag crypto challenges and test them all.\n"
654 "The file should be 8 * 60 bytes long, the file extension defaults to " _YELLOW_("`.cc`") " ",
655 "lf hitag cc -f my_hitag_challenges"
658 void *argtable[] = {
659 arg_param_begin,
660 arg_str0("f", "filename", "<fn w/o ext>", "filename to load from"),
661 arg_param_end
663 CLIExecWithReturn(ctx, Cmd, argtable, true);
665 int fnlen = 0;
666 char filename[FILE_PATH_SIZE] = {0};
667 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
669 CLIParserFree(ctx);
671 clearCommandBuffer();
673 if (fnlen > 0) {
674 uint8_t *data = NULL;
675 size_t datalen = 0;
676 int res = loadFile_safe(filename, ".cc", (void **)&data, &datalen);
677 if (res == PM3_SUCCESS) {
678 if (datalen == (8 * 60)) {
679 SendCommandOLD(CMD_LF_HITAGS_TEST_TRACES, 1, 0, 0, data, datalen);
680 } else {
681 PrintAndLogEx(ERR, "Error, file length mismatch. Expected %d, got %zu", 8 * 60, datalen);
684 if (data) {
685 free(data);
687 } else {
688 SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0);
691 return PM3_SUCCESS;
694 static int CmdLFHitagWriter(const char *Cmd) {
695 CLIParserContext *ctx;
696 CLIParserInit(&ctx, "lf hitag writer",
697 "Act like a Hitag writer"
698 "In password mode the default key is 4D494B52 (MIKR)\n"
699 "In crypto mode the default key is 4F4E4D494B52 (ONMIKR) format: ISK high + ISK low.",
700 "Hitag S\n"
701 " lf hitag writer --03 --nrar 0102030411223344 -p 3 -d 01020304\n"
702 " lf hitag writer --04 -k 4F4E4D494B52 -p 3 -d 01020304\n"
703 "Hitag 2\n"
704 " lf hitag writer --24 -k 4F4E4D494B52 -p 3 -d 01020304\n"
705 " lf hitag writer --27 -k 4D494B52 -p 3 -d 01020304\n"
708 void *argtable[] = {
709 arg_param_begin,
710 arg_lit0(NULL, "03", "HitagS, write page, challenge mode"),
711 arg_lit0(NULL, "04", "HitagS, write page, crypto mode. Set key=0 for no auth"),
712 arg_lit0(NULL, "24", "Hitag2, write page, crypto mode."),
713 arg_lit0(NULL, "27", "Hitag2, write page, password mode"),
714 arg_int1("p", "page", "<dec>", "page address to write to"),
715 arg_str0("d", "data", "<hex>", "data, 4 hex bytes"),
716 arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
717 arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
718 arg_param_end
720 CLIExecWithReturn(ctx, Cmd, argtable, false);
722 // Hitag S
723 bool s03 = arg_get_lit(ctx, 1);
724 bool s04 = arg_get_lit(ctx, 2);
726 // Hitag 2
727 bool h24 = arg_get_lit(ctx, 3);
728 bool h27 = arg_get_lit(ctx, 4);
730 uint32_t page = arg_get_u32_def(ctx, 5, 0);
732 uint8_t data[4];
733 int dlen = 0;
734 int res = CLIParamHexToBuf(arg_get_str(ctx, 6), data, sizeof(data), &dlen);
735 if (res != 0) {
736 CLIParserFree(ctx);
737 return PM3_EINVARG;
740 uint8_t key[6];
741 int keylen = 0;
742 res = CLIParamHexToBuf(arg_get_str(ctx, 7), key, sizeof(key), &keylen);
743 if (res != 0) {
744 CLIParserFree(ctx);
745 return PM3_EINVARG;
748 uint8_t nrar[8];
749 int nalen = 0;
750 res = CLIParamHexToBuf(arg_get_str(ctx, 8), nrar, sizeof(nrar), &nalen);
752 CLIParserFree(ctx);
754 if (res != 0) {
755 return PM3_EINVARG;
758 // sanity checks
759 if (dlen != sizeof(data)) {
760 PrintAndLogEx(WARNING, "Wrong DATA len expected 4, got %d", dlen);
761 return PM3_EINVARG;
764 if (keylen != 0 && keylen != 6 && keylen != 4) {
765 PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen);
766 return PM3_EINVARG;
769 if (nalen != 0 && nalen != 8) {
770 PrintAndLogEx(WARNING, "Wrong NR/AR len expected 0 or 8, got %d", nalen);
771 return PM3_EINVARG;
774 uint8_t foo = (s03 + s04 + h24 + h27);
775 if (foo > 1) {
776 PrintAndLogEx(WARNING, "Only specify one HITAG write cmd");
777 return PM3_EINVARG;
778 } else if (foo == 0) {
779 PrintAndLogEx(WARNING, "Specify one HITAG write cmd");
780 return PM3_EINVARG;
783 hitag_function htf;
784 hitag_data htd;
785 if (s03) {
786 htf = WHTSF_CHALLENGE;
787 memcpy(htd.auth.NrAr, nrar, sizeof(nrar));
788 memcpy(htd.auth.data, data, sizeof(data));
790 if (s04) {
791 htf = WHTSF_KEY;
792 memcpy(htd.crypto.key, key, sizeof(key));
793 memcpy(htd.crypto.data, data, sizeof(data));
795 if (h24) {
796 htf = WHT2F_CRYPTO;
797 memcpy(htd.pwd.password, key, 4);
798 memcpy(htd.crypto.data, data, sizeof(data));
800 if (h27) {
801 htf = WHT2F_PASSWORD;
802 memcpy(htd.pwd.password, key, 4);
803 memcpy(htd.crypto.data, data, sizeof(data));
806 clearCommandBuffer();
807 SendCommandMIX(CMD_LF_HITAGS_WRITE, htf, 0, page, &htd, sizeof(htd));
808 PacketResponseNG resp;
809 if (WaitForResponseTimeout(CMD_ACK, &resp, 4000) == false) {
810 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
811 return PM3_ETIMEOUT;
814 if (resp.oldarg[0] == false) {
815 PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed");
816 return PM3_ESOFT;
818 return PM3_SUCCESS;
821 static int CmdLFHitag2Dump(const char *Cmd) {
823 CLIParserContext *ctx;
824 CLIParserInit(&ctx, "lf hitag dump",
825 "Read all card memory and save to file"
826 "In password mode the default key is 4D494B52 (MIKR)\n"
827 "In crypto mode the default key is 4F4E4D494B52 (ONMIKR) format: ISK high + ISK low.",
828 "lf hitag dump -k 4F4E4D494B52\n"
829 "lf hitag dump -k 4D494B52\n"
832 void *argtable[] = {
833 arg_param_begin,
834 arg_str0("f", "file", "<fn>", "file name"),
835 arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
836 arg_str0(NULL, "nrar", "<hex>", "nonce / answer reader, 8 hex bytes"),
837 arg_param_end
839 CLIExecWithReturn(ctx, Cmd, argtable, false);
840 uint8_t filename[FILE_PATH_SIZE] = {0};
841 int fnlen = 0;
842 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), filename, sizeof(filename), &fnlen);
843 if (res != 0) {
844 CLIParserFree(ctx);
845 return PM3_EINVARG;
848 uint8_t key[6];
849 int keylen = 0;
850 res = CLIParamHexToBuf(arg_get_str(ctx, 2), key, sizeof(key), &keylen);
851 if (res != 0) {
852 CLIParserFree(ctx);
853 return PM3_EINVARG;
856 uint8_t nrar[8];
857 int nalen = 0;
858 res = CLIParamHexToBuf(arg_get_str(ctx, 3), nrar, sizeof(nrar), &nalen);
859 CLIParserFree(ctx);
860 if (res != 0) {
861 return PM3_EINVARG;
864 PrintAndLogEx(WARNING, "to be implememted...");
867 PrintAndLogEx(SUCCESS, "Dumping tag memory...");
869 clearCommandBuffer();
870 //SendCommandNG(CMD_LF_HITAG_DUMP, &htd, sizeof(htd));
871 PacketResponseNG resp;
872 uint8_t *data = resp.data.asBytes;
873 if (fnlen < 1) {
874 char *fptr = filename;
875 fptr += sprintf(fptr, "lf-hitag-");
876 FillFileNameByUID(fptr, data, "-dump", 4);
879 saveFile(filename, ".bin", data, 48);
880 saveFileEML(filename, data, 48, 4);
881 saveFileJSON(filename, jsfHitag, data, 48, NULL);
883 return PM3_SUCCESS;
887 // Annotate HITAG protocol
888 void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
891 void annotateHitag2(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
893 // iceman: live decrypt of trace?
894 if (is_response) {
897 uint8_t cmdbits = (cmd[0] & 0xC0) >> 6;
899 if (cmdsize == 1) {
900 if (cmdbits == HITAG2_START_AUTH) {
901 snprintf(exp, size, "START AUTH");
902 return;
904 if (cmdbits == HITAG2_HALT) {
905 snprintf(exp, size, "HALT");
906 return;
910 if (cmdsize == 3) {
911 if (cmdbits == HITAG2_START_AUTH) {
912 // C 1 C 0
913 // 1100 0 00 1 1100 000
914 uint8_t page = (cmd[0] & 0x38) >> 3;
915 uint8_t inv_page = ((cmd[0] & 0x1) << 2) | ((cmd[1] & 0xC0) >> 6);
916 snprintf(exp, size, "READ page(%x) %x", page, inv_page);
917 return;
919 if (cmdbits == HITAG2_WRITE_PAGE) {
920 uint8_t page = (cmd[0] & 0x38) >> 3;
921 uint8_t inv_page = ((cmd[0] & 0x1) << 2) | ((cmd[1] & 0xC0) >> 6);
922 snprintf(exp, size, "WRITE page(%x) %x", page, inv_page);
923 return;
927 if (cmdsize == 9) {
928 snprintf(exp, size, "Nr Ar Is response");
929 return;
931 } else {
933 if (cmdsize == 9) {
934 snprintf(exp, size, "Nr Ar");
935 return;
942 void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
945 static command_t CommandTable[] = {
946 {"help", CmdHelp, AlwaysAvailable, "This help"},
947 {"eload", CmdLFHitagEload, IfPm3Hitag, "Load Hitag dump file into emulator memory"},
948 {"list", CmdLFHitagList, AlwaysAvailable, "List Hitag trace history"},
949 {"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information"},
950 {"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag reader"},
951 {"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder"},
952 {"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
953 {"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag writer"},
954 {"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag"},
955 {"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges"},
956 { NULL, NULL, 0, NULL }
959 static int CmdHelp(const char *Cmd) {
960 (void)Cmd; // Cmd is not used so far
961 CmdsHelp(CommandTable);
962 return PM3_SUCCESS;
965 int CmdLFHitag(const char *Cmd) {
966 clearCommandBuffer();
967 return CmdsParse(CommandTable, Cmd);
970 int readHitagUid(void) {
971 return (CmdLFHitagReader("--26") == PM3_SUCCESS);