1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency ISO14443A commands
17 //-----------------------------------------------------------------------------
21 #include "cmdparser.h" // command_t
22 #include "commonutil.h" // ARRAYLEN
23 #include "comms.h" // clearCommandBuffer
25 #include "cliparser.h"
28 #include "iso7816/iso7816core.h"
29 #include "emv/emvcore.h"
32 #include "util_posix.h" // msclock
33 #include "aidsearch.h"
34 #include "cmdhf.h" // handle HF plot
35 #include "cliparser.h"
36 #include "protocols.h" // definitions of ISO14A/7816 protocol, MAGIC_GEN_1A
37 #include "iso7816/apduinfo.h" // GetAPDUCodeDescription
38 #include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
39 #include "cmdnfc.h" // print_type4_cc_info
40 #include "fileutils.h" // saveFile
41 #include "atrs.h" // getATRinfo
42 #include "desfire.h" // desfire enums
43 #include "mifare/desfirecore.h" // desfire context
44 #include "mifare/mifaredefault.h"
45 #include "preferences.h" // get/set device debug level
47 static bool g_apdu_in_framing_enable
= true;
48 bool Get_apdu_in_framing(void) {
49 return g_apdu_in_framing_enable
;
51 void Set_apdu_in_framing(bool v
) {
52 g_apdu_in_framing_enable
= v
;
55 static int CmdHelp(const char *Cmd
);
56 static int waitCmd(bool i_select
, uint32_t timeout
, bool verbose
);
59 static const iso14a_polling_frame_t WUPA_FRAME
= {
63 static const iso14a_polling_frame_t MAGWUPA1_FRAME
= {
67 static const iso14a_polling_frame_t MAGWUPA2_FRAME
= {
71 static const iso14a_polling_frame_t MAGWUPA3_FRAME
= {
75 static const iso14a_polling_frame_t MAGWUPA4_FRAME
= {
79 static const iso14a_polling_frame_t ECP_FRAME
= {
80 .frame
= { 0x6a, 0x02, 0xC8, 0x01, 0x00, 0x03, 0x00, 0x02, 0x79, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xD8},
87 static const manufactureName_t manufactureMapping
[] = {
88 // ID, "Vendor Country"
89 { 0x01, "Motorola UK" },
90 { 0x02, "ST Microelectronics SA France" },
91 { 0x03, "Hitachi, Ltd Japan" },
92 { 0x04, "NXP Semiconductors Germany" },
93 { 0x05, "Infineon Technologies AG Germany" },
94 { 0x06, "Cylink USA" },
95 { 0x07, "Texas Instrument France" },
96 { 0x08, "Fujitsu Limited Japan" },
97 { 0x09, "Matsushita Electronics Corporation, Semiconductor Company Japan" },
98 { 0x0A, "NEC Japan" },
99 { 0x0B, "Oki Electric Industry Co. Ltd Japan" },
100 { 0x0C, "Toshiba Corp. Japan" },
101 { 0x0D, "Mitsubishi Electric Corp. Japan" },
102 { 0x0E, "Samsung Electronics Co. Ltd Korea" },
103 { 0x0F, "Hynix / Hyundai, Korea" },
104 { 0x10, "LG-Semiconductors Co. Ltd Korea" },
105 { 0x11, "Emosyn-EM Microelectronics USA" },
106 { 0x12, "INSIDE Technology France" },
107 { 0x13, "ORGA Kartensysteme GmbH Germany" },
108 { 0x14, "SHARP Corporation Japan" },
109 { 0x15, "ATMEL France" },
110 { 0x16, "EM Microelectronic-Marin SA Switzerland" },
111 { 0x17, "KSW Microtec GmbH Germany" },
112 { 0x18, "ZMD AG Germany" },
113 { 0x19, "XICOR, Inc. USA" },
114 { 0x1A, "Sony Corporation Japan" },
115 { 0x1B, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" },
116 { 0x1C, "Emosyn USA" },
117 { 0x1D, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" },
118 { 0x1E, "Magellan Technology Pty Limited Australia" },
119 { 0x1F, "Melexis NV BO Switzerland" },
120 { 0x20, "Renesas Technology Corp. Japan" },
121 { 0x21, "TAGSYS France" },
122 { 0x22, "Transcore USA" },
123 { 0x23, "Shanghai belling corp., ltd. China" },
124 { 0x24, "Masktech Germany Gmbh Germany" },
125 { 0x25, "Innovision Research and Technology Plc UK" },
126 { 0x26, "Hitachi ULSI Systems Co., Ltd. Japan" },
127 { 0x27, "Cypak AB Sweden" },
128 { 0x28, "Ricoh Japan" },
129 { 0x29, "ASK France" },
130 { 0x2A, "Unicore Microsystems, LLC Russian Federation" },
131 { 0x2B, "Dallas Semiconductor/Maxim USA" },
132 { 0x2C, "Impinj, Inc. USA" },
133 { 0x2D, "RightPlug Alliance USA" },
134 { 0x2E, "Broadcom Corporation USA" },
135 { 0x2F, "MStar Semiconductor, Inc Taiwan, ROC" },
136 { 0x30, "BeeDar Technology Inc. USA" },
137 { 0x31, "RFIDsec Denmark" },
138 { 0x32, "Schweizer Electronic AG Germany" },
139 { 0x33, "AMIC Technology Corp Taiwan" },
140 { 0x34, "Mikron JSC Russia" },
141 { 0x35, "Fraunhofer Institute for Photonic Microsystems Germany" },
142 { 0x36, "IDS Microchip AG Switzerland" },
143 { 0x37, "Thinfilm - Kovio USA" },
144 { 0x38, "HMT Microelectronic Ltd Switzerland" },
145 { 0x39, "Silicon Craft Technology Thailand" },
146 { 0x3A, "Advanced Film Device Inc. Japan" },
147 { 0x3B, "Nitecrest Ltd UK" },
148 { 0x3C, "Verayo Inc. USA" },
149 { 0x3D, "HID Global USA" },
150 { 0x3E, "Productivity Engineering Gmbh Germany" },
151 { 0x3F, "Austriamicrosystems AG (reserved) Austria" },
152 { 0x40, "Gemalto SA France" },
153 { 0x41, "Renesas Electronics Corporation Japan" },
154 { 0x42, "3Alogics Inc Korea" },
155 { 0x43, "Top TroniQ Asia Limited Hong Kong" },
156 { 0x44, "Gentag Inc. USA" },
157 { 0x45, "Invengo Information Technology Co.Ltd China" },
158 { 0x46, "Guangzhou Sysur Microelectronics, Inc China" },
159 { 0x47, "CEITEC S.A. Brazil" },
160 { 0x48, "Shanghai Quanray Electronics Co. Ltd. China" },
161 { 0x49, "MediaTek Inc Taiwan" },
162 { 0x4A, "Angstrem PJSC Russia" },
163 { 0x4B, "Celisic Semiconductor (Hong Kong) Limited China" },
164 { 0x4C, "LEGIC Identsystems AG Switzerland" },
165 { 0x4D, "Balluff GmbH Germany" },
166 { 0x4E, "Oberthur Technologies France" },
167 { 0x4F, "Silterra Malaysia Sdn. Bhd. Malaysia" },
168 { 0x50, "DELTA Danish Electronics, Light & Acoustics Denmark" },
169 { 0x51, "Giesecke & Devrient GmbH Germany" },
170 { 0x52, "Shenzhen China Vision Microelectronics Co., Ltd. China" },
171 { 0x53, "Shanghai Feiju Microelectronics Co. Ltd. China" },
172 { 0x54, "Intel Corporation USA" },
173 { 0x55, "Microsensys GmbH Germany" },
174 { 0x56, "Sonix Technology Co., Ltd. Taiwan" },
175 { 0x57, "Qualcomm Technologies Inc USA" },
176 { 0x58, "Realtek Semiconductor Corp Taiwan" },
177 { 0x59, "Freevision Technologies Co. Ltd China" },
178 { 0x5A, "Giantec Semiconductor Inc. China" },
179 { 0x5B, "JSC Angstrem-T Russia" },
180 { 0x5C, "STARCHIP France" },
181 { 0x5D, "SPIRTECH France" },
182 { 0x5E, "GANTNER Electronic GmbH Austria" },
183 { 0x5F, "Nordic Semiconductor Norway" },
184 { 0x60, "Verisiti Inc USA" },
185 { 0x61, "Wearlinks Technology Inc. China" },
186 { 0x62, "Userstar Information Systems Co., Ltd Taiwan" },
187 { 0x63, "Pragmatic Printing Ltd. UK" },
188 { 0x64, "Associacao do Laboratorio de Sistemas Integraveis Tecnologico - LSI-TEC Brazil" },
189 { 0x65, "Tendyron Corporation China" },
190 { 0x66, "MUTO Smart Co., Ltd. Korea" },
191 { 0x67, "ON Semiconductor USA" },
192 { 0x68, "TUBITAK BILGEM Turkey" },
193 { 0x69, "Huada Semiconductor Co., Ltd China" },
194 { 0x6A, "SEVENEY France" },
195 { 0x6B, "ISSM France" },
196 { 0x6C, "Wisesec Ltd Israel" },
197 { 0x7C, "DB HiTek Co Ltd Korea" },
198 { 0x7D, "SATO Vicinity Australia" },
199 { 0x7E, "Holtek Taiwan" },
200 { 0x00, "no tag-info available" } // must be the last entry
203 // get a product description based on the UID
205 // returns description of the best match
206 const char *getTagInfo(uint8_t uid
) {
208 for (int i
= 0; i
< ARRAYLEN(manufactureMapping
); ++i
) {
209 if (uid
== manufactureMapping
[i
].uid
) {
210 return manufactureMapping
[i
].desc
;
214 //No match, return default
215 return manufactureMapping
[ARRAYLEN(manufactureMapping
) - 1].desc
;
218 static const hintAIDList_t hintAIDList
[] = {
219 // AID, AID len, name, hint - how to use
220 { "\xA0\x00\x00\x06\x47\x2F\x00\x01", 8, "FIDO", "hf fido" },
221 { "\xA0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00", 11, "PIV", "" },
222 { "\xD2\x76\x00\x01\x24\x01", 8, "OpenPGP", "" },
223 { "\x31\x50\x41\x59\x2E\x53\x59\x53\x2E\x44\x44\x46\x30\x31", 14, "EMV (pse)", "emv" },
224 { "\x32\x50\x41\x59\x2E\x53\x59\x53\x2E\x44\x44\x46\x30\x31", 14, "EMV (ppse)", "emv" },
225 { "\x41\x44\x20\x46\x31", 5, "CIPURSE", "hf cipurse" },
226 { "\xd2\x76\x00\x00\x85\x01\x00", 7, "desfire", "hf mfdes" },
227 { "\x4F\x53\x45\x2E\x56\x41\x53\x2E\x30\x31", 10, "Apple VAS", "hf vas"},
230 // iso14a apdu input frame length
231 static uint16_t gs_frame_len
= 0;
232 static uint8_t gs_frames_num
= 0;
233 static uint16_t atsFSC
[] = {16, 24, 32, 40, 48, 64, 96, 128, 256};
235 static int CmdHF14AList(const char *Cmd
) {
236 return CmdTraceListAlias(Cmd
, "hf 14a", "14a -c");
239 int hf14a_getconfig(hf14a_config
*config
) {
240 if (!g_session
.pm3_present
) return PM3_ENOTTY
;
245 clearCommandBuffer();
247 SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG
, NULL
, 0);
248 PacketResponseNG resp
;
249 if (!WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG
, &resp
, 2000)) {
250 PrintAndLogEx(WARNING
, "command execution time out");
253 memcpy(config
, resp
.data
.asBytes
, sizeof(hf14a_config
));
257 int hf14a_setconfig(hf14a_config
*config
, bool verbose
) {
258 if (!g_session
.pm3_present
) return PM3_ENOTTY
;
260 clearCommandBuffer();
261 if (config
!= NULL
) {
262 SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG
, (uint8_t *)config
, sizeof(hf14a_config
));
264 SendCommandNG(CMD_HF_ISO14443A_PRINT_CONFIG
, NULL
, 0);
267 SendCommandNG(CMD_HF_ISO14443A_PRINT_CONFIG
, NULL
, 0);
273 static int hf_14a_config_example(void) {
274 PrintAndLogEx(NORMAL
, "\nExamples to revive Gen2/DirectWrite magic cards failing at anticollision:");
275 PrintAndLogEx(NORMAL
, _CYAN_(" MFC 1k 4b UID")":");
276 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 skip --rats skip"));
277 PrintAndLogEx(NORMAL
, _YELLOW_(" hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 11223344440804006263646566676869"));
278 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --std"));
279 PrintAndLogEx(NORMAL
, _CYAN_(" MFC 4k 4b UID")":");
280 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 skip --rats skip"));
281 PrintAndLogEx(NORMAL
, _YELLOW_(" hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 11223344441802006263646566676869"));
282 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --std"));
283 PrintAndLogEx(NORMAL
, _CYAN_(" MFC 1k 7b UID")":");
284 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip --rats skip"));
285 PrintAndLogEx(NORMAL
, _YELLOW_(" hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 04112233445566084400626364656667"));
286 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --std"));
287 PrintAndLogEx(NORMAL
, _CYAN_(" MFC 4k 7b UID")":");
288 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip --rats skip"));
289 PrintAndLogEx(NORMAL
, _YELLOW_(" hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 04112233445566184200626364656667"));
290 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --std"));
291 PrintAndLogEx(NORMAL
, _CYAN_(" MFUL ")"/" _CYAN_(" MFUL EV1 ")"/" _CYAN_(" MFULC")":");
292 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip -rats skip"));
293 PrintAndLogEx(NORMAL
, _YELLOW_(" hf mfu setuid --uid 04112233445566"));
294 PrintAndLogEx(NORMAL
, _YELLOW_(" hf 14a config --std"));
297 static int CmdHf14AConfig(const char *Cmd
) {
298 if (!g_session
.pm3_present
) return PM3_ENOTTY
;
300 CLIParserContext
*ctx
;
301 CLIParserInit(&ctx
, "hf 14a config",
302 "Configure 14a settings (use with caution)\n"
303 " `-v` also prints examples for reviving Gen2 cards",
304 "hf 14a config -> Print current configuration\n"
305 "hf 14a config --std -> Reset default configuration (follow standard)\n"
306 "hf 14a config --atqa std -> Follow standard\n"
307 "hf 14a config --atqa force -> Force execution of anticollision\n"
308 "hf 14a config --atqa skip -> Skip anticollision\n"
309 "hf 14a config --bcc std -> Follow standard\n"
310 "hf 14a config --bcc fix -> Fix bad BCC in anticollision\n"
311 "hf 14a config --bcc ignore -> Ignore bad BCC and use it as such\n"
312 "hf 14a config --cl2 std -> Follow standard\n"
313 "hf 14a config --cl2 force -> Execute CL2\n"
314 "hf 14a config --cl2 skip -> Skip CL2\n"
315 "hf 14a config --cl3 std -> Follow standard\n"
316 "hf 14a config --cl3 force -> Execute CL3\n"
317 "hf 14a config --cl3 skip -> Skip CL3\n"
318 "hf 14a config --rats std -> Follow standard\n"
319 "hf 14a config --rats force -> Execute RATS\n"
320 "hf 14a config --rats skip -> Skip RATS");
324 arg_str0(NULL
, "atqa", "<std|force|skip>", "Configure ATQA<>anticollision behavior"),
325 arg_str0(NULL
, "bcc", "<std|fix|ignore>", "Configure BCC behavior"),
326 arg_str0(NULL
, "cl2", "<std|force|skip>", "Configure SAK<>CL2 behavior"),
327 arg_str0(NULL
, "cl3", "<std|force|skip>", "Configure SAK<>CL3 behavior"),
328 arg_str0(NULL
, "rats", "<std|force|skip>", "Configure RATS behavior"),
329 arg_lit0(NULL
, "std", "Reset default configuration: follow all standard"),
330 arg_lit0("v", "verbose", "verbose output"),
333 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
334 bool defaults
= arg_get_lit(ctx
, 6);
337 int atqa
= defaults
? 0 : -1;
338 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)value
, sizeof(value
), &vlen
);
340 if (strcmp(value
, "std") == 0) atqa
= 0;
341 else if (strcmp(value
, "force") == 0) atqa
= 1;
342 else if (strcmp(value
, "skip") == 0) atqa
= 2;
344 PrintAndLogEx(ERR
, "atqa argument must be 'std', 'force', or 'skip'");
349 int bcc
= defaults
? 0 : -1;
350 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)value
, sizeof(value
), &vlen
);
352 if (strcmp(value
, "std") == 0) bcc
= 0;
353 else if (strcmp(value
, "fix") == 0) bcc
= 1;
354 else if (strcmp(value
, "ignore") == 0) bcc
= 2;
356 PrintAndLogEx(ERR
, "bcc argument must be 'std', 'fix', or 'ignore'");
361 int cl2
= defaults
? 0 : -1;
362 CLIParamStrToBuf(arg_get_str(ctx
, 3), (uint8_t *)value
, sizeof(value
), &vlen
);
364 if (strcmp(value
, "std") == 0) cl2
= 0;
365 else if (strcmp(value
, "force") == 0) cl2
= 1;
366 else if (strcmp(value
, "skip") == 0) cl2
= 2;
368 PrintAndLogEx(ERR
, "cl2 argument must be 'std', 'force', or 'skip'");
373 int cl3
= defaults
? 0 : -1;
374 CLIParamStrToBuf(arg_get_str(ctx
, 4), (uint8_t *)value
, sizeof(value
), &vlen
);
376 if (strcmp(value
, "std") == 0) cl3
= 0;
377 else if (strcmp(value
, "force") == 0) cl3
= 1;
378 else if (strcmp(value
, "skip") == 0) cl3
= 2;
380 PrintAndLogEx(ERR
, "cl3 argument must be 'std', 'force', or 'skip'");
385 int rats
= defaults
? 0 : -1;
386 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)value
, sizeof(value
), &vlen
);
388 if (strcmp(value
, "std") == 0) rats
= 0;
389 else if (strcmp(value
, "force") == 0) rats
= 1;
390 else if (strcmp(value
, "skip") == 0) rats
= 2;
392 PrintAndLogEx(ERR
, "rats argument must be 'std', 'force', or 'skip'");
398 bool verbose
= arg_get_lit(ctx
, 7);
403 if (strlen(Cmd
) == 0) {
404 return hf14a_setconfig(NULL
, verbose
);
408 hf_14a_config_example();
411 hf14a_config config
= {
412 .forceanticol
= atqa
,
419 return hf14a_setconfig(&config
, verbose
);
422 static const char *get_uid_type(iso14a_card_select_t
*card
) {
424 static char s
[60] = {0};
425 memset(s
, 0, sizeof(s
));
427 switch (card
->uidlen
) {
429 if (card
->uid
[0] == 0x08) {
430 sprintf(s
, " ( RID - random ID )");
431 } else if ((card
->uid
[0] & 0xF) == 0xF) {
432 sprintf(s
, " ( FNUID, fixed, non-unique ID )");
433 } else if (card
->uid
[0] == 0x88) {
434 sprintf(s
, " ( Cascade tag - not final )");
435 } else if (card
->uid
[0] == 0xF8) {
436 sprintf(s
, " ( RFU )");
438 sprintf(s
, " ( ONUID, re-used )");
443 sprintf(s
, " ( double )");
447 sprintf(s
, " ( triple )");
456 int Hf14443_4aGetCardData(iso14a_card_select_t
*card
) {
458 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
459 PacketResponseNG resp
;
460 WaitForResponse(CMD_ACK
, &resp
);
461 memcpy(card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
463 uint64_t select_status
= resp
.oldarg
[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
465 if (select_status
== 0) {
466 PrintAndLogEx(ERR
, "E->iso14443a card select failed");
470 if (select_status
== 2) {
471 PrintAndLogEx(ERR
, "E->Card doesn't support iso14443-4 mode");
475 if (select_status
== 3) {
476 PrintAndLogEx(INFO
, "E->Card doesn't support standard iso14443-3 anticollision");
478 if (card
->atqa
[1] == 0x0C && card
->atqa
[0] == 0x00) {
479 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`hf topaz info`"));
481 PrintAndLogEx(SUCCESS
, "\tATQA : %02X %02X", card
->atqa
[1], card
->atqa
[0]);
486 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(card
->uid
, card
->uidlen
));
487 PrintAndLogEx(SUCCESS
, "ATQA: %02X %02X", card
->atqa
[1], card
->atqa
[0]);
488 PrintAndLogEx(SUCCESS
, " SAK: %02X [%" PRIu64
"]", card
->sak
, resp
.oldarg
[0]);
490 // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
491 if (card
->ats_len
< 3) {
492 PrintAndLogEx(INFO
, "E-> Error ATS length(%d) : %s", card
->ats_len
, sprint_hex(card
->ats
, card
->ats_len
));
493 return PM3_ECARDEXCHANGE
;
496 if (card
->ats_len
== card
->ats
[0] + 2)
497 PrintAndLogEx(SUCCESS
, " ATS: [%d] %s", card
->ats
[0], sprint_hex(card
->ats
, card
->ats
[0]));
499 PrintAndLogEx(SUCCESS
, " ATS: [%d] %s", card
->ats_len
, sprint_hex(card
->ats
, card
->ats_len
));
504 iso14a_polling_parameters_t
iso14a_get_polling_parameters(bool use_ecp
, bool use_magsafe
) {
505 // Extra 100ms give enough time for Apple (ECP) devices to proccess field info and make a decision
507 if (use_ecp
&& use_magsafe
) {
508 iso14a_polling_parameters_t full_polling_parameters
= {
509 .frames
= { WUPA_FRAME
, ECP_FRAME
, MAGWUPA1_FRAME
, MAGWUPA2_FRAME
, MAGWUPA3_FRAME
, MAGWUPA4_FRAME
},
513 return full_polling_parameters
;
514 } else if (use_ecp
) {
515 iso14a_polling_parameters_t ecp_polling_parameters
= {
516 .frames
= { WUPA_FRAME
, ECP_FRAME
},
520 return ecp_polling_parameters
;
521 } else if (use_magsafe
) {
522 iso14a_polling_parameters_t magsafe_polling_parameters
= {
523 .frames
= { WUPA_FRAME
, MAGWUPA1_FRAME
, MAGWUPA2_FRAME
, MAGWUPA3_FRAME
, MAGWUPA4_FRAME
},
527 return magsafe_polling_parameters
;
530 iso14a_polling_parameters_t wupa_polling_parameters
= {
531 .frames
= { WUPA_FRAME
},
535 return wupa_polling_parameters
;
538 static int CmdHF14AReader(const char *Cmd
) {
539 CLIParserContext
*ctx
;
540 CLIParserInit(&ctx
, "hf 14a reader",
541 "Act as a ISO-14443a reader to identify tag. Look for ISO-14443a tags until Enter or the pm3 button is pressed",
543 "hf 14a reader -@ -> Continuous mode\n"
544 "hf 14a reader --ecp -> trigger apple enhanced contactless polling\n"
545 "hf 14a reader --mag -> trigger apple magsafe polling\n"
550 arg_lit0("k", "keep", "keep the field active after command executed"),
551 arg_lit0("s", "silent", "silent (no messages)"),
552 arg_lit0(NULL
, "drop", "just drop the signal field"),
553 arg_lit0(NULL
, "skip", "ISO14443-3 select only (skip RATS)"),
554 arg_lit0(NULL
, "ecp", "Use enhanced contactless polling"),
555 arg_lit0(NULL
, "mag", "Use Apple magsafe polling"),
556 arg_lit0("@", NULL
, "continuous reader mode"),
559 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
561 bool disconnectAfter
= true;
562 if (arg_get_lit(ctx
, 1)) {
563 disconnectAfter
= false;
566 bool silent
= arg_get_lit(ctx
, 2);
568 uint32_t cm
= ISO14A_CONNECT
;
569 if (arg_get_lit(ctx
, 3)) {
570 cm
&= ~ISO14A_CONNECT
;
573 if (arg_get_lit(ctx
, 4)) {
574 cm
|= ISO14A_NO_RATS
;
577 bool use_ecp
= arg_get_lit(ctx
, 5);
578 bool use_magsafe
= arg_get_lit(ctx
, 6);
580 iso14a_polling_parameters_t
*polling_parameters
= NULL
;
581 iso14a_polling_parameters_t parameters
= iso14a_get_polling_parameters(use_ecp
, use_magsafe
);
582 if (use_ecp
|| use_magsafe
) {
583 cm
|= ISO14A_USE_CUSTOM_POLLING
;
584 polling_parameters
= ¶meters
;
587 bool continuous
= arg_get_lit(ctx
, 7);
590 if (disconnectAfter
== false) {
591 cm
|= ISO14A_NO_DISCONNECT
;
595 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
598 int res
= PM3_SUCCESS
;
600 clearCommandBuffer();
602 if ((cm
& ISO14A_USE_CUSTOM_POLLING
) == ISO14A_USE_CUSTOM_POLLING
) {
603 SendCommandMIX(CMD_HF_ISO14443A_READER
, cm
, 0, 0, (uint8_t *)polling_parameters
, sizeof(iso14a_polling_parameters_t
));
605 SendCommandMIX(CMD_HF_ISO14443A_READER
, cm
, 0, 0, NULL
, 0);
608 if ((cm
& ISO14A_CONNECT
) == ISO14A_CONNECT
) {
609 PacketResponseNG resp
;
610 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
616 iso14a_card_select_t card
;
617 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
623 3: proprietary Anticollision
625 uint64_t select_status
= resp
.oldarg
[0];
627 if (select_status
== 0) {
633 if (select_status
== 3) {
634 if (!(silent
&& continuous
)) {
635 PrintAndLogEx(INFO
, "Card doesn't support standard iso14443-3 anticollision");
638 if (card
.atqa
[1] == 0x0C && card
.atqa
[0] == 0x00) {
639 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`hf topaz info`"));
641 PrintAndLogEx(SUCCESS
, "ATQA: %02X %02X", card
.atqa
[1], card
.atqa
[0]);
643 PrintAndLogEx(NORMAL
, "");
650 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(card
.uid
, card
.uidlen
));
652 if (!(silent
&& continuous
)) {
653 PrintAndLogEx(SUCCESS
, "ATQA: " _GREEN_("%02X %02X"), card
.atqa
[1], card
.atqa
[0]);
654 PrintAndLogEx(SUCCESS
, " SAK: " _GREEN_("%02X [%" PRIu64
"]"), card
.sak
, resp
.oldarg
[0]);
656 if (card
.ats_len
>= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
657 if (card
.ats_len
== card
.ats
[0] + 2)
658 PrintAndLogEx(SUCCESS
, " ATS: " _GREEN_("%s"), sprint_hex(card
.ats
, card
.ats
[0]));
660 PrintAndLogEx(SUCCESS
, " ATS: [%d] " _GREEN_("%s"), card
.ats_len
, sprint_hex(card
.ats
, card
.ats_len
));
663 PrintAndLogEx(NORMAL
, "");
665 if ((disconnectAfter
== false) && (silent
== false)) {
666 PrintAndLogEx(SUCCESS
, "Card is selected. You can now start sending commands");
671 res
= handle_hf_plot(false);
672 if (res
!= PM3_SUCCESS
) {
673 PrintAndLogEx(DEBUG
, "plot failed");
677 if (kbd_enter_pressed()) {
681 } while (continuous
);
683 if (disconnectAfter
== false) {
684 if (silent
== false) {
685 PrintAndLogEx(INFO
, "field is on");
695 static int CmdHF14AInfo(const char *Cmd
) {
697 bool do_nack_test
= false;
698 bool do_aid_search
= false;
700 CLIParserContext
*ctx
;
701 CLIParserInit(&ctx
, "hf 14a info",
702 "This command makes more extensive tests against a ISO14443a tag in order to collect information",
703 "hf 14a info -nsv -> shows full information about the card\n");
707 arg_lit0("v", "verbose", "verbose output"),
708 arg_lit0("n", "nacktest", "test for nack bug"),
709 arg_lit0("s", "aidsearch", "checks if AIDs from aidlist.json is present on the card and prints information about found AIDs"),
712 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
714 verbose
= arg_get_lit(ctx
, 1);
715 do_nack_test
= arg_get_lit(ctx
, 2);
716 do_aid_search
= arg_get_lit(ctx
, 3);
720 infoHF14A(verbose
, do_nack_test
, do_aid_search
);
724 // Collect ISO14443 Type A UIDs
725 static int CmdHF14ACUIDs(const char *Cmd
) {
726 CLIParserContext
*ctx
;
727 CLIParserInit(&ctx
, "hf 14a cuids",
728 "Collect n>0 ISO14443-a UIDs in one go",
729 "hf 14a cuids -n 5 --> Collect 5 UIDs");
733 arg_int0("n", "num", "<dec>", "Number of UIDs to collect"),
736 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
738 // requested number of UIDs
739 // collect at least 1 (e.g. if no parameter was given)
740 int n
= arg_get_int_def(ctx
, 1, 1);
744 uint64_t t1
= msclock();
745 PrintAndLogEx(SUCCESS
, "collecting %d UIDs", n
);
748 for (int i
= 0; i
< n
; i
++) {
750 if (kbd_enter_pressed()) {
751 PrintAndLogEx(WARNING
, "aborted via keyboard!\n");
755 // execute anticollision procedure
756 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_RATS
, 0, 0, NULL
, 0);
758 PacketResponseNG resp
;
759 WaitForResponse(CMD_ACK
, &resp
);
761 iso14a_card_select_t
*card
= (iso14a_card_select_t
*) resp
.data
.asBytes
;
763 // check if command failed
764 if (resp
.oldarg
[0] == 0) {
765 PrintAndLogEx(WARNING
, "card select failed.");
768 for (uint16_t m
= 0; m
< card
->uidlen
; m
++) {
770 snprintf(uid_string
+ offset
, sizeof(uid_string
) - offset
, "%02X", card
->uid
[m
]);
772 PrintAndLogEx(SUCCESS
, "%s", uid_string
);
775 PrintAndLogEx(SUCCESS
, "end: %" PRIu64
" seconds", (msclock() - t1
) / 1000);
779 // ## simulate iso14443a tag
780 int CmdHF14ASim(const char *Cmd
) {
781 CLIParserContext
*ctx
;
782 CLIParserInit(&ctx
, "hf 14a sim",
783 "Simulate ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"
784 "Use type 7 for Mifare Ultralight EV1, Amiibo (NTAG215 pack 0x8080)",
785 "hf 14a sim -t 1 --uid 11223344 -> MIFARE Classic 1k\n"
786 "hf 14a sim -t 2 -> MIFARE Ultralight\n"
787 "hf 14a sim -t 3 -> MIFARE Desfire\n"
788 "hf 14a sim -t 4 -> ISO/IEC 14443-4\n"
789 "hf 14a sim -t 5 -> MIFARE Tnp3xxx\n"
790 "hf 14a sim -t 6 -> MIFARE Mini\n"
791 "hf 14a sim -t 7 -> MFU EV1 / NTAG 215 Amiibo\n"
792 "hf 14a sim -t 8 -> MIFARE Classic 4k\n"
793 "hf 14a sim -t 9 -> FM11RF005SH Shanghai Metro\n"
794 "hf 14a sim -t 10 -> ST25TA IKEA Rothult\n"
795 "hf 14a sim -t 11 -> Javacard (JCOP)\n"
796 "hf 14a sim -t 12 -> 4K Seos card\n"
801 arg_int1("t", "type", "<1-12> ", "Simulation type to use"),
802 arg_str0("u", "uid", "<hex>", "<4|7|10> hex bytes UID"),
803 arg_int0("n", "num", "<dec>", "Exit simulation after <numreads> blocks have been read by reader. 0 = infinite"),
804 arg_lit0("x", NULL
, "Performs the 'reader attack', nr/ar attack against a reader"),
805 arg_lit0(NULL
, "sk", "Fill simulator keys from found keys"),
806 arg_lit0("v", "verbose", "verbose output"),
809 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
811 int tagtype
= arg_get_int_def(ctx
, 1, 1);
814 uint8_t uid
[10] = {0};
815 CLIGetHexWithReturn(ctx
, 2, uid
, &uid_len
);
818 bool useUIDfromEML
= true;
823 flags
|= FLAG_10B_UID_IN_DATA
;
826 flags
|= FLAG_7B_UID_IN_DATA
;
829 flags
|= FLAG_4B_UID_IN_DATA
;
832 PrintAndLogEx(ERR
, "Please specify a 4, 7, or 10 byte UID");
836 PrintAndLogEx(SUCCESS
, "Emulating " _YELLOW_("ISO/IEC 14443 type A tag")" with " _GREEN_("%d byte UID (%s)"), uid_len
, sprint_hex(uid
, uid_len
));
837 useUIDfromEML
= false;
840 uint8_t exitAfterNReads
= arg_get_int_def(ctx
, 3, 0);
842 if (arg_get_lit(ctx
, 4)) {
843 flags
|= FLAG_NR_AR_ATTACK
;
846 bool setEmulatorMem
= arg_get_lit(ctx
, 5);
847 bool verbose
= arg_get_lit(ctx
, 6);
852 PrintAndLogEx(ERR
, "Undefined tag %d", tagtype
);
857 flags
|= FLAG_UID_IN_EMUL
;
867 payload
.tagtype
= tagtype
;
868 payload
.flags
= flags
;
869 payload
.exitAfter
= exitAfterNReads
;
870 memcpy(payload
.uid
, uid
, uid_len
);
872 clearCommandBuffer();
873 SendCommandNG(CMD_HF_ISO14443A_SIMULATE
, (uint8_t *)&payload
, sizeof(payload
));
874 PacketResponseNG resp
= {0};
876 sector_t
*k_sector
= NULL
;
877 size_t k_sectors_cnt
= MIFARE_4K_MAXSECTOR
;
879 PrintAndLogEx(INFO
, "Press " _GREEN_("pm3 button") " to abort simulation");
880 bool keypress
= kbd_enter_pressed();
881 while (keypress
== false) {
883 if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE
, &resp
, 1500) == 0)
886 if (resp
.status
!= PM3_SUCCESS
)
889 if ((flags
& FLAG_NR_AR_ATTACK
) != FLAG_NR_AR_ATTACK
)
892 const nonces_t
*data
= (nonces_t
*)resp
.data
.asBytes
;
893 readerAttack(k_sector
, k_sectors_cnt
, data
[0], setEmulatorMem
, verbose
);
895 keypress
= kbd_enter_pressed();
899 if ((flags
& FLAG_NR_AR_ATTACK
) == FLAG_NR_AR_ATTACK
) {
900 // inform device to break the sim loop since client has exited
901 SendCommandNG(CMD_BREAK_LOOP
, NULL
, 0);
904 if (resp
.status
== PM3_EOPABORTED
&& ((flags
& FLAG_NR_AR_ATTACK
) == FLAG_NR_AR_ATTACK
)) {
905 //iceman: readerAttack call frees k_sector , this call is useless.
906 showSectorTable(k_sector
, k_sectors_cnt
);
910 PrintAndLogEx(INFO
, "Done!");
914 int CmdHF14ASniff(const char *Cmd
) {
915 CLIParserContext
*ctx
;
916 CLIParserInit(&ctx
, "hf 14a sniff",
917 "Sniff the communication between Hitag reader and tag.\n"
918 "Use `hf 14a list` to view collected data.",
919 " hf 14a sniff -c -r"
923 arg_lit0("c", "card", "triggered by first data from card"),
924 arg_lit0("r", "reader", "triggered by first 7-bit request from reader (REQ, WUP)"),
925 arg_lit0("i", "interactive", "Console will not be returned until sniff finishes or is aborted"),
928 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
932 if (arg_get_lit(ctx
, 1)) {
936 if (arg_get_lit(ctx
, 2)) {
940 bool interactive
= arg_get_lit(ctx
, 3);
943 clearCommandBuffer();
944 SendCommandNG(CMD_HF_ISO14443A_SNIFF
, (uint8_t *)¶m
, sizeof(uint8_t));
946 PrintAndLogEx(INFO
, "Press " _GREEN_("pm3 button") " to abort sniffing");
949 PacketResponseNG resp
;
950 WaitForResponse(CMD_HF_ISO14443A_SNIFF
, &resp
);
951 PrintAndLogEx(INFO
, "Done!");
952 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf 14a list")"` to view captured tracelog");
953 PrintAndLogEx(HINT
, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing");
958 int ExchangeRAW14a(uint8_t *datain
, int datainlen
, bool activateField
, bool leaveSignalON
, uint8_t *dataout
, int maxdataoutlen
, int *dataoutlen
, bool silentMode
) {
964 // select with no disconnect and set gs_frame_len
965 int selres
= SelectCard14443A_4(false, !silentMode
, NULL
);
967 if (selres
!= PM3_SUCCESS
) {
973 cmdc
|= ISO14A_NO_DISCONNECT
;
976 uint8_t data
[PM3_CMD_DATA_SIZE
] = { 0x0a | gs_frames_num
, 0x00 };
979 int min
= MIN((PM3_CMD_DATA_SIZE
- 2), (datainlen
& 0x1FF));
980 memcpy(&data
[2], datain
, min
);
981 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_RAW
| ISO14A_APPEND_CRC
| cmdc
, (datainlen
& 0xFFFF) + 2, 0, data
, min
+ 2);
984 PacketResponseNG resp
;
985 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
986 recv
= resp
.data
.asBytes
;
987 int iLen
= resp
.oldarg
[0];
990 if (silentMode
== false) {
991 PrintAndLogEx(ERR
, "No card response");
993 return PM3_ECARDEXCHANGE
;
996 *dataoutlen
= iLen
- 2;
997 if (*dataoutlen
< 0) {
1001 if (maxdataoutlen
&& *dataoutlen
> maxdataoutlen
) {
1002 if (silentMode
== false) {
1003 PrintAndLogEx(ERR
, "Buffer too small(%d). Needs %d bytes", *dataoutlen
, maxdataoutlen
);
1008 if (recv
[0] != data
[0]) {
1009 if (silentMode
== false) {
1010 PrintAndLogEx(ERR
, "iso14443-4 framing error. Card send %2x must be %2x", recv
[0], data
[0]);
1015 memcpy(dataout
, &recv
[2], *dataoutlen
);
1019 if (silentMode
== false) {
1020 PrintAndLogEx(ERR
, "ISO 14443A CRC error");
1026 if (silentMode
== false) {
1027 PrintAndLogEx(ERR
, "Reply timeout.");
1029 return PM3_ETIMEOUT
;
1035 int SelectCard14443A_4_WithParameters(bool disconnect
, bool verbose
, iso14a_card_select_t
*card
, iso14a_polling_parameters_t
*polling_parameters
) {
1036 // global vars should be prefixed with g_
1041 memset(card
, 0, sizeof(iso14a_card_select_t
));
1046 // Anticollision + SELECT card
1047 PacketResponseNG resp
;
1048 if (polling_parameters
!= NULL
) {
1049 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_DISCONNECT
| ISO14A_USE_CUSTOM_POLLING
, 0, 0, (uint8_t *)polling_parameters
, sizeof(iso14a_polling_parameters_t
));
1051 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_DISCONNECT
, 0, 0, NULL
, 0);
1054 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
1055 PrintAndLogEx(WARNING
, "Command execute timeout");
1056 return PM3_ETIMEOUT
;
1060 if (resp
.oldarg
[0] == 0) {
1062 PrintAndLogEx(WARNING
, "No ISO1443-A Card in field");
1064 return PM3_ECARDEXCHANGE
;
1067 if (resp
.oldarg
[0] != 1 && resp
.oldarg
[0] != 2) {
1068 PrintAndLogEx(WARNING
, "Card not in iso14443-4, res=%" PRId64
".", resp
.oldarg
[0]);
1069 return PM3_ECARDEXCHANGE
;
1072 iso14a_card_select_t
*vcard
= (iso14a_card_select_t
*) resp
.data
.asBytes
;
1074 memcpy(card
, vcard
, sizeof(iso14a_card_select_t
));
1077 if (resp
.oldarg
[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
1079 uint8_t rats
[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
1080 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_RAW
| ISO14A_APPEND_CRC
| ISO14A_NO_DISCONNECT
, sizeof(rats
), 0, rats
, sizeof(rats
));
1081 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
1082 PrintAndLogEx(WARNING
, "Command execute timeout");
1083 return PM3_ETIMEOUT
;
1086 if (resp
.oldarg
[0] == 0) { // ats_len
1088 PrintAndLogEx(FAILED
, "Can't get ATS");
1090 return PM3_ECARDEXCHANGE
;
1093 // get frame length from ATS in data field
1094 if (resp
.oldarg
[0] > 1) {
1095 uint8_t fsci
= resp
.data
.asBytes
[1] & 0x0f;
1096 if (fsci
< ARRAYLEN(atsFSC
)) {
1097 gs_frame_len
= atsFSC
[fsci
];
1102 card
->ats_len
= resp
.oldarg
[0];
1103 memcpy(card
->ats
, resp
.data
.asBytes
, card
->ats_len
);
1106 // get frame length from ATS in card data structure
1107 if (vcard
->ats_len
> 1) {
1108 uint8_t fsci
= vcard
->ats
[1] & 0x0f;
1109 if (fsci
< ARRAYLEN(atsFSC
)) {
1110 gs_frame_len
= atsFSC
[fsci
];
1115 SetISODEPState(ISODEP_NFCA
);
1124 int SelectCard14443A_4(bool disconnect
, bool verbose
, iso14a_card_select_t
*card
) {
1125 return SelectCard14443A_4_WithParameters(disconnect
, verbose
, card
, NULL
);
1128 static int CmdExchangeAPDU(bool chainingin
, const uint8_t *datain
, int datainlen
, bool activateField
, uint8_t *dataout
, int maxdataoutlen
, int *dataoutlen
, bool *chainingout
) {
1129 *chainingout
= false;
1131 size_t timeout
= 1500;
1132 if (activateField
) {
1133 // select with no disconnect and set gs_frame_len
1134 iso14a_card_select_t card
;
1135 int selres
= SelectCard14443A_4(false, true, &card
);
1136 if (selres
!= PM3_SUCCESS
) {
1140 // Extract FWI and SFGI from ATS and increase timeout by the indicated values
1141 // for most cards these values are trivially small so will make no practical
1142 // difference but some "cards" like hf_cardhopper overwrite these to their
1143 // maximum values resulting in ~5 seconds each which can cause timeouts if we
1145 if (((card
.ats
[1] & 0x20) == 0x20) && card
.ats_len
> 2) {
1146 // TB is present in ATS
1149 if ((card
.ats
[1] & 0x10) == 0x10 && card
.ats_len
> 3) {
1150 // TA is also present, so TB at ats[3]
1153 // TA is not present, so TB is at ats[2]
1157 uint8_t fwi
= (tb
& 0xF0) >> 4;
1159 uint32_t fwt
= 256 * 16 * (1 << fwi
);
1163 uint8_t sfgi
= tb
& 0x0F;
1165 uint32_t sgft
= 256 * 16 * (1 << sfgi
);
1173 cmdc
= ISO14A_SEND_CHAINING
;
1175 // "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
1176 // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
1177 // here length PM3_CMD_DATA_SIZE=512
1178 // timeout must be authomatically set by "get ATS"
1180 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_APDU
| ISO14A_NO_DISCONNECT
| cmdc
, (datainlen
& 0x1FF), 0, datain
, datainlen
& 0x1FF);
1182 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_APDU
| ISO14A_NO_DISCONNECT
| cmdc
, 0, 0, NULL
, 0);
1184 PacketResponseNG resp
;
1186 if (WaitForResponseTimeout(CMD_ACK
, &resp
, timeout
)) {
1187 const uint8_t *recv
= resp
.data
.asBytes
;
1188 int iLen
= resp
.oldarg
[0];
1189 uint8_t res
= resp
.oldarg
[1];
1191 int dlen
= iLen
- 2;
1194 *dataoutlen
+= dlen
;
1196 if (maxdataoutlen
&& *dataoutlen
> maxdataoutlen
) {
1197 PrintAndLogEx(DEBUG
, "ERR: APDU: Buffer too small(%d), needs %d bytes", *dataoutlen
, maxdataoutlen
);
1198 return PM3_EAPDU_FAIL
;
1202 if ((res
& 0xF2) == 0xA2) {
1204 *chainingout
= true;
1209 PrintAndLogEx(DEBUG
, "ERR: APDU: No APDU response");
1210 return PM3_EAPDU_FAIL
;
1213 // check apdu length
1214 if (iLen
< 2 && iLen
>= 0) {
1215 PrintAndLogEx(DEBUG
, "ERR: APDU: Small APDU response, len %d", iLen
);
1216 return PM3_EAPDU_FAIL
;
1221 PrintAndLogEx(DEBUG
, "ERR: APDU: Block type mismatch");
1222 return PM3_EAPDU_FAIL
;
1225 memcpy(dataout
, recv
, dlen
);
1228 if ((res
& 0x10) != 0) {
1229 *chainingout
= true;
1234 PrintAndLogEx(DEBUG
, "ERR: APDU: ISO 14443A CRC error");
1235 return PM3_EAPDU_FAIL
;
1238 PrintAndLogEx(DEBUG
, "ERR: APDU: Reply timeout");
1239 return PM3_EAPDU_FAIL
;
1245 int ExchangeAPDU14a(const uint8_t *datain
, int datainlen
, bool activateField
, bool leaveSignalON
, uint8_t *dataout
, int maxdataoutlen
, int *dataoutlen
) {
1247 bool chaining
= false;
1250 // 3 byte here - 1b framing header, 2b crc16
1251 if (g_apdu_in_framing_enable
&&
1252 ((gs_frame_len
&& (datainlen
> gs_frame_len
- 3)) || (datainlen
> PM3_CMD_DATA_SIZE
- 3))) {
1256 bool vActivateField
= activateField
;
1259 int vlen
= MIN(gs_frame_len
- 3, datainlen
- clen
);
1260 bool chainBlockNotLast
= ((clen
+ vlen
) < datainlen
);
1263 res
= CmdExchangeAPDU(chainBlockNotLast
, &datain
[clen
], vlen
, vActivateField
, dataout
, maxdataoutlen
, dataoutlen
, &chaining
);
1264 if (res
!= PM3_SUCCESS
) {
1265 if (leaveSignalON
== false)
1271 // check R-block ACK
1272 // TODO check this one...
1273 if ((*dataoutlen
== 0) && (chaining
!= chainBlockNotLast
)) {
1274 if (leaveSignalON
== false)
1281 vActivateField
= false;
1283 if (clen
!= datainlen
) {
1284 PrintAndLogEx(ERR
, "APDU: I-block/R-block sequence error. Data len=%d, Sent=%d, Last packet len=%d", datainlen
, clen
, *dataoutlen
);
1288 } while (clen
< datainlen
);
1291 res
= CmdExchangeAPDU(false, datain
, datainlen
, activateField
, dataout
, maxdataoutlen
, dataoutlen
, &chaining
);
1292 if (res
!= PM3_SUCCESS
) {
1293 if (leaveSignalON
== false) {
1301 // I-block with chaining
1302 res
= CmdExchangeAPDU(false, NULL
, 0, false, &dataout
[*dataoutlen
], maxdataoutlen
, dataoutlen
, &chaining
);
1303 if (res
!= PM3_SUCCESS
) {
1304 if (leaveSignalON
== false) {
1311 if (leaveSignalON
== false) {
1318 // ISO14443-4. 7. Half-duplex block transmission protocol
1319 static int CmdHF14AAPDU(const char *Cmd
) {
1320 CLIParserContext
*ctx
;
1321 CLIParserInit(&ctx
, "hf 14a apdu",
1322 "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL).\n"
1323 "Works with all APDU types from ISO 7816-4:2013\n"
1326 " `-m` and `-d` goes hand in hand\n"
1327 " -m <CLA INS P1 P2> -d 325041592E5359532E4444463031\n"
1331 " use `-d` with complete APDU data\n"
1332 " -d 00A404000E325041592E5359532E444446303100",
1333 "hf 14a apdu -st -d 00A404000E325041592E5359532E444446303100\n"
1334 "hf 14a apdu -sd -d 00A404000E325041592E5359532E444446303100 -> decode apdu\n"
1335 "hf 14a apdu -sm 00A40400 -d 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n"
1336 "hf 14a apdu -sm 00A40400 -d 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n");
1338 void *argtable
[] = {
1340 arg_lit0("s", "select", "activate field and select card"),
1341 arg_lit0("k", "keep", "keep signal field ON after receive"),
1342 arg_lit0("t", "tlv", "decode TLV"),
1343 arg_lit0(NULL
, "decode", "decode APDU request"),
1344 arg_str0("m", "make", "<hex>", "APDU header, 4 bytes <CLA INS P1 P2>"),
1345 arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
1346 arg_int0("l", "le", "<dec>", "Le APDU parameter if `m` parameter included"),
1347 arg_strx1("d", "data", "<hex>", "full APDU package or data if `m` parameter included"),
1350 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1352 bool activateField
= arg_get_lit(ctx
, 1);
1353 bool leaveSignalON
= arg_get_lit(ctx
, 2);
1354 bool decodeTLV
= arg_get_lit(ctx
, 3);
1355 bool decodeAPDU
= arg_get_lit(ctx
, 4);
1357 uint8_t header
[PM3_CMD_DATA_SIZE
];
1359 CLIGetHexWithReturn(ctx
, 5, header
, &headerlen
);
1361 bool makeAPDU
= (headerlen
> 0);
1363 if (makeAPDU
&& headerlen
!= 4) {
1364 PrintAndLogEx(ERR
, "header length must be 4 bytes instead of %d", headerlen
);
1368 bool extendedAPDU
= arg_get_lit(ctx
, 6);
1369 int le
= arg_get_int_def(ctx
, 7, 0);
1371 uint8_t data
[PM3_CMD_DATA_SIZE
];
1375 uint8_t apdudata
[PM3_CMD_DATA_SIZE
] = {0};
1376 int apdudatalen
= 0;
1378 CLIGetHexBLessWithReturn(ctx
, 8, apdudata
, &apdudatalen
, 1 + 2);
1381 apdu
.cla
= header
[0];
1382 apdu
.ins
= header
[1];
1383 apdu
.p1
= header
[2];
1384 apdu
.p2
= header
[3];
1386 apdu
.lc
= apdudatalen
;
1387 apdu
.data
= apdudata
;
1389 apdu
.extended_apdu
= extendedAPDU
;
1392 if (APDUEncode(&apdu
, data
, &datalen
)) {
1393 PrintAndLogEx(ERR
, "can't make apdu with provided parameters.");
1400 PrintAndLogEx(ERR
, "make mode not set but here `e` option.");
1405 PrintAndLogEx(ERR
, "make mode not set but here `l` option.");
1410 // len = data + PCB(1b) + CRC(2b)
1411 CLIGetHexBLessWithReturn(ctx
, 8, data
, &datalen
, 1 + 2);
1415 PrintAndLogEx(SUCCESS
, _YELLOW_("%s%s%s"),
1416 activateField
? "select card" : "",
1417 leaveSignalON
? ", keep field on" : "",
1418 decodeTLV
? ", TLV" : ""
1420 PrintAndLogEx(SUCCESS
, ">>> %s", sprint_hex_inrow(data
, datalen
));
1425 if (APDUDecode(data
, datalen
, &apdu
) == 0)
1428 PrintAndLogEx(WARNING
, "can't decode APDU.");
1431 int res
= ExchangeAPDU14a(data
, datalen
, activateField
, leaveSignalON
, data
, PM3_CMD_DATA_SIZE
, &datalen
);
1432 if (res
!= PM3_SUCCESS
)
1435 PrintAndLogEx(SUCCESS
, "<<< %s | %s", sprint_hex_inrow(data
, datalen
), sprint_ascii(data
, datalen
));
1436 PrintAndLogEx(SUCCESS
, "<<< status: %02X %02X - %s", data
[datalen
- 2], data
[datalen
- 1], GetAPDUCodeDescription(data
[datalen
- 2], data
[datalen
- 1]));
1439 if (decodeTLV
&& datalen
> 4) {
1440 TLVPrintFromBuffer(data
, datalen
- 2);
1446 static int CmdHF14ACmdRaw(const char *Cmd
) {
1447 CLIParserContext
*ctx
;
1448 CLIParserInit(&ctx
, "hf 14a raw",
1449 "Sends raw bytes over ISO14443a. With option to use TOPAZ 14a mode.",
1450 "hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'\n"
1451 "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40\n"
1452 "hf 14a raw --ecp -s -> send ECP before select"
1455 void *argtable
[] = {
1457 arg_lit0("a", NULL
, "Active signal field ON without select"),
1458 arg_lit0("c", NULL
, "Calculate and append CRC"),
1459 arg_lit0("k", NULL
, "Keep signal field ON after receive"),
1460 arg_lit0("3", NULL
, "ISO14443-3 select only (skip RATS)"),
1461 arg_lit0("r", NULL
, "Do not read response"),
1462 arg_lit0("s", NULL
, "Active signal field ON with select"),
1463 arg_int0("t", "timeout", "<ms>", "Timeout in milliseconds"),
1464 arg_int0("b", NULL
, "<dec>", "Number of bits to send. Useful for send partial byte"),
1465 arg_lit0("v", "verbose", "Verbose output"),
1466 arg_lit0(NULL
, "ecp", "Use enhanced contactless polling"),
1467 arg_lit0(NULL
, "mag", "Use Apple magsafe polling"),
1468 arg_lit0(NULL
, "topaz", "Use Topaz protocol to send command"),
1469 arg_strx1(NULL
, NULL
, "<hex>", "Raw bytes to send"),
1472 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1474 bool active
= arg_get_lit(ctx
, 1);
1475 bool crc
= arg_get_lit(ctx
, 2);
1476 bool keep_field_on
= arg_get_lit(ctx
, 3);
1477 bool no_rats
= arg_get_lit(ctx
, 4);
1478 bool reply
= (arg_get_lit(ctx
, 5) == false);
1479 bool active_select
= arg_get_lit(ctx
, 6);
1480 uint32_t timeout
= (uint32_t)arg_get_int_def(ctx
, 7, 0);
1481 uint16_t numbits
= (uint16_t)arg_get_int_def(ctx
, 8, 0);
1482 bool verbose
= arg_get_lit(ctx
, 9);
1483 bool use_ecp
= arg_get_lit(ctx
, 10);
1484 bool use_magsafe
= arg_get_lit(ctx
, 11);
1485 bool topazmode
= arg_get_lit(ctx
, 12);
1488 uint8_t data
[PM3_CMD_DATA_SIZE_MIX
] = {0};
1489 CLIGetHexWithReturn(ctx
, 13, data
, &datalen
);
1492 bool bTimeout
= (timeout
) ? true : false;
1494 // ensure we can add 2byte crc to input data
1495 if (datalen
>= sizeof(data
) + 2) {
1497 PrintAndLogEx(FAILED
, "Buffer is full, we can't add CRC to your data");
1502 if (crc
&& datalen
> 0 && datalen
< sizeof(data
) - 2) {
1503 uint8_t first
, second
;
1505 compute_crc(CRC_14443_B
, data
, datalen
, &first
, &second
);
1507 compute_crc(CRC_14443_A
, data
, datalen
, &first
, &second
);
1509 data
[datalen
++] = first
;
1510 data
[datalen
++] = second
;
1514 if (active
|| active_select
) {
1515 flags
|= ISO14A_CONNECT
;
1517 flags
|= ISO14A_NO_SELECT
;
1520 uint32_t argtimeout
= 0;
1522 #define MAX_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s
1523 flags
|= ISO14A_SET_TIMEOUT
;
1524 if (timeout
> MAX_TIMEOUT
) {
1525 timeout
= MAX_TIMEOUT
;
1526 PrintAndLogEx(INFO
, "Set timeout to 40542 seconds (11.26 hours). The max we can wait for response");
1528 argtimeout
= 13560000 / 1000 / (8 * 16) * timeout
; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
1531 if (keep_field_on
) {
1532 flags
|= ISO14A_NO_DISCONNECT
;
1536 flags
|= ISO14A_RAW
;
1540 flags
|= ISO14A_TOPAZMODE
;
1544 flags
|= ISO14A_NO_RATS
;
1547 // TODO: allow to use reader command with both data and polling configuration
1548 if (use_ecp
|| use_magsafe
) {
1549 PrintAndLogEx(WARNING
, "ECP and Magsafe not supported with this command at this moment. Instead use 'hf 14a reader -sk --ecp/--mag'");
1550 // flags |= ISO14A_USE_MAGSAFE;
1551 // flags |= ISO14A_USE_ECP;
1554 // Max buffer is PM3_CMD_DATA_SIZE_MIX
1555 datalen
= (datalen
> PM3_CMD_DATA_SIZE_MIX
) ? PM3_CMD_DATA_SIZE_MIX
: datalen
;
1557 clearCommandBuffer();
1558 SendCommandMIX(CMD_HF_ISO14443A_READER
, flags
, (datalen
& 0x1FF) | ((uint32_t)(numbits
<< 16)), argtimeout
, data
, datalen
);
1563 res
= waitCmd(true, timeout
, verbose
);
1564 if (res
== PM3_SUCCESS
&& datalen
> 0)
1565 waitCmd(false, timeout
, verbose
);
1570 static int waitCmd(bool i_select
, uint32_t timeout
, bool verbose
) {
1571 PacketResponseNG resp
;
1573 if (WaitForResponseTimeout(CMD_ACK
, &resp
, timeout
+ 1500)) {
1574 uint16_t len
= (resp
.oldarg
[0] & 0xFFFF);
1576 len
= (resp
.oldarg
[1] & 0xFFFF);
1579 PrintAndLogEx(SUCCESS
, "Card selected. UID[%u]:", len
);
1585 PrintAndLogEx(WARNING
, "Can't select card.");
1589 PrintAndLogEx(SUCCESS
, "received " _YELLOW_("%u") " bytes", len
);
1597 uint8_t *data
= resp
.data
.asBytes
;
1599 if (i_select
== false && len
>= 3) {
1600 bool crc
= check_crc(CRC_14443_A
, data
, len
);
1605 (crc
) ? _GREEN_("%02X %02X") : _RED_("%02X %02X"),
1610 PrintAndLogEx(SUCCESS
, "%s[ %s ]", sprint_hex(data
, len
- 2), s
);
1612 PrintAndLogEx(SUCCESS
, "%s", sprint_hex(data
, len
));
1616 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
1617 return PM3_ETIMEOUT
;
1622 static int CmdHF14AAntiFuzz(const char *Cmd
) {
1624 CLIParserContext
*ctx
;
1625 CLIParserInit(&ctx
, "hf 14a antifuzz",
1626 "Tries to fuzz the ISO14443a anticollision phase",
1627 "hf 14a antifuzz -4\n");
1629 void *argtable
[] = {
1631 arg_lit0("4", NULL
, "4 byte uid"),
1632 arg_lit0("7", NULL
, "7 byte uid"),
1633 arg_lit0(NULL
, "10", "10 byte uid"),
1636 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1641 param
.flag
= FLAG_4B_UID_IN_DATA
;
1643 if (arg_get_lit(ctx
, 2))
1644 param
.flag
= FLAG_7B_UID_IN_DATA
;
1645 if (arg_get_lit(ctx
, 3))
1646 param
.flag
= FLAG_10B_UID_IN_DATA
;
1649 clearCommandBuffer();
1650 SendCommandNG(CMD_HF_ISO14443A_ANTIFUZZ
, (uint8_t *)¶m
, sizeof(param
));
1654 static int CmdHF14AChaining(const char *Cmd
) {
1656 CLIParserContext
*ctx
;
1657 CLIParserInit(&ctx
, "hf 14a chaining",
1658 "Enable/Disable ISO14443a input chaining. Maximum input length goes from ATS.",
1659 "hf 14a chaining -> show chaining enable/disable state\n"
1660 "hf 14a chaining --off -> disable chaining\n"
1663 void *argtable
[] = {
1665 arg_lit0("1", "on", "enabled chaining"),
1666 arg_lit0("0", "off", "disable chaining"),
1669 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1671 bool on
= arg_get_lit(ctx
, 1);
1672 bool off
= arg_get_lit(ctx
, 2);
1675 if ((on
+ off
) > 1) {
1676 PrintAndLogEx(INFO
, "Select only one option");
1681 Set_apdu_in_framing(true);
1684 Set_apdu_in_framing(false);
1686 PrintAndLogEx(INFO
, "\nISO 14443-4 input chaining %s.\n", g_apdu_in_framing_enable
? "enabled" : "disabled");
1690 static void printTag(const char *tag
) {
1691 PrintAndLogEx(SUCCESS
, " " _YELLOW_("%s"), tag
);
1694 int detect_nxp_card(uint8_t sak
, uint16_t atqa
, uint64_t select_status
) {
1698 if ((sak
& 0x02) != 0x02) {
1699 if ((sak
& 0x19) == 0x19) {
1701 } else if ((sak
& 0x40) == 0x40) {
1703 } else if ((sak
& 0x38) == 0x38) {
1705 } else if ((sak
& 0x18) == 0x18) {
1706 if (select_status
== 1) {
1711 } else if ((sak
& 0x09) == 0x09) {
1713 } else if ((sak
& 0x28) == 0x28) {
1715 } else if ((sak
& 0x08) == 0x08) {
1716 if (select_status
== 1) {
1721 } else if ((sak
& 0x11) == 0x11) {
1723 } else if ((sak
& 0x10) == 0x10) {
1725 } else if ((sak
& 0x01) == 0x01) {
1727 } else if ((sak
& 0x24) == 0x24) {
1729 } else if ((sak
& 0x20) == 0x20) {
1730 if (select_status
== 1) {
1731 if ((atqa
& 0x0040) == 0x0040) {
1732 if ((atqa
& 0x0300) == 0x0300) {
1739 if ((atqa
& 0x0001) == 0x0001) {
1745 if ((atqa
& 0x0004) == 0x0004) {
1749 type
|= (MTDESFIRE
| MT424
);
1751 } else if ((sak
& 0x04) == 0x04) {
1754 type
|= MTULTRALIGHT
;
1756 } else if ((sak
& 0x0A) == 0x0A) {
1758 if ((atqa
& 0x0003) == 0x0003) {
1760 } else if ((atqa
& 0x0005) == 0x0005) {
1763 } else if ((sak
& 0x53) == 0x53) {
1771 // Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1
1772 static int detect_nxp_card_print(uint8_t sak
, uint16_t atqa
, uint64_t select_status
) {
1775 PrintAndLogEx(SUCCESS
, "Possible types:");
1777 if ((sak
& 0x02) != 0x02) {
1778 if ((sak
& 0x19) == 0x19) {
1779 printTag("MIFARE Classic 2K");
1781 } else if ((sak
& 0x40) == 0x40) {
1782 if ((atqa
& 0x0110) == 0x0110)
1783 printTag("P2P Support / Proprietary");
1785 printTag("P2P Support / Android");
1788 } else if ((sak
& 0x38) == 0x38) {
1789 printTag("SmartMX with MIFARE Classic 4K");
1791 } else if ((sak
& 0x18) == 0x18) {
1792 if (select_status
== 1) {
1793 if ((atqa
& 0x0040) == 0x0040) {
1794 printTag("MIFARE Plus EV1 4K CL2 in SL1");
1795 printTag("MIFARE Plus S 4K CL2 in SL1");
1796 printTag("MIFARE Plus X 4K CL2 in SL1");
1798 printTag("MIFARE Plus EV1 4K in SL1");
1799 printTag("MIFARE Plus S 4K in SL1");
1800 printTag("MIFARE Plus X 4K in SL1");
1805 if ((atqa
& 0x0040) == 0x0040) {
1806 printTag("MIFARE Classic 4K CL2");
1808 printTag("MIFARE Classic 4K");
1813 } else if ((sak
& 0x09) == 0x09) {
1814 if ((atqa
& 0x0040) == 0x0040) {
1815 printTag("MIFARE Mini 0.3K CL2");
1817 printTag("MIFARE Mini 0.3K");
1821 } else if ((sak
& 0x28) == 0x28) {
1822 printTag("SmartMX with MIFARE Classic 1K");
1824 } else if ((sak
& 0x08) == 0x08) {
1825 if (select_status
== 1) {
1826 if ((atqa
& 0x0040) == 0x0040) {
1827 printTag("MIFARE Plus EV1 2K CL2 in SL1");
1828 printTag("MIFARE Plus S 2K CL2 in SL1");
1829 printTag("MIFARE Plus X 2K CL2 in SL1");
1830 printTag("MIFARE Plus SE 1K CL2");
1832 printTag("MIFARE Plus EV1 2K in SL1");
1833 printTag("MIFARE Plus S 2K in SL1");
1834 printTag("MIFARE Plus X 2K in SL1");
1835 printTag("MIFARE Plus SE 1K");
1840 if ((atqa
& 0x0040) == 0x0040) {
1841 printTag("MIFARE Classic 1K CL2");
1843 printTag("MIFARE Classic 1K");
1848 } else if ((sak
& 0x11) == 0x11) {
1849 printTag("MIFARE Plus 4K in SL2");
1851 } else if ((sak
& 0x10) == 0x10) {
1852 printTag("MIFARE Plus 2K in SL2");
1854 } else if ((sak
& 0x01) == 0x01) {
1855 printTag("TNP3xxx (TagNPlay, Activision Game Appliance)");
1857 } else if ((sak
& 0x24) == 0x24) {
1858 printTag("MIFARE DESFire CL1");
1859 printTag("MIFARE DESFire EV1 CL1");
1861 } else if ((sak
& 0x20) == 0x20) {
1862 if (select_status
== 1) {
1863 if ((atqa
& 0x0040) == 0x0040) {
1864 if ((atqa
& 0x0300) == 0x0300) {
1865 printTag("MIFARE DESFire CL2");
1866 printTag("MIFARE DESFire EV1 256B/2K/4K/8K CL2");
1867 printTag("MIFARE DESFire EV2 2K/4K/8K/16K/32K");
1868 printTag("MIFARE DESFire EV3 2K/4K/8K");
1869 printTag("MIFARE DESFire Light 640B");
1872 printTag("MIFARE Plus EV1 2K/4K CL2 in SL3");
1873 printTag("MIFARE Plus S 2K/4K CL2 in SL3");
1874 printTag("MIFARE Plus X 2K/4K CL2 in SL3");
1875 printTag("MIFARE Plus SE 1K CL2");
1880 if ((atqa
& 0x0001) == 0x0001) {
1881 printTag("HID SEOS (smartmx / javacard)");
1884 printTag("MIFARE Plus EV1 2K/4K in SL3");
1885 printTag("MIFARE Plus S 2K/4K in SL3");
1886 printTag("MIFARE Plus X 2K/4K in SL3");
1887 printTag("MIFARE Plus SE 1K");
1891 if ((atqa
& 0x0004) == 0x0004) {
1897 printTag("NTAG 4xx");
1898 type
|= (MTDESFIRE
| MT424
);
1900 } else if ((sak
& 0x04) == 0x04) {
1901 printTag("Any MIFARE CL1");
1904 printTag("MIFARE Ultralight");
1905 printTag("MIFARE Ultralight C");
1906 printTag("MIFARE Ultralight EV1");
1907 printTag("MIFARE Ultralight Nano");
1908 printTag("MIFARE Ultralight AES");
1909 printTag("MIFARE Hospitality");
1910 printTag("NTAG 2xx");
1911 type
|= MTULTRALIGHT
;
1913 } else if ((sak
& 0x0A) == 0x0A) {
1915 if ((atqa
& 0x0003) == 0x0003) {
1916 // Uses Shanghai algo
1917 printTag("FM11RF005SH (FUDAN Shanghai Metro)");
1919 } else if ((atqa
& 0x0005) == 0x0005) {
1920 printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)");
1923 } else if ((sak
& 0x53) == 0x53) {
1924 printTag("FM11RF08SH (FUDAN)");
1928 if (type
== MTNONE
) {
1929 PrintAndLogEx(WARNING
, " failed to fingerprint");
1940 static const uid_label_name_t uid_label_map
[] = {
1942 {0x02, 0x84, "M24SR64-Y"},
1943 {0x02, 0xA3, "25TA02KB-P"},
1944 {0x02, 0xC4, "25TA64K"},
1945 {0x02, 0xE3, "25TA02KB"},
1946 {0x02, 0xE4, "25TA512B"},
1947 {0x02, 0xF3, "25TA02KB-D"},
1948 {0x11, 0x22, "NTAG21x Modifiable"},
1949 {0x00, 0x00, "None"}
1952 static void getTagLabel(uint8_t uid0
, uint8_t uid1
) {
1954 while (uid_label_map
[i
].uid0
!= 0x00) {
1955 if ((uid_label_map
[i
].uid0
== uid0
) && (uid_label_map
[i
].uid1
== uid1
)) {
1956 PrintAndLogEx(SUCCESS
, _YELLOW_(" %s"), uid_label_map
[i
].desc
);
1963 static void get_compact_tlv(uint8_t *d
, uint8_t n
) {
1968 uint8_t tag
= NIBBLE_HIGH(d
[0]);
1969 uint8_t len
= NIBBLE_LOW(d
[0]);
1973 PrintAndLogEx(INFO
, " %1x%1x " _YELLOW_("%s") " Country code in (ISO 3166-1)", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
1974 // iso3166 script in cmdlffdb.c is buggy, Ã…land, Australia not showing. getline issues
1977 PrintAndLogEx(INFO
, " %1x%1x " _YELLOW_("%s") " Issuer identification number (ISO 7812-1)", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
1980 PrintAndLogEx(INFO
, " %1x%1x " _YELLOW_("%s") " Card service data byte", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
1981 PrintAndLogEx(INFO
, " %c....... Application selection: by full DF name", (d
[1] & 0x80) ? '1' : '0');
1982 PrintAndLogEx(INFO
, " .%c...... Application selection: by partial DF name", (d
[1] & 0x40) ? '1' : '0');
1983 PrintAndLogEx(INFO
, " ..%c..... BER-TLV data objects available in EF.DIR", (d
[1] & 0x20) ? '1' : '0');
1984 PrintAndLogEx(INFO
, " ...%c.... BER-TLV data objects available in EF.ATR", (d
[1] & 0x10) ? '1' : '0');
1985 PrintAndLogEx(INFO
, " ....%c... EF.DIR and EF.ATR access services: by READ BINARY command", (d
[1] & 0x08) ? '1' : '0');
1986 PrintAndLogEx(INFO
, " .....%c.. EF.DIR and EF.ATR access services: by GET DATA command", (d
[1] & 0x04) ? '1' : '0');
1987 PrintAndLogEx(INFO
, " ......%c. EF.DIR and EF.ATR access services: by GET RECORD(s) command", (d
[1] & 0x02) ? '1' : '0');
1988 PrintAndLogEx(INFO
, " .......%c EF.DIR and EF.ATR access services: RFU", (d
[1] & 0x01) ? '1' : '0');
1991 PrintAndLogEx(INFO
, " %1x%1x " _YELLOW_("%s") " Initial access data", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
1994 PrintAndLogEx(INFO
, " %1x%1x " _YELLOW_("%s") " Card issuer data", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
1997 PrintAndLogEx(INFO
, " %1x%1x " _YELLOW_("%s") " Pre-issuing data", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
2000 PrintAndLogEx(INFO
, " %1x%1x " _YELLOW_("%s") " Card capabilities", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
2002 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") " - Selection methods", d
[1]);
2003 PrintAndLogEx(INFO
, " %c....... DF selection by full DF name", (d
[1] & 0x80) ? '1' : '0');
2004 PrintAndLogEx(INFO
, " .%c...... DF selection by partial DF name", (d
[1] & 0x40) ? '1' : '0');
2005 PrintAndLogEx(INFO
, " ..%c..... DF selection by path", (d
[1] & 0x20) ? '1' : '0');
2006 PrintAndLogEx(INFO
, " ...%c.... DF selection by file identifier", (d
[1] & 0x10) ? '1' : '0');
2007 PrintAndLogEx(INFO
, " ....%c... Implicit DF selection", (d
[1] & 0x08) ? '1' : '0');
2008 PrintAndLogEx(INFO
, " .....%c.. Short EF identifier supported", (d
[1] & 0x04) ? '1' : '0');
2009 PrintAndLogEx(INFO
, " ......%c. Record number supported", (d
[1] & 0x02) ? '1' : '0');
2010 PrintAndLogEx(INFO
, " .......%c Record identifier supported", (d
[1] & 0x01) ? '1' : '0');
2013 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") " - Data coding byte", d
[2]);
2016 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") " - Command chaining, length fields and logical channels", d
[3]);
2020 PrintAndLogEx(INFO
, " %1x%1x ... " _YELLOW_("%s") " Status indicator", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
2023 PrintAndLogEx(INFO
, " %1x%1x ... " _YELLOW_("%s") " Application identifier", tag
, len
, sprint_hex_inrow(d
+ 1, len
));
2035 int infoHF14A(bool verbose
, bool do_nack_test
, bool do_aid_search
) {
2037 uint8_t dbg_curr
= DBG_NONE
;
2038 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
2042 clearCommandBuffer();
2043 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_DISCONNECT
, 0, 0, NULL
, 0);
2044 PacketResponseNG resp
;
2045 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
2046 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
2051 iso14a_card_select_t card
;
2052 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
2058 3: proprietary Anticollision
2060 uint64_t select_status
= resp
.oldarg
[0];
2062 if (select_status
== 0) {
2063 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
2065 return select_status
;
2068 PrintAndLogEx(NORMAL
, "");
2070 if (select_status
== 3) {
2071 PrintAndLogEx(INFO
, "Card doesn't support standard iso14443-3 anticollision");
2074 PrintAndLogEx(SUCCESS
, "ATQA: %02X %02X", card
.atqa
[1], card
.atqa
[0]);
2078 if (card
.atqa
[1] == 0x0C && card
.atqa
[0] == 0x00) {
2079 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`hf topaz info`"));
2083 return select_status
;
2087 PrintAndLogEx(INFO
, "--- " _CYAN_("ISO14443-a Information") "---------------------");
2090 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s") " %s", sprint_hex(card
.uid
, card
.uidlen
), get_uid_type(&card
));
2091 PrintAndLogEx(SUCCESS
, "ATQA: " _GREEN_("%02X %02X"), card
.atqa
[1], card
.atqa
[0]);
2092 PrintAndLogEx(SUCCESS
, " SAK: " _GREEN_("%02X [%" PRIu64
"]"), card
.sak
, resp
.oldarg
[0]);
2094 bool isMifareMini
= false;
2095 bool isMifareClassic
= true;
2096 bool isMifareDESFire
= false;
2097 bool isMifarePlus
= false;
2098 bool isMifareUltralight
= false;
2101 bool isFUDAN
= false;
2102 bool isISO18092
= false;
2103 bool isNTAG424
= false;
2104 bool isSEOS
= false;
2105 int nxptype
= MTNONE
;
2107 if (card
.uidlen
<= 4) {
2108 nxptype
= detect_nxp_card_print(card
.sak
, ((card
.atqa
[1] << 8) + card
.atqa
[0]), select_status
);
2110 isMifareMini
= ((nxptype
& MTMINI
) == MTMINI
);
2111 isMifareClassic
= ((nxptype
& MTCLASSIC
) == MTCLASSIC
);
2112 isMifareDESFire
= ((nxptype
& MTDESFIRE
) == MTDESFIRE
);
2113 isMifarePlus
= ((nxptype
& MTPLUS
) == MTPLUS
);
2114 isMifareUltralight
= ((nxptype
& MTULTRALIGHT
) == MTULTRALIGHT
);
2115 isNTAG424
= ((nxptype
& MT424
) == MT424
);
2116 isFUDAN
= ((nxptype
& MTFUDAN
) == MTFUDAN
);
2117 isEMV
= ((nxptype
& MTEMV
) == MTEMV
);
2118 isISO18092
= ((nxptype
& MTISO18092
) == MTISO18092
);
2119 isSEOS
= ((nxptype
& HID_SEOS
) == HID_SEOS
);
2121 // generic catch, we assume MIFARE Classic for all unknown ISO14443a tags
2122 isMifareClassic
|= ((nxptype
& MTOTHER
) == MTOTHER
);
2126 // Double & triple sized UID, can be mapped to a manufacturer.
2127 PrintAndLogEx(SUCCESS
, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card
.uid
[0]));
2129 switch (card
.uid
[0]) {
2132 isMifareClassic
= false;
2135 nxptype
= detect_nxp_card_print(card
.sak
, ((card
.atqa
[1] << 8) + card
.atqa
[0]), select_status
);
2137 isMifareMini
= ((nxptype
& MTMINI
) == MTMINI
);
2138 isMifareClassic
= ((nxptype
& MTCLASSIC
) == MTCLASSIC
);
2139 isMifareDESFire
= ((nxptype
& MTDESFIRE
) == MTDESFIRE
);
2140 isMifarePlus
= ((nxptype
& MTPLUS
) == MTPLUS
);
2141 isMifareUltralight
= ((nxptype
& MTULTRALIGHT
) == MTULTRALIGHT
);
2142 isNTAG424
= ((nxptype
& MT424
) == MT424
);
2144 if ((nxptype
& MTOTHER
) == MTOTHER
)
2145 isMifareClassic
= true;
2147 if ((nxptype
& MTFUDAN
) == MTFUDAN
)
2150 if ((nxptype
& MTEMV
) == MTEMV
)
2154 case 0x05: // Infineon
2155 if ((card
.uid
[1] & 0xF0) == 0x10) {
2156 printTag("my-d(tm) command set SLE 66R04/16/32P, SLE 66R04/16/32S");
2157 } else if ((card
.uid
[1] & 0xF0) == 0x20) {
2158 printTag("my-d(tm) command set SLE 66R01/16/32P (Type 2 Tag)");
2159 } else if ((card
.uid
[1] & 0xF0) == 0x30) {
2160 printTag("my-d(tm) move lean SLE 66R01P/66R01PN");
2161 } else if ((card
.uid
[1] & 0xF0) == 0x70) {
2162 printTag("my-d(tm) move lean SLE 66R01L");
2164 isMifareUltralight
= true;
2165 isMifareClassic
= false;
2167 if (card
.sak
== 0x88) {
2168 printTag("Infineon MIFARE CLASSIC 1K");
2169 isMifareUltralight
= false;
2170 isMifareClassic
= true;
2172 getTagLabel(card
.uid
[0], card
.uid
[1]);
2175 if (memcmp(card
.uid
, "FSTN10m", 7) == 0) {
2176 isMifareClassic
= false;
2177 printTag("Waveshare NFC-Powered e-Paper 1.54\" (please disregard MANUFACTURER mapping above)");
2181 if (memcmp(card
.uid
, "WSDZ10m", 7) == 0) {
2182 isMifareClassic
= false;
2183 printTag("Waveshare NFC-Powered e-Paper (please disregard MANUFACTURER mapping above)");
2187 getTagLabel(card
.uid
[0], card
.uid
[1]);
2190 isMifareClassic
= false;
2192 // ******** is card of the MFU type (UL/ULC/NTAG/ etc etc)
2195 uint64_t tagT
= GetHF14AMfU_Type();
2196 if (tagT
!= MFU_TT_UL_ERROR
) {
2197 ul_print_type(tagT
, 0);
2198 isMifareUltralight
= true;
2199 printTag("MIFARE Ultralight/C/NTAG Compatible");
2201 printTag("Possible AZTEK (iso14443a compliant)");
2204 // reconnect for further tests
2205 clearCommandBuffer();
2206 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_DISCONNECT
, 0, 0, NULL
, 0);
2207 WaitForResponse(CMD_ACK
, &resp
);
2209 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
2211 select_status
= resp
.oldarg
[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS
2213 if (select_status
== 0) {
2215 return select_status
;
2220 if (card
.atqa
[0] == 0x03) {
2221 // Uses Shanghai algo
2222 printTag("FM11RF005SH (FUDAN Shanghai Metro)");
2224 } else if (card
.atqa
[0] == 0x05) {
2225 // Uses MIFARE Crypto-1 algo
2226 printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)");
2231 printTag("JCOP 31/41");
2235 printTag("JCOP31 or JCOP41 v2.3.1");
2239 printTag("Nokia 6212 or 6131");
2243 printTag("FM11RF08SH (FUDAN)");
2247 printTag("Gemplus MPCOS");
2258 // try to request ATS even if tag claims not to support it
2259 if (select_status
== 2) {
2260 uint8_t rats
[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
2261 clearCommandBuffer();
2262 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_RAW
| ISO14A_APPEND_CRC
| ISO14A_NO_DISCONNECT
, 2, 0, rats
, sizeof(rats
));
2263 WaitForResponse(CMD_ACK
, &resp
);
2265 memcpy(card
.ats
, resp
.data
.asBytes
, resp
.oldarg
[0]);
2266 card
.ats_len
= resp
.oldarg
[0]; // note: ats_len includes CRC Bytes
2267 if (card
.ats_len
> 3)
2271 if (card
.ats_len
>= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
2273 PrintAndLogEx(INFO
, "-------------------------- " _CYAN_("ATS") " --------------------------");
2274 bool ta1
= 0, tb1
= 0, tc1
= 0;
2276 if (select_status
== 2) {
2277 PrintAndLogEx(INFO
, "--> SAK incorrectly claims that card doesn't support RATS <--");
2280 bool bad_ats
= false;
2281 if (card
.ats
[0] != card
.ats_len
- 2) {
2282 PrintAndLogEx(WARNING
, _RED_("ATS may be corrupted."));
2283 PrintAndLogEx(INFO
, "Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card
.ats_len
);
2287 PrintAndLogEx(SUCCESS
, "ATS: " _YELLOW_("%s")"[ %02X %02X ]", sprint_hex(card
.ats
, card
.ats_len
- 2), card
.ats
[card
.ats_len
- 2], card
.ats
[card
.ats_len
- 1]);
2288 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "............... TL length is " _GREEN_("%d") " bytes", card
.ats
[0], card
.ats
[0]);
2290 if (bad_ats
== false) {
2292 if ((card
.ats
[0] > 1) && (card
.ats_len
> 3)) { // there is a format byte (T0)
2293 ta1
= (card
.ats
[1] & 0x10) == 0x10;
2294 tb1
= (card
.ats
[1] & 0x20) == 0x20;
2295 tc1
= (card
.ats
[1] & 0x40) == 0x40;
2296 int16_t fsci
= card
.ats
[1] & 0x0f;
2298 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "............ T0 TA1 is%s present, TB1 is%s present, "
2299 "TC1 is%s present, FSCI is %d (FSC = %d)",
2301 (ta1
? "" : _RED_(" NOT")),
2302 (tb1
? "" : _RED_(" NOT")),
2303 (tc1
? "" : _RED_(" NOT")),
2305 fsci
< ARRAYLEN(atsFSC
) ? atsFSC
[fsci
] : -1
2309 if (ta1
&& (card
.ats_len
> pos
+ 2)) {
2310 char dr
[16], ds
[16];
2311 dr
[0] = ds
[0] = '\0';
2312 if (card
.ats
[pos
] & 0x10) strcat(ds
, "2, ");
2313 if (card
.ats
[pos
] & 0x20) strcat(ds
, "4, ");
2314 if (card
.ats
[pos
] & 0x40) strcat(ds
, "8, ");
2315 if (card
.ats
[pos
] & 0x01) strcat(dr
, "2, ");
2316 if (card
.ats
[pos
] & 0x02) strcat(dr
, "4, ");
2317 if (card
.ats
[pos
] & 0x04) strcat(dr
, "8, ");
2318 if (strlen(ds
) != 0) ds
[strlen(ds
) - 2] = '\0';
2319 if (strlen(dr
) != 0) dr
[strlen(dr
) - 2] = '\0';
2320 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "......... TA1 different divisors are%s supported, "
2321 "DR: [%s], DS: [%s]",
2323 ((card
.ats
[pos
] & 0x80) ? _RED_(" NOT") : ""),
2331 if (tb1
&& (card
.ats_len
> pos
+ 2)) {
2332 uint32_t sfgi
= card
.ats
[pos
] & 0x0F;
2333 uint32_t fwi
= card
.ats
[pos
] >> 4;
2335 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "...... TB1 SFGI = %d (SFGT = %s%d/fc), FWI = " _YELLOW_("%d") " (FWT = %d/fc)",
2338 sfgi
? "" : "(not needed) ",
2339 sfgi
? (1 << 12) << sfgi
: 0,
2346 if (tc1
&& (card
.ats_len
> pos
+ 2)) {
2347 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "... TC1 NAD is%s supported, CID is%s supported",
2349 (card
.ats
[pos
] & 0x01) ? "" : _RED_(" NOT"),
2350 (card
.ats
[pos
] & 0x02) ? "" : _RED_(" NOT")
2355 // ATS - Historial bytes and identify based on it
2356 if ((card
.ats
[0] > pos
) && (card
.ats_len
>= card
.ats
[0] + 2)) {
2359 if (card
.ats
[0] - pos
>= 7) {
2361 snprintf(tip
, sizeof(tip
), " ");
2363 if ((card
.sak
& 0x70) == 0x40) { // and no GetVersion()..
2365 if (memcmp(card
.ats
+ pos
, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
2366 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus X 2K/4K (SL3)");
2368 } else if (memcmp(card
.ats
+ pos
, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
2370 if ((card
.atqa
[0] & 0x02) == 0x02) {
2371 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus S 2K (SL3)");
2372 } else if ((card
.atqa
[0] & 0x04) == 0x04) {
2373 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus S 4K (SL3)");
2376 } else if (memcmp(card
.ats
+ pos
, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) {
2377 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus SE 1K (17pF)");
2379 } else if (memcmp(card
.ats
+ pos
, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) {
2380 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus SE 1K (70pF)");
2383 } else { //SAK B4,5,6
2385 if ((card
.sak
& 0x20) == 0x20) { // and no GetVersion()..
2387 if (memcmp(card
.ats
+ pos
, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
2388 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus X 2K (SL1)");
2389 } else if (memcmp(card
.ats
+ pos
, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
2390 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus S 2K (SL1)");
2391 } else if (memcmp(card
.ats
+ pos
, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) {
2392 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus SE 1K (17pF)");
2393 } else if (memcmp(card
.ats
+ pos
, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) {
2394 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus SE 1K (70pF)");
2397 if (memcmp(card
.ats
+ pos
, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
2398 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus X 4K (SL1)");
2399 } else if (memcmp(card
.ats
+ pos
, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
2400 snprintf(tip
+ strlen(tip
), sizeof(tip
) - strlen(tip
), _GREEN_("%s"), "MIFARE Plus S 4K (SL1)");
2406 uint8_t calen
= card
.ats
[0] - pos
;
2407 PrintAndLogEx(NORMAL
, "");
2408 PrintAndLogEx(INFO
, "-------------------- " _CYAN_("Historical bytes") " --------------------");
2410 if (card
.ats
[pos
] == 0xC1) {
2411 PrintAndLogEx(INFO
, " %s%s", sprint_hex(card
.ats
+ pos
, calen
), tip
);
2412 PrintAndLogEx(SUCCESS
, " C1..................... Mifare or (multiple) virtual cards of various type");
2413 PrintAndLogEx(SUCCESS
, " %02X.................. length is " _YELLOW_("%d") " bytes", card
.ats
[pos
+ 1], card
.ats
[pos
+ 1]);
2414 switch (card
.ats
[pos
+ 2] & 0xf0) {
2416 PrintAndLogEx(SUCCESS
, " 1x............... MIFARE DESFire");
2417 isMifareDESFire
= true;
2418 isMifareClassic
= false;
2419 isMifarePlus
= false;
2422 PrintAndLogEx(SUCCESS
, " 2x............... MIFARE Plus");
2423 isMifarePlus
= true;
2424 isMifareDESFire
= false;
2425 isMifareClassic
= false;
2428 switch (card
.ats
[pos
+ 2] & 0x0f) {
2430 PrintAndLogEx(SUCCESS
, " x0............... < 1 kByte");
2433 PrintAndLogEx(SUCCESS
, " x1............... 1 kByte");
2436 PrintAndLogEx(SUCCESS
, " x2............... 2 kByte");
2439 PrintAndLogEx(SUCCESS
, " x3............... 4 kByte");
2442 PrintAndLogEx(SUCCESS
, " x4............... 8 kByte");
2445 switch (card
.ats
[pos
+ 3] & 0xf0) {
2447 PrintAndLogEx(SUCCESS
, " 0x............ Engineering sample");
2450 PrintAndLogEx(SUCCESS
, " 2x............ Released");
2453 switch (card
.ats
[pos
+ 3] & 0x0f) {
2455 PrintAndLogEx(SUCCESS
, " x0............ Generation 1");
2458 PrintAndLogEx(SUCCESS
, " x1............ Generation 2");
2461 PrintAndLogEx(SUCCESS
, " x2............ Generation 3");
2464 switch (card
.ats
[pos
+ 4] & 0x0f) {
2466 PrintAndLogEx(SUCCESS
, " x0......... Only VCSL supported");
2469 PrintAndLogEx(SUCCESS
, " x1......... VCS, VCSL, and SVC supported");
2472 PrintAndLogEx(SUCCESS
, " xE......... no VCS command supported");
2477 if (card
.ats
[pos
] == 0x80 || card
.ats
[pos
] == 0x00) {
2478 PrintAndLogEx(SUCCESS
, "%s (compact TLV data object)", sprint_hex_inrow(&card
.ats
[pos
], calen
));
2479 get_compact_tlv(card
.ats
+ pos
, calen
);
2481 PrintAndLogEx(SUCCESS
, "%s - %s"
2482 , sprint_hex_inrow(card
.ats
+ pos
, calen
)
2483 , sprint_ascii(card
.ats
+ pos
, calen
)
2487 PrintAndLogEx(NORMAL
, "");
2493 if (do_aid_search
) {
2495 PrintAndLogEx(INFO
, "-------------------- " _CYAN_("AID Search") " --------------------");
2497 json_t
*root
= AIDSearchInit(verbose
);
2500 bool ActivateField
= true;
2501 for (size_t elmindx
= 0; elmindx
< json_array_size(root
); elmindx
++) {
2503 if (kbd_enter_pressed()) {
2507 json_t
*data
= AIDSearchGetElm(root
, elmindx
);
2508 uint8_t vaid
[200] = {0};
2510 if (!AIDGetFromElm(data
, vaid
, sizeof(vaid
), &vaidlen
) || !vaidlen
)
2514 uint8_t result
[1024] = {0};
2515 size_t resultlen
= 0;
2516 int res
= Iso7816Select(CC_CONTACTLESS
, ActivateField
, true, vaid
, vaidlen
, result
, sizeof(result
), &resultlen
, &sw
);
2517 ActivateField
= false;
2521 uint8_t dfname
[200] = {0};
2522 size_t dfnamelen
= 0;
2523 if (resultlen
> 3) {
2524 struct tlvdb
*tlv
= tlvdb_parse_multi(result
, resultlen
);
2526 // 0x84 Dedicated File (DF) Name
2527 const struct tlv
*dfnametlv
= tlvdb_get_tlv(tlvdb_find_full(tlv
, 0x84));
2529 dfnamelen
= dfnametlv
->len
;
2530 memcpy(dfname
, dfnametlv
->value
, dfnamelen
);
2536 if (sw
== ISO7816_OK
|| sw
== ISO7816_INVALID_DF
|| sw
== ISO7816_FILE_TERMINATED
) {
2537 if (sw
== ISO7816_OK
) {
2538 if (verbose
) PrintAndLogEx(SUCCESS
, "Application ( " _GREEN_("ok") " )");
2540 if (verbose
) PrintAndLogEx(WARNING
, "Application ( " _RED_("blocked") " )");
2543 PrintAIDDescriptionBuf(root
, vaid
, vaidlen
, verbose
);
2546 if (dfnamelen
== vaidlen
) {
2547 if (memcmp(dfname
, vaid
, vaidlen
) == 0) {
2548 if (verbose
) PrintAndLogEx(INFO
, "(DF) Name found and equal to AID");
2550 PrintAndLogEx(INFO
, "(DF) Name not equal to AID: %s :", sprint_hex(dfname
, dfnamelen
));
2551 PrintAIDDescriptionBuf(root
, dfname
, dfnamelen
, verbose
);
2554 PrintAndLogEx(INFO
, "(DF) Name not equal to AID: %s :", sprint_hex(dfname
, dfnamelen
));
2555 PrintAIDDescriptionBuf(root
, dfname
, dfnamelen
, verbose
);
2558 if (verbose
) PrintAndLogEx(INFO
, "(DF) Name not found");
2561 if (verbose
) PrintAndLogEx(SUCCESS
, "----------------------------------------------------");
2568 if (verbose
== false && found
)
2569 PrintAndLogEx(INFO
, "----------------------------------------------------");
2576 PrintAndLogEx(INFO
, "proprietary iso18092 card found");
2579 PrintAndLogEx(INFO
, "proprietary non iso14443-4 card found, RATS not supported");
2580 if ((card
.sak
& 0x20) == 0x20) {
2581 PrintAndLogEx(INFO
, "--> SAK incorrectly claims that card supports RATS <--");
2585 if (select_status
== 1) {
2590 if (setDeviceDebugLevel(verbose
? DBG_INFO
: DBG_NONE
, false) != PM3_SUCCESS
) {
2594 PrintAndLogEx(INFO
, "");
2596 uint16_t isMagic
= 0;
2598 if (isMifareClassic
|| isMifareMini
) {
2599 isMagic
= detect_mf_magic(true, MF_KEY_B
, 0xFFFFFFFFFFFF);
2602 if (isMifareUltralight
) {
2603 isMagic
= detect_mf_magic(false, MF_KEY_A
, 0);
2606 if (isMifareClassic
|| isMifareMini
) {
2607 int res
= detect_classic_static_nonce();
2608 if (res
== NONCE_STATIC
) {
2609 PrintAndLogEx(SUCCESS
, "Static nonce......... " _YELLOW_("yes"));
2612 if (res
== NONCE_FAIL
&& verbose
) {
2613 PrintAndLogEx(SUCCESS
, "Static nonce......... " _RED_("read failed"));
2616 if (res
== NONCE_NORMAL
) {
2619 res
= detect_classic_prng();
2621 PrintAndLogEx(SUCCESS
, "Prng detection....... " _GREEN_("weak"));
2622 } else if (res
== 0) {
2623 PrintAndLogEx(SUCCESS
, "Prng detection....... " _YELLOW_("hard"));
2625 PrintAndLogEx(FAILED
, "Prng detection........ " _RED_("fail"));
2629 detect_classic_nackbug(false);
2633 uint8_t signature
[32] = {0};
2634 res
= read_mfc_ev1_signature(signature
);
2635 if (res
== PM3_SUCCESS
) {
2636 mfc_ev1_print_signature(card
.uid
, card
.uidlen
, signature
, sizeof(signature
));
2640 if (setDeviceDebugLevel(dbg_curr
, false) != PM3_SUCCESS
) {
2644 PrintAndLogEx(NORMAL
, "");
2645 if (isMifareUltralight
) {
2647 if (((isMagic
& MAGIC_FLAG_GEN_1A
) == MAGIC_FLAG_GEN_1A
) || ((isMagic
& MAGIC_FLAG_GEN_1B
) == MAGIC_FLAG_GEN_1B
)) {
2648 PrintAndLogEx(HINT
, "Hint: use `" _YELLOW_("hf mfu *") "` magic commands");
2651 if ((isMagic
& MAGIC_FLAG_NTAG21X
) == MAGIC_FLAG_NTAG21X
) {
2652 PrintAndLogEx(HINT
, "Hint: use `" _YELLOW_("hf mfu *") "` magic commands");
2655 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("hf mfu info") "`");
2658 if (isMifarePlus
&& (isMagic
== MAGIC_FLAG_NONE
)) {
2659 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("hf mfp info") "`");
2662 if (isMifareDESFire
&& (isMagic
== MAGIC_FLAG_NONE
) && isEMV
== false) {
2663 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("hf mfdes info") "`");
2667 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("hf st info") "`");
2671 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("emv reader") "`");
2675 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("hf seos info") "`");
2679 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("hf fudan dump") "`");
2681 PrintAndLogEx(HINT, " hf 14a raw -a -b 7 -k 26");
2682 PrintAndLogEx(HINT, " hf 14a raw -k -c 3000");
2683 PrintAndLogEx(HINT, " hf 14a raw -k -c 3001");
2684 PrintAndLogEx(HINT, " hf 14a raw -k -c 3002");
2685 PrintAndLogEx(HINT, " hf 14a raw -k -c 3003");
2686 PrintAndLogEx(HINT, " hf 14a raw -k -c 3004");
2687 PrintAndLogEx(HINT, " hf 14a raw -k -c 3005");
2688 PrintAndLogEx(HINT, " hf 14a raw -k -c 3006");
2689 PrintAndLogEx(HINT, " hf 14a raw -c 3007");
2694 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("hf ntag424 info") "`");
2697 if (isMifareClassic
|| isMifareMini
) {
2698 if (((isMagic
& MAGIC_FLAG_GEN_1A
) == MAGIC_FLAG_GEN_1A
) || ((isMagic
& MAGIC_FLAG_GEN_1B
) == MAGIC_FLAG_GEN_1B
)) {
2699 PrintAndLogEx(HINT
, "Hint: use `" _YELLOW_("hf mf c*") "` magic commands");
2701 // if GEN4 GDM in Gen1a more, hint about it
2702 if ((isMagic
& MAGIC_FLAG_GDM_WUP_40
) == MAGIC_FLAG_GDM_WUP_40
) {
2703 PrintAndLogEx(HINT
, "Hint: use `" _YELLOW_("hf mf gdm* --gen1a") "` magic commands");
2707 if ((isMagic
& MAGIC_FLAG_GEN_3
) == MAGIC_FLAG_GEN_3
) {
2708 PrintAndLogEx(HINT
, "Hint: use `" _YELLOW_("hf mf gen3*") "` magic commands");
2711 if ((isMagic
& MAGIC_FLAG_GEN_4GTU
) == MAGIC_FLAG_GEN_4GTU
) {
2712 PrintAndLogEx(HINT
, "Hint: use `" _YELLOW_("hf mf g*") "` magic commands");
2715 if ((isMagic
& MAGIC_FLAG_GDM_AUTH
) == MAGIC_FLAG_GDM_AUTH
) {
2716 PrintAndLogEx(HINT
, "Hint: use `" _YELLOW_("hf mf gdm*") "` magic commands");
2719 if ((isMagic
& MAGIC_FLAG_GEN_2
) == MAGIC_FLAG_GEN_2
) {
2720 PrintAndLogEx(HINT
, "Hint: use `" _YELLOW_("hf mf") "` commands");
2722 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`hf mf`") " commands");
2727 PrintAndLogEx(NORMAL
, "");
2729 return select_status
;
2732 int infoHF14A4Applications(bool verbose
) {
2733 bool cardFound
[ARRAYLEN(hintAIDList
)] = {0};
2734 bool ActivateField
= true;
2736 for (int i
= 0; i
< ARRAYLEN(hintAIDList
); i
++) {
2738 uint8_t result
[1024] = {0};
2739 size_t resultlen
= 0;
2740 int res
= Iso7816Select(CC_CONTACTLESS
, ActivateField
, true, (uint8_t *)hintAIDList
[i
].aid
, hintAIDList
[i
].aid_length
, result
, sizeof(result
), &resultlen
, &sw
);
2741 ActivateField
= false;
2745 if (sw
== ISO7816_OK
|| sw
== ISO7816_INVALID_DF
|| sw
== ISO7816_FILE_TERMINATED
) {
2748 PrintAndLogEx(INFO
, "----------------- " _CYAN_("Short AID search") " -----------------");
2752 if (sw
== ISO7816_OK
) {
2754 PrintAndLogEx(SUCCESS
, "Application " _CYAN_("%s") " ( " _GREEN_("ok") " )", hintAIDList
[i
].desc
);
2755 cardFound
[i
] = true;
2758 PrintAndLogEx(WARNING
, "Application " _CYAN_("%s") " ( " _RED_("blocked") " )", hintAIDList
[i
].desc
);
2765 PrintAndLogEx(INFO
, "---------------------------------------------------");
2768 if (found
>= ARRAYLEN(hintAIDList
) - 1) {
2769 PrintAndLogEx(HINT
, "Hint: card answers to all AID. It maybe the latest revision of plus/desfire/ultralight card.");
2771 for (int i
= 0; i
< ARRAYLEN(hintAIDList
); i
++) {
2772 if (cardFound
[i
] && strlen(hintAIDList
[i
].hint
))
2773 PrintAndLogEx(HINT
, "Hint: try `" _YELLOW_("%s") "` commands", hintAIDList
[i
].hint
);
2782 static uint32_t inc_sw_error_occurrence(uint16_t sw
, uint32_t *all_sw
) {
2783 uint8_t sw1
= (uint8_t)(sw
>> 8);
2784 uint8_t sw2
= (uint8_t)(0xff & sw
);
2786 // Don't count successes
2787 if (sw1
== 0x90 && sw2
== 0x00) {
2791 // Always max "Instruction not supported"
2792 if (sw1
== 0x6D && sw2
== 0x00) {
2793 return 0xFFFFFFFFUL
;
2796 all_sw
[(sw1
* 256) + sw2
]++;
2798 return all_sw
[(sw1
* 256) + sw2
];
2801 static int CmdHf14AFindapdu(const char *Cmd
) {
2802 // TODO: Option to select AID/File (and skip INS 0xA4).
2803 // TODO: Check all instructions with extended APDUs if the card support it.
2804 // TODO: Option to reset tag before every command.
2805 CLIParserContext
*ctx
;
2806 CLIParserInit(&ctx
, "hf 14a apdufind",
2807 "Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1/P2 commands.\n"
2808 "It loops all 256 possible values for each byte.\n"
2809 "The loop oder is INS -> P1/P2 (alternating) -> CLA.\n"
2810 "Tag must be on antenna before running.",
2812 "hf 14a apdufind --cla 80\n"
2813 "hf 14a apdufind --cla 80 --error-limit 20 --skip-ins a4 --skip-ins b0 --with-le\n"
2816 void *argtable
[] = {
2818 arg_str0("c", "cla", "<hex>", "Start value of CLASS (1 hex byte)"),
2819 arg_str0("i", "ins", "<hex>", "Start value of INSTRUCTION (1 hex byte)"),
2820 arg_str0(NULL
, "p1", "<hex>", "Start value of P1 (1 hex byte)"),
2821 arg_str0(NULL
, "p2", "<hex>", "Start value of P2 (1 hex byte)"),
2822 arg_u64_0("r", "reset", "<number>", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"),
2823 arg_u64_0("e", "error-limit", "<number>", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 512."),
2824 arg_strx0("s", "skip-ins", "<hex>", "Do not test an instruction (can be specified multiple times)"),
2825 arg_lit0("l", "with-le", "Search for APDUs with Le=0 (case 2S) as well"),
2826 arg_lit0("v", "verbose", "Verbose output"),
2829 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
2832 uint8_t cla_arg
[1] = {0};
2833 CLIGetHexWithReturn(ctx
, 1, cla_arg
, &cla_len
);
2836 uint8_t ins_arg
[1] = {0};
2837 CLIGetHexWithReturn(ctx
, 2, ins_arg
, &ins_len
);
2840 uint8_t p1_arg
[1] = {0};
2841 CLIGetHexWithReturn(ctx
, 3, p1_arg
, &p1_len
);
2844 uint8_t p2_arg
[1] = {0};
2845 CLIGetHexWithReturn(ctx
, 4, p2_arg
, &p2_len
);
2847 uint64_t reset_time
= arg_get_u64_def(ctx
, 5, 5 * 60);
2848 uint32_t error_limit
= arg_get_u64_def(ctx
, 6, 512);
2850 int ignore_ins_len
= 0;
2851 uint8_t ignore_ins_arg
[250] = {0};
2852 CLIGetHexWithReturn(ctx
, 7, ignore_ins_arg
, &ignore_ins_len
);
2854 bool with_le
= arg_get_lit(ctx
, 8);
2855 bool verbose
= arg_get_lit(ctx
, 9);
2859 bool activate_field
= true;
2860 bool keep_field_on
= true;
2861 uint8_t cla
= cla_arg
[0];
2862 uint8_t ins
= ins_arg
[0];
2863 uint8_t p1
= p1_arg
[0];
2864 uint8_t p2
= p2_arg
[0];
2866 uint8_t response
[PM3_CMD_DATA_SIZE
] = {0};
2868 uint8_t aSELECT_AID
[80];
2869 int aSELECT_AID_n
= 0;
2871 // Check if the tag reponds to APDUs.
2872 PrintAndLogEx(INFO
, "Sending a test APDU (select file command) to check if the tag is responding to APDU");
2873 param_gethex_to_eol("00a404000aa000000440000101000100", 0, aSELECT_AID
, sizeof(aSELECT_AID
), &aSELECT_AID_n
);
2874 int res
= ExchangeAPDU14a(aSELECT_AID
, aSELECT_AID_n
, true, false, response
, sizeof(response
), &response_n
);
2875 if (res
!= PM3_SUCCESS
) {
2876 PrintAndLogEx(FAILED
, "Tag did not respond to a test APDU (select file command). Aborting...");
2880 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
2881 PrintAndLogEx(NORMAL
, "");
2882 PrintAndLogEx(SUCCESS
, "Starting the APDU finder [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla
, ins
, p1
, p2
);
2884 bool inc_p1
= false;
2885 bool skip_ins
= false;
2886 uint32_t all_sw
[256][256] = { { 0 } };
2887 uint32_t sw_occurrences
= 0;
2889 uint64_t t_start
= msclock();
2890 uint64_t t_last_reset
= msclock();
2897 // Exit (was the Enter key pressed)?
2898 if (kbd_enter_pressed()) {
2899 PrintAndLogEx(INFO
, "User interrupted detected. Aborting");
2903 // Skip/Ignore this instrctuion?
2904 for (int i
= 0; i
< ignore_ins_len
; i
++) {
2905 if (ins
== ignore_ins_arg
[i
]) {
2917 PrintAndLogEx(INFO
, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla
, ins
, p1
, p2
);
2920 // Send APDU without Le (case 1) and with Le = 0 (case 2S), if "with-le" was set.
2921 uint8_t command
[5] = {cla
, ins
, p1
, p2
, 0x00};
2923 for (int i
= 0; i
< 1 + with_le
; i
++) {
2925 res
= ExchangeAPDU14a(command
, command_n
+ i
, activate_field
, keep_field_on
, response
, sizeof(response
), &response_n
);
2926 if (res
!= PM3_SUCCESS
) {
2928 activate_field
= true;
2932 uint16_t sw
= get_sw(response
, response_n
);
2933 sw_occurrences
= inc_sw_error_occurrence(sw
, all_sw
[0]);
2936 if (sw_occurrences
< error_limit
) {
2937 logLevel_t log_level
= INFO
;
2938 if (sw
== ISO7816_OK
) {
2939 log_level
= SUCCESS
;
2942 if (verbose
== true || sw
!= 0x6e00) {
2943 PrintAndLogEx(log_level
, "Got response for APDU \"%s\": %04X (%s)",
2944 sprint_hex_inrow(command
, command_n
+ i
),
2946 GetAPDUCodeDescription(sw
>> 8, sw
& 0xff)
2949 if (response_n
> 2) {
2950 PrintAndLogEx(SUCCESS
, "Response data is: %s | %s",
2951 sprint_hex_inrow(response
, response_n
- 2),
2952 sprint_ascii(response
, response_n
- 2)
2958 // Do not reativate the filed until the next reset.
2959 activate_field
= false;
2960 } while (++ins
!= ins_arg
[0]);
2962 // Increment P1/P2 in an alternating fashion.
2971 // Check if re-selecting the card is needed.
2972 uint64_t t_since_last_reset
= ((msclock() - t_last_reset
) / 1000);
2973 if (t_since_last_reset
> reset_time
) {
2975 activate_field
= true;
2976 t_last_reset
= msclock();
2977 PrintAndLogEx(INFO
, "Last reset was %" PRIu64
" seconds ago. Resetting the tag to prevent timeout issues", t_since_last_reset
);
2979 PrintAndLogEx(INFO
, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla
, ins
, p1
, p2
);
2981 } while (p1
!= p1_arg
[0] || p2
!= p2_arg
[0]);
2984 PrintAndLogEx(INFO
, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla
, ins
, p1
, p2
);
2986 } while (cla
!= cla_arg
[0]);
2989 PrintAndLogEx(SUCCESS
, "Runtime: %" PRIu64
" seconds\n", (msclock() - t_start
) / 1000);
2994 int CmdHF14ANdefRead(const char *Cmd
) {
2995 CLIParserContext
*ctx
;
2996 CLIParserInit(&ctx
, "hf 14a ndefread",
2997 "Read NFC Data Exchange Format (NDEF) file on Type 4 NDEF tag",
2999 "hf 14a ndefread -f myfilename -> save raw NDEF to file"
3002 void *argtable
[] = {
3004 arg_str0("f", "file", "<fn>", "save raw NDEF to file"),
3005 arg_litn("v", "verbose", 0, 2, "verbose output"),
3008 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3010 char filename
[FILE_PATH_SIZE
] = {0};
3011 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3013 bool verbose
= arg_get_lit(ctx
, 2);
3014 bool verbose2
= arg_get_lit(ctx
, 2) > 1;
3017 bool activate_field
= true;
3018 bool keep_field_on
= true;
3019 uint8_t response
[PM3_CMD_DATA_SIZE
];
3021 bool backward_compatibility_v1
= false;
3023 // --------------- Select NDEF Tag application ----------------
3024 uint8_t aSELECT_AID
[80];
3025 int aSELECT_AID_n
= 0;
3026 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID
, sizeof(aSELECT_AID
), &aSELECT_AID_n
);
3027 int res
= ExchangeAPDU14a(aSELECT_AID
, aSELECT_AID_n
, activate_field
, keep_field_on
, response
, sizeof(response
), &resplen
);
3028 if (res
!= PM3_SUCCESS
) {
3038 uint16_t sw
= get_sw(response
, resplen
);
3039 if (sw
!= ISO7816_OK
) {
3040 // Try NDEF Type 4 Tag v1.0
3041 param_gethex_to_eol("00a4040007d2760000850100", 0, aSELECT_AID
, sizeof(aSELECT_AID
), &aSELECT_AID_n
);
3042 res
= ExchangeAPDU14a(aSELECT_AID
, aSELECT_AID_n
, activate_field
, keep_field_on
, response
, sizeof(response
), &resplen
);
3043 if (res
!= PM3_SUCCESS
) {
3052 sw
= get_sw(response
, resplen
);
3053 if (sw
!= ISO7816_OK
) {
3054 PrintAndLogEx(ERR
, "Selecting NDEF aid failed (%04x - %s).", sw
, GetAPDUCodeDescription(sw
>> 8, sw
& 0xff));
3058 backward_compatibility_v1
= true;
3061 activate_field
= false;
3062 keep_field_on
= true;
3064 // --------------- CC file reading ----------------
3065 uint8_t aSELECT_FILE_CC
[30];
3066 int aSELECT_FILE_CC_n
= 0;
3067 if (backward_compatibility_v1
) {
3068 param_gethex_to_eol("00a4000002e103", 0, aSELECT_FILE_CC
, sizeof(aSELECT_FILE_CC
), &aSELECT_FILE_CC_n
);
3070 param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC
, sizeof(aSELECT_FILE_CC
), &aSELECT_FILE_CC_n
);
3072 res
= ExchangeAPDU14a(aSELECT_FILE_CC
, aSELECT_FILE_CC_n
, activate_field
, keep_field_on
, response
, sizeof(response
), &resplen
);
3073 if (res
!= PM3_SUCCESS
) {
3078 sw
= get_sw(response
, resplen
);
3079 if (sw
!= ISO7816_OK
) {
3080 PrintAndLogEx(ERR
, "Selecting CC file failed (%04x - %s).", sw
, GetAPDUCodeDescription(sw
>> 8, sw
& 0xff));
3085 uint8_t aREAD_CC
[30];
3087 param_gethex_to_eol("00b000000f", 0, aREAD_CC
, sizeof(aREAD_CC
), &aREAD_CC_n
);
3088 res
= ExchangeAPDU14a(aREAD_CC
, aREAD_CC_n
, activate_field
, keep_field_on
, response
, sizeof(response
), &resplen
);
3089 if (res
!= PM3_SUCCESS
) {
3093 sw
= get_sw(response
, resplen
);
3094 if (sw
!= ISO7816_OK
) {
3095 PrintAndLogEx(ERR
, "reading CC file failed (%04x - %s).", sw
, GetAPDUCodeDescription(sw
>> 8, sw
& 0xff));
3101 uint8_t cc_data
[resplen
- 2];
3102 memcpy(cc_data
, response
, sizeof(cc_data
));
3103 uint8_t file_id
[2] = {cc_data
[9], cc_data
[10]};
3106 print_type4_cc_info(cc_data
, sizeof(cc_data
));
3109 uint16_t max_rapdu_size
= (cc_data
[3] << 8 | cc_data
[4]) - 2;
3110 max_rapdu_size
= max_rapdu_size
< sizeof(response
) - 2 ? max_rapdu_size
: sizeof(response
) - 2;
3112 // --------------- NDEF file reading ----------------
3113 uint8_t aSELECT_FILE_NDEF
[30];
3114 int aSELECT_FILE_NDEF_n
= 0;
3115 if (backward_compatibility_v1
) {
3116 param_gethex_to_eol("00a4000002", 0, aSELECT_FILE_NDEF
, sizeof(aSELECT_FILE_NDEF
), &aSELECT_FILE_NDEF_n
);
3118 param_gethex_to_eol("00a4000c02", 0, aSELECT_FILE_NDEF
, sizeof(aSELECT_FILE_NDEF
), &aSELECT_FILE_NDEF_n
);
3120 memcpy(aSELECT_FILE_NDEF
+ aSELECT_FILE_NDEF_n
, file_id
, sizeof(file_id
));
3121 res
= ExchangeAPDU14a(aSELECT_FILE_NDEF
, aSELECT_FILE_NDEF_n
+ sizeof(file_id
), activate_field
, keep_field_on
, response
, sizeof(response
), &resplen
);
3122 if (res
!= PM3_SUCCESS
) {
3127 sw
= get_sw(response
, resplen
);
3128 if (sw
!= ISO7816_OK
) {
3129 PrintAndLogEx(ERR
, "Selecting NDEF file failed (%04x - %s).", sw
, GetAPDUCodeDescription(sw
>> 8, sw
& 0xff));
3134 // read first 2 bytes to get NDEF length
3135 uint8_t aREAD_NDEF
[30];
3136 int aREAD_NDEF_n
= 0;
3137 param_gethex_to_eol("00b0000002", 0, aREAD_NDEF
, sizeof(aREAD_NDEF
), &aREAD_NDEF_n
);
3138 res
= ExchangeAPDU14a(aREAD_NDEF
, aREAD_NDEF_n
, activate_field
, keep_field_on
, response
, sizeof(response
), &resplen
);
3139 if (res
!= PM3_SUCCESS
) {
3144 sw
= get_sw(response
, resplen
);
3145 if (sw
!= ISO7816_OK
) {
3146 PrintAndLogEx(ERR
, "reading NDEF file failed (%04x - %s).", sw
, GetAPDUCodeDescription(sw
>> 8, sw
& 0xff));
3151 uint16_t ndef_size
= (response
[0] << 8) + response
[1];
3152 uint16_t offset
= 2;
3153 uint8_t *ndef_file
= calloc(ndef_size
, sizeof(uint8_t));
3154 if (ndef_file
== NULL
) {
3155 PrintAndLogEx(ERR
, "Out of memory error in CmdHF14ANdef(). Aborting...\n");
3160 if (ndef_size
+ offset
> 0xFFFF) {
3161 PrintAndLogEx(ERR
, "NDEF size abnormally large in CmdHF14ANdef(). Aborting...\n");
3167 for (uint16_t i
= offset
; i
< ndef_size
+ offset
; i
+= max_rapdu_size
) {
3168 uint16_t segment_size
= max_rapdu_size
< ndef_size
+ offset
- i
? max_rapdu_size
: ndef_size
+ offset
- i
;
3169 keep_field_on
= i
< ndef_size
+ offset
- max_rapdu_size
;
3171 param_gethex_to_eol("00b00000", 0, aREAD_NDEF
, sizeof(aREAD_NDEF
), &aREAD_NDEF_n
);
3172 aREAD_NDEF
[2] = i
>> 8;
3173 aREAD_NDEF
[3] = i
& 0xFF;
3174 aREAD_NDEF
[4] = segment_size
;
3176 res
= ExchangeAPDU14a(aREAD_NDEF
, aREAD_NDEF_n
+ 1, activate_field
, keep_field_on
, response
, sizeof(response
), &resplen
);
3177 if (res
!= PM3_SUCCESS
) {
3183 sw
= get_sw(response
, resplen
);
3184 if (sw
!= ISO7816_OK
) {
3185 PrintAndLogEx(ERR
, "reading NDEF file failed (%04x - %s).", sw
, GetAPDUCodeDescription(sw
>> 8, sw
& 0xff));
3191 if (resplen
!= segment_size
+ 2) {
3192 PrintAndLogEx(ERR
, "reading NDEF file failed, expected %i bytes, got %i bytes.", segment_size
, resplen
- 2);
3198 memcpy(ndef_file
+ (i
- offset
), response
, segment_size
);
3202 PrintAndLogEx(NORMAL
, "");
3203 PrintAndLogEx(INFO
, "--- " _CYAN_("NDEF raw") " ----------------");
3204 print_buffer(ndef_file
, ndef_size
, 1);
3207 NDEFRecordsDecodeAndPrint(ndef_file
, ndef_size
, verbose
);
3209 pm3_save_dump(filename
, ndef_file
, ndef_size
, jsfNDEF
);
3211 if (verbose
== false) {
3212 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf 14a ndefread -v`") " for more details");
3214 if (verbose2
== false) {
3215 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf 14a ndefread -vv`") " for more details");
3223 int CmdHF14ANdefFormat(const char *Cmd
) {
3224 CLIParserContext
*ctx
;
3225 CLIParserInit(&ctx
, "hf 14a ndefformat",
3226 "Format ISO14443-a Tag as a NFC tag with Data Exchange Format (NDEF)",
3227 "hf 14a ndefformat\n"
3230 void *argtable
[] = {
3232 arg_lit0("v", "verbose", "verbose output"),
3235 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3236 bool verbose
= arg_get_lit(ctx
, 1);
3239 if (g_session
.pm3_present
== false)
3242 bool activate_field
= true;
3243 bool keep_field_on
= false;
3244 uint8_t response
[PM3_CMD_DATA_SIZE
];
3247 SetAPDULogging(false);
3249 // step 1 - Select NDEF Tag application
3250 uint8_t aSELECT_AID
[80];
3251 int aSELECT_AID_n
= 0;
3252 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID
, sizeof(aSELECT_AID
), &aSELECT_AID_n
);
3253 int res
= ExchangeAPDU14a(aSELECT_AID
, aSELECT_AID_n
, activate_field
, keep_field_on
, response
, sizeof(response
), &resplen
);
3255 if (res
!= PM3_SUCCESS
) {
3263 bool have_application
= true;
3264 uint16_t sw
= get_sw(response
, resplen
);
3265 if (sw
!= ISO7816_OK
) {
3266 have_application
= false;
3267 PrintAndLogEx(INFO
, "no NDEF application found");
3269 PrintAndLogEx(INFO
, "found ndef application");
3273 // setup desfire authentication context
3274 uint8_t empty_key
[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3275 DesfireContext_t dctx
;
3276 dctx
.secureChannel
= DACNone
;
3277 DesfireSetKey(&dctx
, 0, T_DES
, empty_key
);
3278 DesfireSetKdf(&dctx
, MFDES_KDF_ALGO_NONE
, NULL
, 0);
3279 DesfireSetCommandSet(&dctx
, DCCNativeISO
);
3280 DesfireSetCommMode(&dctx
, DCMPlain
);
3282 // step 1 - create application
3283 if (have_application
== false) {
3284 // "hf mfdes createapp --aid 000001 --fid E110 --ks1 0B --ks2 A1 --dfhex D2760000850101 -t des -n 0 -k 0000000000000000"
3285 PrintAndLogEx(INFO
, "creating NDEF application...");
3287 // authenticae first to AID 00 00 00
3288 res
= DesfireSelectAndAuthenticateEx(&dctx
, DACEV1
, 0x000000, false, verbose
);
3289 if (res
!= PM3_SUCCESS
) {
3291 PrintAndLogEx(INFO
, "failed empty auth..");
3295 // create application
3296 uint8_t dfname
[] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
3298 uint8_t ks2
= 0xA1; // bit FileID in ks2
3299 uint32_t appid
= 0x0000001;
3300 uint16_t fileid
= 0xE110;
3301 uint8_t data
[250] = {0};
3304 DesfireAIDUintToByte(appid
, &data
[0]);
3307 Uint2byteToMemLe(&data
[5], fileid
);
3308 memcpy(&data
[7], dfname
, sizeof(dfname
));
3312 PrintAndLogEx(INFO
, "---------------------------");
3313 PrintAndLogEx(INFO
, _CYAN_("Creating Application using:"));
3314 PrintAndLogEx(INFO
, "AID........... 0x%02X%02X%02X", data
[2], data
[1], data
[0]);
3315 PrintAndLogEx(INFO
, "Key Set 1..... 0x%02X", data
[3]);
3316 PrintAndLogEx(INFO
, "Key Set 2..... 0x%02X", data
[4]);
3317 PrintAndLogEx(INFO
, "ISO file ID... %s", (data
[4] & 0x20) ? "enabled" : "disabled");
3318 if ((data
[4] & 0x20)) {
3319 PrintAndLogEx(INFO
, "ISO file ID... 0x%04X", MemLeToUint2byte(&data
[5]));
3320 PrintAndLogEx(INFO
, "DF Name[%02d] %s | %s\n", 7, sprint_ascii(dfname
, sizeof(dfname
)), sprint_hex(dfname
, sizeof(dfname
)));
3322 PrintKeySettings(data
[3], data
[4], true, true);
3323 PrintAndLogEx(INFO
, "---------------------------");
3326 res
= DesfireCreateApplication(&dctx
, data
, datalen
);
3327 if (res
!= PM3_SUCCESS
) {
3328 PrintAndLogEx(ERR
, "Desfire CreateApplication command " _RED_("error") ". Result: %d", res
);
3333 PrintAndLogEx(SUCCESS
, "Desfire application %06x successfully " _GREEN_("created"), appid
);
3336 // step 2 - create capability container (CC File)
3338 // authenticae to the new AID 00 00 01
3339 uint8_t aes_key
[] = {
3340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3343 dctx
.secureChannel
= DACNone
;
3344 DesfireSetKey(&dctx
, 0, T_AES
, aes_key
);
3345 DesfireSetKdf(&dctx
, MFDES_KDF_ALGO_NONE
, NULL
, 0);
3346 DesfireSetCommandSet(&dctx
, DCCNativeISO
);
3347 DesfireSetCommMode(&dctx
, DCMPlain
);
3348 res
= DesfireSelectAndAuthenticateEx(&dctx
, DACEV1
, 0x000001, false, verbose
);
3349 if (res
!= PM3_SUCCESS
) {
3351 PrintAndLogEx(INFO
, "failed aid auth..");
3355 // hf mfdes createfile --aid 000001 --fid 01 --isofid E103 --amode plain --size 00000F
3356 // --rrights free --wrights key0 --rwrights key0 --chrights key0
3357 // -n 0 -t aes -k 00000000000000000000000000000000 -m plain
3359 uint16_t isofid
= 0xE103;
3360 uint32_t fsize
= 0x0F;
3361 uint8_t filetype
= 0x00; // standard file
3363 // file access mode: plain 0x00
3364 // read access: free 0x0E
3365 // write access: key0 0x00
3366 // r/w access: key0 0x00
3367 // change access: key0 0x00
3368 memset(data
, 0x00, sizeof(data
));
3372 data
[1] = isofid
& 0xff;
3373 data
[2] = (isofid
>> 8) & 0xff;
3376 uint8_t *settings
= &data
[datalen
];
3380 DesfireEncodeFileAcessMode(&settings
[1], 0x0E, 0x00, 0x00, 0x00) ;
3383 Uint3byteToMemLe(&data
[datalen
], fsize
);
3387 PrintAndLogEx(INFO
, "App: %06x. File num: 0x%02x type: 0x%02x data[%zu]: %s", appid
, data
[0], filetype
, datalen
, sprint_hex(data
, datalen
));
3390 DesfirePrintCreateFileSettings(filetype
, data
, datalen
);
3392 res
= DesfireCreateFile(&dctx
, filetype
, data
, datalen
, true); // check length only if we dont use raw mode
3393 if (res
!= PM3_SUCCESS
) {
3394 PrintAndLogEx(ERR
, "Desfire CreateFile command " _RED_("error") ". Result: %d", res
);
3399 PrintAndLogEx(SUCCESS
, "%s file %02x in the app %06x created " _GREEN_("successfully"), GetDesfireFileType(filetype
), data
[0], appid
);
3403 // hf mfdes write --aid 000001 --fid 01 -d 000F20003B00340406E10400FF00FF
3404 // -n 0 -t aes -k 00000000000000000000000000000000 -m plain
3405 res
= DesfireSelectAndAuthenticateEx(&dctx
, DACEV1
, 0x000001, false, verbose
);
3406 if (res
!= PM3_SUCCESS
) {
3408 PrintAndLogEx(INFO
, "failed aid auth..");
3412 uint8_t fnum
= 0x01;
3413 uint32_t offset
= 0;
3414 uint8_t cc_data
[] = {0x00, 0x0F, 0x20, 0x00, 0x3B, 0x00, 0x34, 0x04, 0x06, 0xE1, 0x04, 0x00, 0xFF, 0x00, 0x00};
3416 res
= DesfireWriteFile(&dctx
, fnum
, offset
, sizeof(cc_data
), cc_data
);
3417 if (res
!= PM3_SUCCESS
) {
3418 PrintAndLogEx(ERR
, "Desfire WriteFile command " _RED_("error") ". Result: %d", res
);
3424 PrintAndLogEx(INFO
, "Write data file %02x " _GREEN_("success"), fnum
);
3429 // step 3 - create NDEF record file
3430 // hf mfdes write --aid 000001 --fid 02 -d 000CD1010855016E78702E636F6DFE
3431 // -n 0 -t aes -k 00000000000000000000000000000000 -m plain
3436 filetype
= 0x00; // standard file
3438 // file access mode: plain 0x00
3439 // read access: free 0x0E
3440 // write access: key0 0x00
3441 // r/w access: key0 0x00
3442 // change access: key0 0x00
3443 memset(data
, 0x00, sizeof(data
));
3447 data
[1] = isofid
& 0xff;
3448 data
[2] = (isofid
>> 8) & 0xff;
3451 settings
= &data
[datalen
];
3455 DesfireEncodeFileAcessMode(&settings
[1], 0x0E, 0x00, 0x00, 0x00) ;
3458 Uint3byteToMemLe(&data
[datalen
], fsize
);
3462 PrintAndLogEx(INFO
, "App: %06x. File num: 0x%02x type: 0x%02x data[%zu]: %s", appid
, data
[0], filetype
, datalen
, sprint_hex(data
, datalen
));
3465 DesfirePrintCreateFileSettings(filetype
, data
, datalen
);
3467 res
= DesfireCreateFile(&dctx
, filetype
, data
, datalen
, true); // check length only if we dont use raw mode
3468 if (res
!= PM3_SUCCESS
) {
3469 PrintAndLogEx(ERR
, "Desfire CreateFile command " _RED_("error") ". Result: %d", res
);
3474 PrintAndLogEx(SUCCESS
, "%s file %02x in the app %06x created " _GREEN_("successfully"), GetDesfireFileType(filetype
), data
[0], appid
);
3479 PrintAndLogEx(NORMAL
, "");
3480 PrintAndLogEx(INFO
, "finished");
3484 int CmdHF14ANdefWrite(const char *Cmd
) {
3485 CLIParserContext
*ctx
;
3486 CLIParserInit(&ctx
, "hf 14a ndefwrite",
3487 "Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n",
3488 "hf 14a ndefwrite -d 0300FE -> write empty record to tag\n"
3489 "hf 14a ndefwrite -f myfilename\n"
3490 "hf 14a ndefwrite -d 003fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n"
3493 void *argtable
[] = {
3495 arg_str0("d", NULL
, "<hex>", "raw NDEF hex bytes"),
3496 arg_str0("f", "file", "<fn>", "write raw NDEF file to tag"),
3497 arg_lit0("p", NULL
, "fix NDEF record headers / terminator block if missing"),
3498 arg_lit0("v", "verbose", "verbose output"),
3501 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3503 uint8_t raw
[256] = {0};
3505 CLIGetHexWithReturn(ctx
, 1, raw
, &rawlen
);
3508 char filename
[FILE_PATH_SIZE
] = {0};
3509 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3511 bool fix_msg
= arg_get_lit(ctx
, 3);
3512 bool verbose
= arg_get_lit(ctx
, 4);
3515 if (g_session
.pm3_present
== false) {
3519 if ((rawlen
&& fnlen
) || (rawlen
== 0 && fnlen
== 0)) {
3520 PrintAndLogEx(WARNING
, "Please specify either raw hex or filename");
3524 int res
= PM3_SUCCESS
;
3525 int32_t bytes
= rawlen
;
3529 uint8_t *dump
= NULL
;
3530 size_t bytes_read
= 0;
3531 res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, sizeof(raw
));
3532 if (res
!= PM3_SUCCESS
) {
3535 memcpy(raw
, dump
, bytes_read
);
3541 PrintAndLogEx(INFO
, "Num of bytes... %i (raw %i)", bytes
, rawlen
);
3544 // Has raw bytes ndef message header?bytes
3554 if (fix_msg
== false) {
3555 PrintAndLogEx(WARNING
, "raw NDEF message doesn't have a proper header, continuing...");
3557 if (bytes
+ 2 > sizeof(raw
)) {
3558 PrintAndLogEx(WARNING
, "no room for header, exiting...");
3561 uint8_t tmp_raw
[256];
3562 memcpy(tmp_raw
, raw
, sizeof(tmp_raw
));
3565 memcpy(raw
+ 2, tmp_raw
, sizeof(raw
) - 2);
3567 PrintAndLogEx(SUCCESS
, "Added generic message header (0x03)");
3572 // Has raw bytes ndef a terminator block?
3573 if (raw
[bytes
- 1] != 0xFE) {
3574 if (fix_msg
== false) {
3575 PrintAndLogEx(WARNING
, "raw NDEF message doesn't have a terminator block, continuing...");
3578 if (bytes
+ 1 > sizeof(raw
)) {
3579 PrintAndLogEx(WARNING
, "no room for terminator block, exiting...");
3584 PrintAndLogEx(SUCCESS
, "Added terminator block (0xFE)");
3589 PrintAndLogEx(INFO
, "Num of Bytes... %u", bytes
);
3590 print_buffer(raw
, bytes
, 0);
3594 // setup desfire authentication context
3595 // authenticae to the new AID 00 00 01
3596 uint8_t aes_key
[] = {
3597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3601 DesfireContext_t dctx
;
3602 dctx
.secureChannel
= DACNone
;
3603 DesfireSetKey(&dctx
, 0, T_AES
, aes_key
);
3604 DesfireSetKdf(&dctx
, MFDES_KDF_ALGO_NONE
, NULL
, 0);
3605 DesfireSetCommandSet(&dctx
, DCCNativeISO
);
3606 DesfireSetCommMode(&dctx
, DCMPlain
);
3607 res
= DesfireSelectAndAuthenticateEx(&dctx
, DACEV1
, 0x000001, false, verbose
);
3608 if (res
!= PM3_SUCCESS
) {
3610 PrintAndLogEx(INFO
, "failed aid auth..");
3616 // hf mfdes write --aid 000002 --fid 02 -
3617 // -n 0 -t aes -k 00000000000000000000000000000000 -m plain
3618 uint8_t fnum
= 0x02;
3619 uint32_t offset
= 0;
3621 res
= DesfireWriteFile(&dctx
, fnum
, offset
, bytes
, raw
);
3622 if (res
!= PM3_SUCCESS
) {
3623 PrintAndLogEx(ERR
, "Desfire WriteFile command " _RED_("error") ". Result: %d", res
);
3629 PrintAndLogEx(INFO
, "Write data file %02x " _GREEN_("success"), fnum
);
3632 PrintAndLogEx(NORMAL
, "");
3633 PrintAndLogEx(INFO
, "finished");
3637 static command_t CommandTable
[] = {
3638 {"-----------", CmdHelp
, AlwaysAvailable
, "----------------------- " _CYAN_("General") " -----------------------"},
3639 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
3640 {"list", CmdHF14AList
, AlwaysAvailable
, "List ISO 14443-a history"},
3641 {"-----------", CmdHelp
, IfPm3Iso14443a
, "---------------------- " _CYAN_("Operations") " ---------------------"},
3642 {"antifuzz", CmdHF14AAntiFuzz
, IfPm3Iso14443a
, "Fuzzing the anticollision phase. Warning! Readers may react strange"},
3643 {"config", CmdHf14AConfig
, IfPm3Iso14443a
, "Configure 14a settings (use with caution)"},
3644 {"cuids", CmdHF14ACUIDs
, IfPm3Iso14443a
, "Collect n>0 ISO14443-a UIDs in one go"},
3645 {"info", CmdHF14AInfo
, IfPm3Iso14443a
, "Tag information"},
3646 {"sim", CmdHF14ASim
, IfPm3Iso14443a
, "Simulate ISO 14443-a tag"},
3647 {"sniff", CmdHF14ASniff
, IfPm3Iso14443a
, "sniff ISO 14443-a traffic"},
3648 {"raw", CmdHF14ACmdRaw
, IfPm3Iso14443a
, "Send raw hex data to tag"},
3649 {"reader", CmdHF14AReader
, IfPm3Iso14443a
, "Act like an ISO14443-a reader"},
3650 {"-----------", CmdHelp
, IfPm3Iso14443a
, "------------------------- " _CYAN_("APDU") " -------------------------"},
3651 {"apdu", CmdHF14AAPDU
, IfPm3Iso14443a
, "Send ISO 14443-4 APDU to tag"},
3652 {"apdufind", CmdHf14AFindapdu
, IfPm3Iso14443a
, "Enumerate APDUs - CLA/INS/P1P2"},
3653 {"chaining", CmdHF14AChaining
, IfPm3Iso14443a
, "Control ISO 14443-4 input chaining"},
3654 {"-----------", CmdHelp
, IfPm3Iso14443a
, "------------------------- " _CYAN_("NDEF") " -------------------------"},
3655 {"ndefformat", CmdHF14ANdefFormat
, IfPm3Iso14443a
, "Format ISO 14443-A as NFC Type 4 tag"},
3656 {"ndefread", CmdHF14ANdefRead
, IfPm3Iso14443a
, "Read an NDEF file from ISO 14443-A Type 4 tag"},
3657 {"ndefwrite", CmdHF14ANdefWrite
, IfPm3Iso14443a
, "Write NDEF records to ISO 14443-A tag"},
3658 {NULL
, NULL
, NULL
, NULL
}
3661 static int CmdHelp(const char *Cmd
) {
3662 (void)Cmd
; // Cmd is not used so far
3663 CmdsHelp(CommandTable
);
3667 int CmdHF14A(const char *Cmd
) {
3668 clearCommandBuffer();
3669 return CmdsParse(CommandTable
, Cmd
);