textual
[RRG-proxmark3.git] / client / src / cmdlfhitag.c
blob232acf0680a18d5bc65831fec7a61a243bddda55
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 -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, "simulate Hitag1"),
219 arg_lit0("2", NULL, "simulate Hitag2"),
220 arg_lit0("s", NULL, "simulate HitagS"),
221 arg_param_end
223 CLIExecWithReturn(ctx, Cmd, argtable, false);
225 int fnlen = 0;
226 char filename[FILE_PATH_SIZE] = {0};
227 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
229 bool use_ht1 = arg_get_lit(ctx, 2);
230 bool use_ht2 = arg_get_lit(ctx, 3);
231 bool use_hts = arg_get_lit(ctx, 4);
232 CLIParserFree(ctx);
234 uint8_t n = (use_ht1 + use_ht2 + use_hts);
235 if (n != 1) {
236 PrintAndLogEx(ERR, "error, only specify one Hitag type");
237 return PM3_EINVARG;
240 DumpFileType_t dftype = getfiletype(filename);
241 size_t dumplen = 0;
242 uint8_t *dump = NULL;
243 int res = 0;
244 switch (dftype) {
245 case BIN: {
246 res = loadFile_safe(filename, ".bin", (void **)&dump, &dumplen);
247 break;
249 case EML: {
250 res = loadFileEML_safe(filename, (void **)&dump, &dumplen);
251 break;
253 case JSON: {
254 dumplen = 4 * 64;
255 dump = calloc(dumplen, sizeof(uint8_t));
256 if (dump == NULL) {
257 PrintAndLogEx(ERR, "error, cannot allocate memory");
258 return PM3_EMALLOC;
260 res = loadFileJSON(filename, (void *)dump, dumplen, &dumplen, NULL);
261 break;
263 case DICTIONARY: {
264 PrintAndLogEx(ERR, "error, only BIN/JSON/EML formats allowed");
265 return PM3_EINVARG;
269 if (res != PM3_SUCCESS) {
270 PrintAndLogEx(ERR, "error, something went wrong when loading file");
271 free(dump);
272 return PM3_EFILE;
275 // check dump len..
276 if (dumplen == 48 || dumplen == 4 * 64) {
277 struct {
278 uint16_t len;
279 uint8_t *data;
280 } PACKED payload;
281 payload.len = dumplen;
282 memcpy(payload.data, dump, dumplen);
284 clearCommandBuffer();
285 SendCommandNG(CMD_LF_HITAG_ELOAD, (uint8_t *)&payload, 2 + dumplen);
286 } else {
287 PrintAndLogEx(ERR, "error, wrong dump file size. got %zu", dumplen);
290 free(dump);
291 return PM3_SUCCESS;
294 static int CmdLFHitagSim(const char *Cmd) {
295 CLIParserContext *ctx;
296 CLIParserInit(&ctx, "lf hitag sim",
297 "Simulate Hitag2 / HitagS transponder\n"
298 "You need to `lf hitag eload` first",
299 "lf hitag sim -2"
302 void *argtable[] = {
303 arg_param_begin,
304 arg_lit0("1", NULL, "simulate Hitag1"),
305 arg_lit0("2", NULL, "simulate Hitag2"),
306 arg_lit0("s", NULL, "simulate HitagS"),
307 arg_param_end
309 CLIExecWithReturn(ctx, Cmd, argtable, true);
311 bool use_ht1 = arg_get_lit(ctx, 1);
312 bool use_ht2 = arg_get_lit(ctx, 2);
313 bool use_hts = arg_get_lit(ctx, 3);
314 CLIParserFree(ctx);
316 if ((use_ht1 + use_ht2 + use_hts) > 1) {
317 PrintAndLogEx(ERR, "error, Only specify one Hitag type");
318 return PM3_EINVARG;
321 uint16_t cmd = CMD_LF_HITAG_SIMULATE;
322 // if (use_ht1)
323 // cmd = CMD_LF_HITAG1_SIMULATE;
325 if (use_hts)
326 cmd = CMD_LF_HITAGS_SIMULATE;
328 clearCommandBuffer();
329 SendCommandMIX(cmd, 0, 0, 0, NULL, 0);
330 return PM3_SUCCESS;
333 static void printHitagConfiguration(uint8_t config) {
335 char msg[100];
336 memset(msg, 0, sizeof(msg));
338 char bits[9];
339 char *bs = bits;
340 for (uint8_t i = 0 ; i < 8 ; i++) {
341 snprintf(bs, sizeof(bits) - i, "%1d", (config >> (7 - i)) & 1);
342 bs++;
345 PrintAndLogEx(INFO, "\n\nHitag2 tag information ");
346 PrintAndLogEx(INFO, "------------------------------------");
348 //configuration byte
349 PrintAndLogEx(SUCCESS, "Config byte : 0x%02X [ %s ]", config, bits);
351 // encoding
352 strcat(msg, "Encoding : ");
353 if (config & 0x1) {
354 strcat(msg + strlen(msg), _YELLOW_("Biphase"));
355 } else {
356 strcat(msg + strlen(msg), _YELLOW_("Manchester"));
358 PrintAndLogEx(SUCCESS, "%s", msg);
359 memset(msg, 0, sizeof(msg));
361 // version
362 strcat(msg, "Coding in HITAG 2 operation: %s");
363 uint8_t foo = (config & 0x6) >> 1;
364 switch (foo) {
365 case 0:
366 PrintAndLogEx(SUCCESS, "Version : public mode B, Coding: biphase");
367 PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
368 break;
369 case 1:
370 PrintAndLogEx(SUCCESS, "Version : public mode A, Coding: manchester");
371 PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
372 break;
373 case 2:
374 PrintAndLogEx(SUCCESS, "Version : public mode C, Coding: biphase");
375 PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
376 break;
377 case 3:
378 PrintAndLogEx(SUCCESS, "Version : Hitag2");
379 PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
380 break;
382 memset(msg, 0, sizeof(msg));
384 // mode
385 strcat(msg, "Tag is in : ");
386 if (config & 0x8) {
387 strcat(msg + strlen(msg), _YELLOW_("Crypto mode"));
388 } else {
389 strcat(msg + strlen(msg), _YELLOW_("Password mode"));
391 PrintAndLogEx(SUCCESS, "%s", msg);
392 memset(msg, 0, sizeof(msg));
394 // page access
395 strcat(msg, "Page 6,7 : ");
396 if (config & 0x10) {
397 strcat(msg + strlen(msg), "read only");
398 } else {
399 strcat(msg + strlen(msg), _GREEN_("RW"));
401 PrintAndLogEx(SUCCESS, "%s", msg);
402 memset(msg, 0, sizeof(msg));
404 // page access
405 strcat(msg, "Page 4,5 : ");
406 if (config & 0x20) {
407 strcat(msg + strlen(msg), "read only");
408 } else {
409 strcat(msg + strlen(msg), _GREEN_("RW"));
411 PrintAndLogEx(SUCCESS, "%s", msg);
412 memset(msg, 0, sizeof(msg));
414 // OTP
415 strcat(msg, "Page 3 : ");
416 if (config & 0x40) {
417 strcat(msg + strlen(msg), "read only. Configuration byte and password tag " _RED_("FIXED / IRREVERSIBLE"));
418 } else {
419 strcat(msg + strlen(msg), _GREEN_("RW"));
421 PrintAndLogEx(SUCCESS, "%s", msg);
422 memset(msg, 0, sizeof(msg));
424 // OTP
425 if (config & 0x80) {
426 strcat(msg, "Page 1 : " _RED_("locked") "\n");
428 strcat(msg + strlen(msg), "Page 2 : ");
429 if (config & 0x8) {
430 strcat(msg + strlen(msg), _RED_("locked"));
431 } else {
432 strcat(msg + strlen(msg), "read only");
434 } else {
435 strcat(msg, "Page 1,2 : " _GREEN_("RW"));
437 PrintAndLogEx(SUCCESS, "%s", msg);
438 PrintAndLogEx(INFO, "------------------------------------");
441 static bool getHitagUid(uint32_t *uid) {
442 hitag_data htd;
443 memset(&htd, 0, sizeof(htd));
444 clearCommandBuffer();
445 SendCommandMIX(CMD_LF_HITAG_READER, RHT2F_UID_ONLY, 0, 0, &htd, sizeof(htd));
446 PacketResponseNG resp;
447 if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
448 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
449 return false;
452 if (resp.oldarg[0] == false) {
453 PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID");
454 return false;
457 if (uid)
458 *uid = bytes_to_num(resp.data.asBytes, 4);
460 return true;
463 static int CmdLFHitagInfo(const char *Cmd) {
464 CLIParserContext *ctx;
465 CLIParserInit(&ctx, "lf hitag info",
466 "Sniff traffic between Hitag reader and tag.",
467 "lf hitag info"
470 void *argtable[] = {
471 arg_param_begin,
472 arg_param_end
474 CLIExecWithReturn(ctx, Cmd, argtable, true);
475 CLIParserFree(ctx);
477 // read UID
478 uint32_t uid = 0;
479 if (getHitagUid(&uid) == false)
480 return PM3_ESOFT;
482 PrintAndLogEx(NORMAL, "");
483 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
484 PrintAndLogEx(INFO, "-------------------------------------------------------------");
485 PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%08X"), uid);
486 PrintAndLogEx(SUCCESS, " TYPE: " _GREEN_("%s"), getHitagTypeStr(uid));
488 // how to detemine Hitag types?
489 // read block3, get configuration byte.
491 // common configurations.
492 // printHitagConfiguration(0x06);
493 //printHitagConfiguration( 0x0E );
494 //printHitagConfiguration( 0x02 );
495 //printHitagConfiguration( 0x00 );
496 //printHitagConfiguration( 0x04 );
497 PrintAndLogEx(INFO, "-------------------------------------------------------------");
498 return PM3_SUCCESS;
501 // TODO: iceman
502 // Hitag2 reader, problem is that this command mixes up stuff. So 26 give uid. 21 etc will also give you a memory dump !?
504 static int CmdLFHitagReader(const char *Cmd) {
506 CLIParserContext *ctx;
507 CLIParserInit(&ctx, "lf hitag reader",
508 "Act like a Hitag Reader",
509 "Hitag S\n"
510 " lf hitag reader --01 --nrar 0102030411223344\n"
511 " lf hitag reader --02 -k 4F4E4D494B52\n"
512 "Hitag 2\n"
513 " lf hitag reader --21 -k 4D494B52\n"
514 " lf hitag reader --22 --nrar 0102030411223344\n"
515 " lf hitag reader --23 -k 4F4E4D494B52\n"
516 " lf hitag reader --26\n"
519 void *argtable[] = {
520 arg_param_begin,
521 arg_lit0(NULL, "01", "HitagS, read all pages, challenge mode"),
522 arg_lit0(NULL, "02", "HitagS, read all pages, crypto mode. Set key=0 for no auth"),
523 arg_lit0(NULL, "21", "Hitag2, read all pages, password mode. def 4D494B52 (MIKR)"),
524 arg_lit0(NULL, "22", "Hitag2, read all pages, challenge mode"),
525 arg_lit0(NULL, "23", "Hitag2, read all pages, crypto mode. Key ISK high + ISK low. def 4F4E4D494B52 (ONMIKR)"),
526 arg_lit0(NULL, "25", "Hitag2, test recorded authentications (replay?)"),
527 arg_lit0(NULL, "26", "Hitag2, read UID"),
528 arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
529 arg_str0(NULL, "nrar", "<hex>", "nonce / answer reader, 8 hex bytes"),
530 arg_param_end
532 CLIExecWithReturn(ctx, Cmd, argtable, false);
534 // Hitag S
535 bool s01 = arg_get_lit(ctx, 1);
536 bool s02 = arg_get_lit(ctx, 2);
538 // Hitag 2
539 bool h21 = arg_get_lit(ctx, 3);
540 bool h22 = arg_get_lit(ctx, 4);
541 bool h23 = arg_get_lit(ctx, 5);
542 bool h25 = arg_get_lit(ctx, 6);
543 bool h26 = arg_get_lit(ctx, 7);
545 uint8_t key[6];
546 int keylen = 0;
547 int res = CLIParamHexToBuf(arg_get_str(ctx, 8), key, sizeof(key), &keylen);
548 if (res != 0) {
549 CLIParserFree(ctx);
550 return PM3_EINVARG;
553 uint8_t nrar[8];
554 int nalen = 0;
555 res = CLIParamHexToBuf(arg_get_str(ctx, 9), nrar, sizeof(nrar), &nalen);
556 CLIParserFree(ctx);
557 if (res != 0) {
558 return PM3_EINVARG;
561 // sanity checks
562 if (keylen != 0 && keylen != 4) {
563 PrintAndLogEx(WARNING, "Wrong KEY len expected 0 or 4, got %d", keylen);
564 return PM3_EINVARG;
567 if (nalen != 0 && nalen != 6) {
568 PrintAndLogEx(WARNING, "Wrong NR/AR len expected 0 or 6, got %d", nalen);
569 return PM3_EINVARG;
572 uint8_t foo = (s01 + s02 + h21 + h22 + h23 + h25 + h26);
573 if (foo > 1) {
574 PrintAndLogEx(WARNING, "Only specify one HITAG reader cmd");
575 return PM3_EINVARG;
576 } else if (foo == 0) {
577 PrintAndLogEx(WARNING, "Specify one HITAG reader cms");
578 return PM3_EINVARG;
581 hitag_function htf;
582 hitag_data htd;
583 uint16_t cmd = CMD_LF_HITAG_READER;
584 if (s01) {
585 cmd = CMD_LF_HITAGS_READ;
586 htf = RHTSF_CHALLENGE;
587 memcpy(htd.auth.NrAr, nrar, sizeof(nrar));
589 if (s02) {
590 cmd = CMD_LF_HITAGS_READ;
591 htf = RHTSF_KEY;
592 memcpy(htd.crypto.key, key, sizeof(key));
594 if (h21) {
595 htf = RHT2F_PASSWORD;
596 memcpy(htd.pwd.password, key, 4);
598 if (h22) {
599 htf = RHT2F_AUTHENTICATE;
600 memcpy(htd.auth.NrAr, nrar, sizeof(nrar));
602 if (h23) {
603 htf = RHT2F_CRYPTO;
604 memcpy(htd.crypto.key, key, sizeof(key));
606 if (h25) {
607 htf = RHT2F_TEST_AUTH_ATTEMPTS;
609 if (h26) {
610 htf = RHT2F_UID_ONLY;
613 clearCommandBuffer();
614 SendCommandMIX(cmd, htf, 0, 0, &htd, sizeof(htd));
615 PacketResponseNG resp;
616 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
617 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
618 return PM3_ETIMEOUT;
621 if (resp.oldarg[0] == false) {
622 PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
623 return PM3_ESOFT;
626 uint32_t id = bytes_to_num(resp.data.asBytes, 4);
627 uint8_t *data = resp.data.asBytes;
628 PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id);
630 if (htf != RHT2F_UID_ONLY) {
632 // block3, 1 byte
633 printHitagConfiguration(data[4 * 3]);
635 return PM3_SUCCESS;
638 static int CmdLFHitagCheckChallenges(const char *Cmd) {
640 CLIParserContext *ctx;
641 CLIParserInit(&ctx, "lf hitag cc",
642 "Check challenges, load a file with saved hitag crypto challenges and test them all.\n"
643 "The file should be 8 * 60 bytes long, the file extension defaults to " _YELLOW_("`.cc`") " ",
644 "lf hitag cc -f my_hitag_challenges"
647 void *argtable[] = {
648 arg_param_begin,
649 arg_str0("f", "filename", "<fn w/o ext>", "filename to load from"),
650 arg_param_end
652 CLIExecWithReturn(ctx, Cmd, argtable, true);
654 int fnlen = 0;
655 char filename[FILE_PATH_SIZE] = {0};
656 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
658 CLIParserFree(ctx);
660 clearCommandBuffer();
662 if (fnlen > 0) {
663 uint8_t *data = NULL;
664 size_t datalen = 0;
665 int res = loadFile_safe(filename, ".cc", (void **)&data, &datalen);
666 if (res == PM3_SUCCESS) {
667 if (datalen == (8 * 60)) {
668 SendCommandOLD(CMD_LF_HITAGS_TEST_TRACES, 1, 0, 0, data, datalen);
669 } else {
670 PrintAndLogEx(ERR, "Error, file length mismatch. Expected %d, got %zu", 8 * 60, datalen);
673 if (data) {
674 free(data);
676 } else {
677 SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0);
680 return PM3_SUCCESS;
683 static int CmdLFHitagWriter(const char *Cmd) {
684 CLIParserContext *ctx;
685 CLIParserInit(&ctx, "lf hitag writer",
686 "Act like a Hitag writer"
687 "In password mode the default key is 4D494B52 (MIKR)\n"
688 "In crypto mode the default key is 4F4E4D494B52 (ONMIKR) format: ISK high + ISK low.",
689 "Hitag S\n"
690 " lf hitag writer --03 --nrar 0102030411223344 -p 3 -d 01020304\n"
691 " lf hitag writer --04 -k 4F4E4D494B52 -p 3 -d 01020304\n"
692 "Hitag 2\n"
693 " lf hitag writer --24 -k 4F4E4D494B52 -p 3 -d 01020304\n"
694 " lf hitag writer --27 -k 4D494B52 -p 3 -d 01020304\n"
697 void *argtable[] = {
698 arg_param_begin,
699 arg_lit0(NULL, "03", "HitagS, write page, challenge mode"),
700 arg_lit0(NULL, "04", "HitagS, write page, crypto mode. Set key=0 for no auth"),
701 arg_lit0(NULL, "24", "Hitag2, write page, crypto mode."),
702 arg_lit0(NULL, "27", "Hitag2, write page, password mode"),
703 arg_int1("p", "page", "<dec>", "page address to write to"),
704 arg_str0("d", "data", "<hex>", "data, 4 hex bytes"),
705 arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
706 arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
707 arg_param_end
709 CLIExecWithReturn(ctx, Cmd, argtable, false);
711 // Hitag S
712 bool s03 = arg_get_lit(ctx, 1);
713 bool s04 = arg_get_lit(ctx, 2);
715 // Hitag 2
716 bool h24 = arg_get_lit(ctx, 3);
717 bool h27 = arg_get_lit(ctx, 4);
719 uint32_t page = arg_get_u32_def(ctx, 5, 0);
721 uint8_t data[4];
722 int dlen = 0;
723 int res = CLIParamHexToBuf(arg_get_str(ctx, 6), data, sizeof(data), &dlen);
724 if (res != 0) {
725 CLIParserFree(ctx);
726 return PM3_EINVARG;
729 uint8_t key[6];
730 int keylen = 0;
731 res = CLIParamHexToBuf(arg_get_str(ctx, 7), key, sizeof(key), &keylen);
732 if (res != 0) {
733 CLIParserFree(ctx);
734 return PM3_EINVARG;
737 uint8_t nrar[8];
738 int nalen = 0;
739 res = CLIParamHexToBuf(arg_get_str(ctx, 8), nrar, sizeof(nrar), &nalen);
741 CLIParserFree(ctx);
743 if (res != 0) {
744 return PM3_EINVARG;
747 // sanity checks
748 if (dlen != sizeof(data)) {
749 PrintAndLogEx(WARNING, "Wrong DATA len expected 4, got %d", dlen);
750 return PM3_EINVARG;
753 if (keylen != 0 && keylen != 6 && keylen != 4) {
754 PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen);
755 return PM3_EINVARG;
758 if (nalen != 0 && nalen != 8) {
759 PrintAndLogEx(WARNING, "Wrong NR/AR len expected 0 or 8, got %d", nalen);
760 return PM3_EINVARG;
763 uint8_t foo = (s03 + s04 + h24 + h27);
764 if (foo > 1) {
765 PrintAndLogEx(WARNING, "Only specify one HITAG write cmd");
766 return PM3_EINVARG;
767 } else if (foo == 0) {
768 PrintAndLogEx(WARNING, "Specify one HITAG write cmd");
769 return PM3_EINVARG;
772 hitag_function htf;
773 hitag_data htd;
774 if (s03) {
775 htf = WHTSF_CHALLENGE;
776 memcpy(htd.auth.NrAr, nrar, sizeof(nrar));
777 memcpy(htd.auth.data, data, sizeof(data));
779 if (s04) {
780 htf = WHTSF_KEY;
781 memcpy(htd.crypto.key, key, sizeof(key));
782 memcpy(htd.crypto.data, data, sizeof(data));
784 if (h24) {
785 htf = WHT2F_CRYPTO;
786 memcpy(htd.pwd.password, key, 4);
787 memcpy(htd.crypto.data, data, sizeof(data));
789 if (h27) {
790 htf = WHT2F_PASSWORD;
791 memcpy(htd.pwd.password, key, 4);
792 memcpy(htd.crypto.data, data, sizeof(data));
795 clearCommandBuffer();
796 SendCommandMIX(CMD_LF_HITAGS_WRITE, htf, 0, page, &htd, sizeof(htd));
797 PacketResponseNG resp;
798 if (WaitForResponseTimeout(CMD_ACK, &resp, 4000) == false) {
799 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
800 return PM3_ETIMEOUT;
803 if (resp.oldarg[0] == false) {
804 PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed");
805 return PM3_ESOFT;
807 return PM3_SUCCESS;
810 static int CmdLFHitag2Dump(const char *Cmd) {
812 CLIParserContext *ctx;
813 CLIParserInit(&ctx, "lf hitag dump",
814 "Read all card memory and save to file"
815 "In password mode the default key is 4D494B52 (MIKR)\n"
816 "In crypto mode the default key is 4F4E4D494B52 (ONMIKR) format: ISK high + ISK low.",
817 "lf hitag dump -k 4F4E4D494B52\n"
818 "lf hitag dump -k 4D494B52\n"
821 void *argtable[] = {
822 arg_param_begin,
823 arg_str0("f", "file", "<fn>", "file name"),
824 arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
825 arg_str0(NULL, "nrar", "<hex>", "nonce / answer reader, 8 hex bytes"),
826 arg_param_end
828 CLIExecWithReturn(ctx, Cmd, argtable, false);
829 uint8_t filename[FILE_PATH_SIZE] = {0};
830 int fnlen = 0;
831 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), filename, sizeof(filename), &fnlen);
832 if (res != 0) {
833 CLIParserFree(ctx);
834 return PM3_EINVARG;
837 uint8_t key[6];
838 int keylen = 0;
839 res = CLIParamHexToBuf(arg_get_str(ctx, 2), key, sizeof(key), &keylen);
840 if (res != 0) {
841 CLIParserFree(ctx);
842 return PM3_EINVARG;
845 uint8_t nrar[8];
846 int nalen = 0;
847 res = CLIParamHexToBuf(arg_get_str(ctx, 3), nrar, sizeof(nrar), &nalen);
848 CLIParserFree(ctx);
849 if (res != 0) {
850 return PM3_EINVARG;
853 PrintAndLogEx(WARNING, "to be implememted...");
856 PrintAndLogEx(SUCCESS, "Dumping tag memory...");
858 clearCommandBuffer();
859 //SendCommandNG(CMD_LF_HITAG_DUMP, &htd, sizeof(htd));
860 PacketResponseNG resp;
861 uint8_t *data = resp.data.asBytes;
862 if (fnlen < 1) {
863 char *fptr = filename;
864 fptr += sprintf(fptr, "lf-hitag-");
865 FillFileNameByUID(fptr, data, "-dump", 4);
868 saveFile(filename, ".bin", data, 48);
869 saveFileEML(filename, data, 48, 4);
870 saveFileJSON(filename, jsfHitag, data, 48, NULL);
872 return PM3_SUCCESS;
876 // Annotate HITAG protocol
877 void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
880 void annotateHitag2(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
882 // iceman: live decrypt of trace?
883 if (is_response) {
886 uint8_t cmdbits = (cmd[0] & 0xC0) >> 6;
888 if (cmdsize == 1) {
889 if (cmdbits == HITAG2_START_AUTH) {
890 snprintf(exp, size, "START AUTH");
891 return;
893 if (cmdbits == HITAG2_HALT) {
894 snprintf(exp, size, "HALT");
895 return;
899 if (cmdsize == 3) {
900 if (cmdbits == HITAG2_START_AUTH) {
901 // C 1 C 0
902 // 1100 0 00 1 1100 000
903 uint8_t page = (cmd[0] & 0x38) >> 3;
904 uint8_t inv_page = ((cmd[0] & 0x1) << 2) | ((cmd[1] & 0xC0) >> 6);
905 snprintf(exp, size, "READ page(%x) %x", page, inv_page);
906 return;
908 if (cmdbits == HITAG2_WRITE_PAGE) {
909 uint8_t page = (cmd[0] & 0x38) >> 3;
910 uint8_t inv_page = ((cmd[0] & 0x1) << 2) | ((cmd[1] & 0xC0) >> 6);
911 snprintf(exp, size, "WRITE page(%x) %x", page, inv_page);
912 return;
916 if (cmdsize == 9) {
917 snprintf(exp, size, "Nr Ar Is response");
918 return;
920 } else {
922 if (cmdsize == 9) {
923 snprintf(exp, size, "Nr Ar");
924 return;
931 void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
934 static command_t CommandTable[] = {
935 {"help", CmdHelp, AlwaysAvailable, "This help"},
936 {"eload", CmdLFHitagEload, IfPm3Hitag, "Load Hitag dump file into emulator memory"},
937 {"list", CmdLFHitagList, AlwaysAvailable, "List Hitag trace history"},
938 {"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information"},
939 {"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag reader"},
940 {"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder"},
941 {"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
942 {"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag writer"},
943 {"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag"},
944 {"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges"},
945 { NULL, NULL, 0, NULL }
948 static int CmdHelp(const char *Cmd) {
949 (void)Cmd; // Cmd is not used so far
950 CmdsHelp(CommandTable);
951 return PM3_SUCCESS;
954 int CmdLFHitag(const char *Cmd) {
955 clearCommandBuffer();
956 return CmdsParse(CommandTable, Cmd);
959 int readHitagUid(void) {
960 return (CmdLFHitagReader("--26") == PM3_SUCCESS);