fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdhf15.c
blob4c82dc0e3ab9f3bacdcf8db02ac8ecfe3c90e2af
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
3 // Modified 2010-2012 by <adrian -at- atrox.at>
4 // Modified 2012 by <vsza at vsza.hu>
5 // Modfified 2018 by <iceman>
6 //
7 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
8 // at your option, any later version. See the LICENSE.txt file for the text of
9 // the license.
10 //-----------------------------------------------------------------------------
11 // High frequency ISO15693 commands
12 //-----------------------------------------------------------------------------
13 // There are three basic operation modes, depending on which device (proxmark/pc)
14 // the signal processing, (de)modulation, transmission protocol and logic is done.
15 // Mode 1:
16 // All steps are done on the proxmark, the output of the commands is returned via
17 // USB-debug-print commands.
18 // Mode 2:
19 // The protocol is done on the PC, passing only Iso15693 data frames via USB. This
20 // allows direct communication with a tag on command level
21 // Mode 3:
22 // The proxmark just samples the antenna and passes this "analog" data via USB to
23 // the client. Signal Processing & decoding is done on the pc. This is the slowest
24 // variant, but offers the possibility to analyze the waveforms directly.
25 #include "cmdhf15.h"
26 #include <ctype.h>
27 #include "cmdparser.h" // command_t
28 #include "commonutil.h" // ARRAYLEN
29 #include "comms.h" // clearCommandBuffer
30 #include "cmdtrace.h"
31 #include "iso15693tools.h" // ISO15693 error codes etc
32 #include "protocols.h" // ISO15693 command set
33 #include "crypto/libpcrypto.h"
34 #include "graph.h"
35 #include "crc16.h" // iso15 crc
36 #include "cmddata.h" // getsamples
37 #include "fileutils.h" // savefileEML
38 #include "cliparser.h"
39 #include "util_posix.h" // msleep
41 #define FrameSOF Iso15693FrameSOF
42 #define Logic0 Iso15693Logic0
43 #define Logic1 Iso15693Logic1
44 #define FrameEOF Iso15693FrameEOF
46 #ifndef Crc15
47 # define Crc15(data, len) Crc16ex(CRC_15693, (data), (len))
48 #endif
49 #ifndef CheckCrc15
50 # define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
51 #endif
52 #ifndef AddCrc15
53 #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
54 #endif
56 typedef struct {
57 uint8_t lock;
58 uint8_t block[4];
59 } t15memory_t;
61 // structure and database for uid -> tagtype lookups
62 typedef struct {
63 uint64_t uid;
64 int mask; // how many MSB bits used
65 const char *desc;
66 } productName_t;
68 const productName_t uidmapping[] = {
70 // UID, #significant Bits, "Vendor(+Product)"
71 { 0xE001000000000000LL, 16, "Motorola UK" },
73 // E0 02 xx
74 // 02 = ST Microelectronics
75 // XX = IC id (Chip ID Family)
76 { 0xE002000000000000LL, 16, "ST Microelectronics SA France" },
77 { 0xE002050000000000LL, 24, "ST Microelectronics; LRI64 [IC id = 05]"},
78 { 0xE002080000000000LL, 24, "ST Microelectronics; LRI2K [IC id = 08]"},
79 { 0xE0020A0000000000LL, 24, "ST Microelectronics; LRIS2K [IC id = 10]"},
80 { 0xE002440000000000LL, 24, "ST Microelectronics; LRIS64K [IC id = 68]"},
82 { 0xE003000000000000LL, 16, "Hitachi, Ltd Japan" },
84 // E0 04 xx
85 // 04 = Manufacturer code (Philips/NXP)
86 // XX = IC id (Chip ID Family)
87 //I-Code SLI SL2 ICS20 [IC id = 01]
88 //I-Code SLI-S [IC id = 02]
89 //I-Code SLI-L [IC id = 03]
90 //I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)]
91 //I-Code SLIX2 [IC id = 01 + bit35 set to 1 + bit36 set to 0]
92 //I-Code SLIX-S [IC id = 02 + bit36 set to 1]
93 //I-Code SLIX-L [IC id = 03 + bit36 set to 1]
94 { 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" },
95 { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX) ICS2602(SLIX2)" },
96 { 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" },
97 { 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" },
99 // E0 05 XX .. .. ..
100 // 05 = Manufacturer code (Infineon)
101 // XX = IC id (Chip ID Family)
102 { 0xE005000000000000LL, 16, "Infineon Technologies AG Germany" },
103 { 0xE005A10000000000LL, 24, "Infineon; SRF55V01P [IC id = 161] plain mode 1kBit"},
104 { 0xE005A80000000000LL, 24, "Infineon; SRF55V01P [IC id = 168] pilot series 1kBit"},
105 { 0xE005400000000000LL, 24, "Infineon; SRF55V02P [IC id = 64] plain mode 2kBit"},
106 { 0xE005000000000000LL, 24, "Infineon; SRF55V10P [IC id = 00] plain mode 10KBit"},
107 { 0xE005500000000000LL, 24, "Infineon; SRF55V02S [IC id = 80] secure mode 2kBit"},
108 { 0xE005100000000000LL, 24, "Infineon; SRF55V10S [IC id = 16] secure mode 10KBit"},
109 { 0xE0051E0000000000LL, 23, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"},
110 { 0xE005200000000000LL, 21, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"},
112 { 0xE006000000000000LL, 16, "Cylink USA" },
115 // E0 07 xx
116 // 07 = Texas Instruments
117 // XX = from bit 41 to bit 43 = product configuration - from bit 44 to bit 47 IC id (Chip ID Family)
118 //Tag IT RFIDType-I Plus, 2kBit, TI Inlay
119 //Tag-it HF-I Plus Inlay [IC id = 00] -> b'0000 000 2kBit
120 //Tag-it HF-I Plus Chip [IC id = 64] -> b'1000 000 2kBit
121 //Tag-it HF-I Standard Chip / Inlays [IC id = 96] -> b'1100 000 256Bit
122 //Tag-it HF-I Pro Chip / Inlays [IC id = 98] -> b'1100 010 256Bit, Password protection
123 { 0xE007000000000000LL, 16, "Texas Instrument France" },
124 { 0xE007000000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Inlay; 64x32bit" },
125 { 0xE007100000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Chip; 64x32bit" },
126 { 0xE007800000000000LL, 23, "Texas Instrument; Tag-it HF-I Plus (RF-HDT-DVBB tag or Third Party Products)" },
127 { 0xE007C00000000000LL, 23, "Texas Instrument; Tag-it HF-I Standard; 8x32bit" },
128 { 0xE007C40000000000LL, 23, "Texas Instrument; Tag-it HF-I Pro; 8x23bit; password" },
130 { 0xE008000000000000LL, 16, "Fujitsu Limited Japan" },
131 { 0xE009000000000000LL, 16, "Matsushita Electronics Corporation, Semiconductor Company Japan" },
132 { 0xE00A000000000000LL, 16, "NEC Japan" },
133 { 0xE00B000000000000LL, 16, "Oki Electric Industry Co. Ltd Japan" },
134 { 0xE00C000000000000LL, 16, "Toshiba Corp. Japan" },
135 { 0xE00D000000000000LL, 16, "Mitsubishi Electric Corp. Japan" },
136 { 0xE00E000000000000LL, 16, "Samsung Electronics Co. Ltd Korea" },
137 { 0xE00F000000000000LL, 16, "Hynix / Hyundai, Korea" },
138 { 0xE010000000000000LL, 16, "LG-Semiconductors Co. Ltd Korea" },
139 { 0xE011000000000000LL, 16, "Emosyn-EM Microelectronics USA" },
141 { 0xE012000000000000LL, 16, "HID Corporation" },
142 { 0xE012000000000000LL, 16, "INSIDE Technology France" },
143 { 0xE013000000000000LL, 16, "ORGA Kartensysteme GmbH Germany" },
144 { 0xE014000000000000LL, 16, "SHARP Corporation Japan" },
145 { 0xE015000000000000LL, 16, "ATMEL France" },
147 { 0xE016000000000000LL, 16, "EM Microelectronic-Marin SA Switzerland (Skidata)"},
148 { 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); EM4034 [IC id = 01] (Read/Write - no AFI)"},
149 { 0xE0160C0000000000LL, 24, "EM-Marin SA (Skidata); EM4035 [IC id = 03] (Read/Write - replaced by 4233)"},
150 { 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135 [IC id = 04] (Read/Write - replaced by 4233) 36x64bit start page 13"},
151 { 0xE016140000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 05] 28pF"},
152 { 0xE016180000000000LL, 24, "EM-Marin SA (Skidata); EM4006 [IC id = 06] (Read Only)"},
153 { 0xE0161C0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 07] 23,5pF (Read/Write)"},
154 { 0xE016200000000000LL, 24, "EM-Marin SA (Skidata); EM4033 [IC id = 08] 23,5pF (Read Only - no AFI / no DSFID / no security blocks)"},
155 { 0xE016240000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 09] 23,5pF CustomerID-102"},
156 { 0xE016280000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 10] 23,5pF (1Kb flash memory - not provide High Security mode and QuietStorage feature)" },
157 { 0xE0163C0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 15] 23,5pF"},
158 { 0xE0167C0000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 31] 95pF"},
159 { 0xE016940000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 37] 95pF 51x64bit "},
160 { 0xE0169c0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 39] 95pF (Read/Write)" },
161 { 0xE016A80000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 42] 97pF" },
162 { 0xE016BC0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 47] 97pF" },
164 { 0xE017000000000000LL, 16, "KSW Microtec GmbH Germany" },
165 { 0xE018000000000000LL, 16, "ZMD AG Germany" },
166 { 0xE019000000000000LL, 16, "XICOR, Inc. USA" },
167 { 0xE01A000000000000LL, 16, "Sony Corporation Japan Identifier Company Country" },
168 { 0xE01B000000000000LL, 16, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" },
169 { 0xE01C000000000000LL, 16, "Emosyn USA" },
170 { 0xE01D000000000000LL, 16, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" },
171 { 0xE01E000000000000LL, 16, "Magellan Technology Pty Limited Australia" },
172 { 0xE01F000000000000LL, 16, "Melexis NV BO Switzerland" },
173 { 0xE020000000000000LL, 16, "Renesas Technology Corp. Japan" },
174 { 0xE021000000000000LL, 16, "TAGSYS France" },
175 { 0xE022000000000000LL, 16, "Transcore USA" },
176 { 0xE023000000000000LL, 16, "Shanghai belling corp., ltd. China" },
177 { 0xE024000000000000LL, 16, "Masktech Germany Gmbh Germany" },
178 { 0xE025000000000000LL, 16, "Innovision Research and Technology Plc UK" },
179 { 0xE026000000000000LL, 16, "Hitachi ULSI Systems Co., Ltd. Japan" },
180 { 0xE027000000000000LL, 16, "Cypak AB Sweden" },
181 { 0xE028000000000000LL, 16, "Ricoh Japan" },
182 { 0xE029000000000000LL, 16, "ASK France" },
183 { 0xE02A000000000000LL, 16, "Unicore Microsystems, LLC Russian Federation" },
184 { 0xE02B000000000000LL, 16, "Dallas Semiconductor/Maxim USA" },
185 { 0xE02C000000000000LL, 16, "Impinj, Inc. USA" },
186 { 0xE02D000000000000LL, 16, "RightPlug Alliance USA" },
187 { 0xE02E000000000000LL, 16, "Broadcom Corporation USA" },
188 { 0xE02F000000000000LL, 16, "MStar Semiconductor, Inc Taiwan, ROC" },
189 { 0xE030000000000000LL, 16, "BeeDar Technology Inc. USA" },
190 { 0xE031000000000000LL, 16, "RFIDsec Denmark" },
191 { 0xE032000000000000LL, 16, "Schweizer Electronic AG Germany" },
192 { 0xE033000000000000LL, 16, "AMIC Technology Corp Taiwan" },
193 { 0xE034000000000000LL, 16, "Mikron JSC Russia" },
194 { 0xE035000000000000LL, 16, "Fraunhofer Institute for Photonic Microsystems Germany" },
195 { 0xE036000000000000LL, 16, "IDS Microchip AG Switzerland" },
196 { 0xE037000000000000LL, 16, "Kovio USA" },
197 { 0xE038000000000000LL, 16, "HMT Microelectronic Ltd Switzerland Identifier Company Country" },
198 { 0xE039000000000000LL, 16, "Silicon Craft Technology Thailand" },
199 { 0xE03A000000000000LL, 16, "Advanced Film Device Inc. Japan" },
200 { 0xE03B000000000000LL, 16, "Nitecrest Ltd UK" },
201 { 0xE03C000000000000LL, 16, "Verayo Inc. USA" },
202 { 0xE03D000000000000LL, 16, "HID Global USA" },
203 { 0xE03E000000000000LL, 16, "Productivity Engineering Gmbh Germany" },
204 { 0xE03F000000000000LL, 16, "Austriamicrosystems AG (reserved) Austria" },
205 { 0xE040000000000000LL, 16, "Gemalto SA France" },
206 { 0xE041000000000000LL, 16, "Renesas Electronics Corporation Japan" },
207 { 0xE042000000000000LL, 16, "3Alogics Inc Korea" },
208 { 0xE043000000000000LL, 16, "Top TroniQ Asia Limited Hong Kong" },
209 { 0xE044000000000000LL, 16, "Gentag Inc (USA) USA" },
210 { 0, 0, "no tag-info available" } // must be the last entry
213 static int CmdHF15Help(const char *Cmd);
215 static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
217 #define PUBLIC_ECDA_KEYLEN 33
218 const ecdsa_publickey_t nxp_15693_public_keys[] = {
219 {"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
220 {"Manufacturer Mifare Classic MFC1C14_x", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
221 {"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
222 {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
223 {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
224 {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
225 {"MIKRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"},
226 {"VivoKey Spark1 Public key", "04d64bb732c0d214e7ec580736acf847284b502c25c0f7f2fa86aace1dada4387a"},
229 uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = {
230 // ICODE SLIX2 / DNA
232 0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3,
233 0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71,
234 0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64,
235 0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0
237 // unknown. Needs identification
239 0x04, 0x4F, 0x6D, 0x3F, 0x29, 0x4D, 0xEA, 0x57,
240 0x37, 0xF0, 0xF4, 0x6F, 0xFE, 0xE8, 0x8A, 0x35,
241 0x6E, 0xED, 0x95, 0x69, 0x5D, 0xD7, 0xE0, 0xC2,
242 0x7A, 0x59, 0x1E, 0x6F, 0x6F, 0x65, 0x96, 0x2B, 0xAF
244 // unknown. Needs identification
246 0x04, 0xA7, 0x48, 0xB6, 0xA6, 0x32, 0xFB, 0xEE,
247 0x2C, 0x08, 0x97, 0x70, 0x2B, 0x33, 0xBE, 0xA1,
248 0xC0, 0x74, 0x99, 0x8E, 0x17, 0xB8, 0x4A, 0xCA,
249 0x04, 0xFF, 0x26, 0x7E, 0x5D, 0x2C, 0x91, 0xF6, 0xDC
251 // manufacturer public key
253 0x04, 0x6F, 0x70, 0xAC, 0x55, 0x7F, 0x54, 0x61,
254 0xCE, 0x50, 0x52, 0xC8, 0xE4, 0xA7, 0x83, 0x8C,
255 0x11, 0xC7, 0xA2, 0x36, 0x79, 0x7E, 0x8A, 0x07,
256 0x30, 0xA1, 0x01, 0x83, 0x7C, 0x00, 0x40, 0x39, 0xC2
258 // MIKRON public key.
260 0x04, 0xf9, 0x71, 0xed, 0xa7, 0x42, 0xa4, 0xa8,
261 0x0d, 0x32, 0xdc, 0xf6, 0xa8, 0x14, 0xa7, 0x07,
262 0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7,
263 0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2
267 uint8_t i;
268 uint8_t revuid[8];
269 for (i = 0; i < sizeof(revuid); i++) {
270 revuid[i] = uid[7 - i];
272 uint8_t revsign[32];
273 for (i = 0; i < sizeof(revsign); i++) {
274 revsign[i] = signature[31 - i];
277 int reason = 0;
278 bool is_valid = false;
279 for (i = 0; i < ARRAYLEN(nxp_15693_public_keys); i++) {
281 int dl = 0;
282 uint8_t key[PUBLIC_ECDA_KEYLEN];
283 param_gethex_to_eol(nxp_15693_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl);
285 int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, false);
286 is_valid = (res == 0);
287 if (is_valid) {
288 reason = 1;
289 break;
292 // try with sha256
293 res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, true);
294 is_valid = (res == 0);
295 if (is_valid) {
296 reason = 2;
297 break;
300 // try with reversed uid / signature
301 res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, revuid, sizeof(revuid), revsign, sizeof(revsign), false);
302 is_valid = (res == 0);
303 if (is_valid) {
304 reason = 3;
305 break;
309 // try with sha256
310 res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, revuid, sizeof(revuid), revsign, sizeof(revsign), true);
311 is_valid = (res == 0);
312 if (is_valid) {
313 reason = 4;
314 break;
318 PrintAndLogEx(NORMAL, "");
319 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
320 if (is_valid == false || i == ARRAYLEN(nxp_15693_public_keys)) {
321 PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
322 PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
323 PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
324 return PM3_ESOFT;
327 PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_15693_public_keys[i].desc);
328 PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_15693_public_keys[i].value);
329 PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
330 PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
331 PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
332 switch (reason) {
333 case 1:
334 PrintAndLogEx(INFO, " Params used: UID and signature, plain");
335 break;
336 case 2:
337 PrintAndLogEx(INFO, " Params used: UID and signature, SHA256");
338 break;
339 case 3:
340 PrintAndLogEx(INFO, " Params used: reversed UID and signature, plain");
341 break;
342 case 4:
343 PrintAndLogEx(INFO, " Params used: reversed UID and signature, SHA256");
344 break;
346 return PM3_SUCCESS;
349 // get a product description based on the UID
350 // uid[8] tag uid
351 // returns description of the best match
352 static const char *getTagInfo_15(uint8_t *uid) {
353 if (uid == NULL) {
354 return "";
357 uint64_t myuid, mask;
358 int i = 0, best = -1;
359 memcpy(&myuid, uid, sizeof(uint64_t));
360 while (uidmapping[i].mask > 0) {
361 mask = (~0ULL) << (64 - uidmapping[i].mask);
362 if ((myuid & mask) == uidmapping[i].uid) {
363 if (best == -1) {
364 best = i;
365 } else {
366 if (uidmapping[i].mask > uidmapping[best].mask) {
367 best = i;
371 i++;
374 if (best >= 0)
375 return uidmapping[best].desc;
376 return uidmapping[i].desc;
379 // return a clear-text message to an errorcode
380 static const char *TagErrorStr(uint8_t error) {
381 switch (error) {
382 case 0x01:
383 return "The command is not supported";
384 case 0x02:
385 return "The command is not recognized";
386 case 0x03:
387 return "The option is not supported.";
388 case 0x0f:
389 return "Unknown error.";
390 case 0x10:
391 return "The specified block is not available (doesn't exist).";
392 case 0x11:
393 return "The specified block is already -locked and thus cannot be locked again";
394 case 0x12:
395 return "The specified block is locked and its content cannot be changed.";
396 case 0x13:
397 return "The specified block was not successfully programmed.";
398 case 0x14:
399 return "The specified block was not successfully locked.";
400 default:
401 return "Reserved for Future Use or Custom command error.";
405 // fast method to just read the UID of a tag (collision detection not supported)
406 // *buf should be large enough to fit the 64bit uid
407 // returns 1 if succeeded
408 static int getUID(bool loop, uint8_t *buf) {
410 uint8_t data[5];
411 data[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
412 data[1] = ISO15693_INVENTORY;
413 data[2] = 0; // mask length
415 AddCrc15(data, 3);
417 // params
418 uint8_t fast = 1;
419 uint8_t reply = 1;
421 int res = PM3_ESOFT;
423 do {
424 clearCommandBuffer();
425 SendCommandMIX(CMD_HF_ISO15693_COMMAND, sizeof(data), fast, reply, data, sizeof(data));
426 PacketResponseNG resp;
427 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
429 int resplen = resp.oldarg[0];
430 if (resplen >= 12 && CheckCrc15(resp.data.asBytes, 12)) {
432 if (buf)
433 memcpy(buf, resp.data.asBytes + 2, 8);
435 DropField();
437 PrintAndLogEx(NORMAL, "");
438 PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL, buf));
439 PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("%s"), getTagInfo_15(buf));
441 res = PM3_SUCCESS;
443 if (loop == false) {
444 break;
448 } while (loop && kbd_enter_pressed() == false);
450 DropField();
451 return res;
454 // used with 'hf search'
455 bool readHF15Uid(bool loop, bool verbose) {
456 uint8_t uid[8] = {0};
457 if (getUID(loop, uid) != PM3_SUCCESS) {
458 if (verbose) PrintAndLogEx(WARNING, "no tag found");
459 return false;
461 return true;
464 // adds 6
465 static uint8_t arg_add_default(void *at[]) {
466 at[0] = arg_param_begin;
467 at[1] = arg_str0("u", "uid", "<hex>", "full UID, 8 bytes");
468 at[2] = arg_lit0(NULL, "ua", "unaddressed mode");
469 at[3] = arg_lit0("*", NULL, "scan for tag");
470 at[4] = arg_lit0("2", NULL, "use slower '1 out of 256' mode");
471 at[5] = arg_lit0("o", "opt", "set OPTION Flag (needed for TI)");
472 return 6;
474 static uint16_t arg_get_raw_flag(uint8_t uidlen, bool unaddressed, bool scan, bool add_option) {
475 uint16_t flags = 0;
476 if (unaddressed) {
477 // unaddressed mode may not be supported by all vendors
478 flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY);
480 if (uidlen == 8) {
481 flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS);
483 if (scan) {
484 flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS);
486 if (add_option) {
487 flags |= (ISO15_REQ_OPTION);
489 return flags;
492 // Mode 3
493 static int CmdHF15Demod(const char *Cmd) {
495 CLIParserContext *ctx;
496 CLIParserInit(&ctx, "hf 15 demod",
497 "Tries to demodulate / decode ISO-15693, from downloaded samples.\n"
498 "Gather samples with 'hf 15 samples' / 'hf 15 sniff'",
499 "hf 15 demod\n");
501 void *argtable[] = {
502 arg_param_begin,
503 arg_param_end
505 CLIExecWithReturn(ctx, Cmd, argtable, true);
506 CLIParserFree(ctx);
508 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
509 int i, j;
510 int max = 0, maxPos = 0;
511 int skip = 4;
513 if (GraphTraceLen < 1000) {
514 PrintAndLogEx(FAILED, "Too few samples in GraphBuffer. Need more than 1000");
515 PrintAndLogEx(HINT, "Run " _YELLOW_("`hf 15 samples`") " to collect and download data");
516 return PM3_ESOFT;
519 // First, correlate for SOF
520 for (i = 0; i < 1000; i++) {
521 int corr = 0;
522 for (j = 0; j < ARRAYLEN(FrameSOF); j += skip) {
523 corr += FrameSOF[j] * GraphBuffer[i + (j / skip)];
525 if (corr > max) {
526 max = corr;
527 maxPos = i;
531 PrintAndLogEx(INFO, "SOF at %d, correlation %zu", maxPos, max / (ARRAYLEN(FrameSOF) / skip));
533 i = maxPos + ARRAYLEN(FrameSOF) / skip;
534 int k = 0;
535 uint8_t outBuf[2048] = {0};
536 memset(outBuf, 0, sizeof(outBuf));
537 uint8_t mask = 0x01;
538 for (;;) {
539 int corr0 = 0, corr1 = 0, corrEOF = 0;
540 for (j = 0; j < ARRAYLEN(Logic0); j += skip) {
541 corr0 += Logic0[j] * GraphBuffer[i + (j / skip)];
543 for (j = 0; j < ARRAYLEN(Logic1); j += skip) {
544 corr1 += Logic1[j] * GraphBuffer[i + (j / skip)];
546 for (j = 0; j < ARRAYLEN(FrameEOF); j += skip) {
547 corrEOF += FrameEOF[j] * GraphBuffer[i + (j / skip)];
549 // Even things out by the length of the target waveform.
550 corr0 *= 4;
551 corr1 *= 4;
553 if (corrEOF > corr1 && corrEOF > corr0) {
554 PrintAndLogEx(INFO, "EOF at %d", i);
555 break;
556 } else if (corr1 > corr0) {
557 i += ARRAYLEN(Logic1) / skip;
558 outBuf[k] |= mask;
559 } else {
560 i += ARRAYLEN(Logic0) / skip;
563 mask <<= 1;
564 if (mask == 0) {
565 k++;
566 mask = 0x01;
569 if ((i + (int)ARRAYLEN(FrameEOF)) >= GraphTraceLen) {
570 PrintAndLogEx(INFO, "ran off end!");
571 break;
574 if (k > 2048) {
575 PrintAndLogEx(INFO, "ran out of buffer");
576 break;
580 if (mask != 0x01) {
581 PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)");
582 PrintAndLogEx(INFO, " mask = %02x", mask);
585 if (k == 0) {
586 return PM3_SUCCESS;
589 i = 0;
590 PrintAndLogEx(NORMAL, "");
591 PrintAndLogEx(INFO, "Got %d octets, decoded as following", k);
592 PrintAndLogEx(NORMAL, "");
593 PrintAndLogEx(SUCCESS, " idx | data");
594 PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------");
595 if (k / 16 > 0) {
596 for (; i < k; i += 16) {
597 PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, 16));
601 uint8_t mod = (k % 16);
602 if (mod > 0) {
603 PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, mod));
605 PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------");
606 if (k > 2) {
607 PrintAndLogEx(SUCCESS, "--> CRC %04x", Crc15(outBuf, k - 2));
609 PrintAndLogEx(NORMAL, "");
610 return PM3_SUCCESS;
613 // * Acquire Samples as Reader (enables carrier, sends inquiry)
614 //helptext
615 static int CmdHF15Samples(const char *Cmd) {
617 CLIParserContext *ctx;
618 CLIParserInit(&ctx, "hf 15 samples",
619 "Acquire samples as Reader (enables carrier, send inquiry\n"
620 "and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal",
621 "hf 15 samples");
623 void *argtable[] = {
624 arg_param_begin,
625 arg_param_end
627 CLIExecWithReturn(ctx, Cmd, argtable, false);
628 CLIParserFree(ctx);
630 clearCommandBuffer();
631 SendCommandNG(CMD_HF_ISO15693_ACQ_RAW_ADC, NULL, 0);
633 getSamples(0, true);
635 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 15 demod") "` to decode signal");
636 return PM3_SUCCESS;
639 // Get NXP system information from SLIX2 tag/VICC
640 static int NxpSysInfo(uint8_t *uid) {
642 if (uid == NULL) {
643 return PM3_EINVARG;
646 uint8_t req[PM3_CMD_DATA_SIZE] = {0};
647 uint8_t fast = 1;
648 uint8_t reply = 1;
649 uint16_t reqlen = 0;
651 req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
652 req[reqlen++] = ISO15693_GET_SYSTEM_INFO;
653 req[reqlen++] = 0x04; // IC manufacturer code
654 memcpy(req + 3, uid, 8); // add UID
655 reqlen += 8;
657 AddCrc15(req, reqlen);
658 reqlen += 2;
660 PacketResponseNG resp;
661 clearCommandBuffer();
662 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen);
663 if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
664 PrintAndLogEx(WARNING, "iso15693 timeout");
665 DropField();
666 return PM3_ETIMEOUT;
669 DropField();
671 int status = resp.oldarg[0];
672 if (status == PM3_ETEAROFF) {
673 return status;
676 if (status < 2) {
677 PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command");
678 return PM3_EWRONGANSWER;
681 uint8_t *recv = resp.data.asBytes;
683 if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
684 PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
685 return PM3_EWRONGANSWER;
688 bool support_signature = (recv[5] & 0x01);
689 bool support_easmode = (recv[4] & 0x03);
691 PrintAndLogEx(INFO, "--------- " _CYAN_("NXP Sysinfo") " ---------");
692 PrintAndLogEx(INFO, " raw : %s", sprint_hex(recv, 8));
693 PrintAndLogEx(INFO, " Password protection configuration:");
694 PrintAndLogEx(INFO, " * Page L read%s password protected", ((recv[2] & 0x01) ? "" : " not"));
695 PrintAndLogEx(INFO, " * Page L write%s password protected", ((recv[2] & 0x02) ? "" : " not"));
696 PrintAndLogEx(INFO, " * Page H read%s password protected", ((recv[2] & 0x08) ? "" : " not"));
697 PrintAndLogEx(INFO, " * Page H write%s password protected", ((recv[2] & 0x20) ? "" : " not"));
699 PrintAndLogEx(INFO, " Lock bits:");
700 PrintAndLogEx(INFO, " * AFI%s locked", ((recv[3] & 0x01) ? "" : " not")); // AFI lock bit
701 PrintAndLogEx(INFO, " * EAS%s locked", ((recv[3] & 0x02) ? "" : " not")); // EAS lock bit
702 PrintAndLogEx(INFO, " * DSFID%s locked", ((recv[3] & 0x03) ? "" : " not")); // DSFID lock bit
703 PrintAndLogEx(INFO, " * Password protection configuration%s locked", ((recv[3] & 0x04) ? "" : " not")); // Password protection pointer address and access conditions lock bit
705 PrintAndLogEx(INFO, " Features:");
706 PrintAndLogEx(INFO, " * User memory password protection%s supported", ((recv[4] & 0x01) ? "" : " not"));
707 PrintAndLogEx(INFO, " * Counter feature%s supported", ((recv[4] & 0x02) ? "" : " not"));
708 PrintAndLogEx(INFO, " * EAS ID%s supported by EAS ALARM command", support_easmode ? "" : " not");
709 PrintAndLogEx(INFO, " * EAS password protection%s supported", ((recv[4] & 0x04) ? "" : " not"));
710 PrintAndLogEx(INFO, " * AFI password protection%s supported", ((recv[4] & 0x10) ? "" : " not"));
711 PrintAndLogEx(INFO, " * Extended mode%s supported by INVENTORY READ command", ((recv[4] & 0x20) ? "" : " not"));
712 PrintAndLogEx(INFO, " * EAS selection%s supported by extended mode in INVENTORY READ command", ((recv[4] & 0x40) ? "" : " not"));
713 PrintAndLogEx(INFO, " * READ SIGNATURE command%s supported", support_signature ? "" : " not");
714 PrintAndLogEx(INFO, " * Password protection for READ SIGNATURE command%s supported", ((recv[5] & 0x02) ? "" : " not"));
715 PrintAndLogEx(INFO, " * STAY QUIET PERSISTENT command%s supported", ((recv[5] & 0x03) ? "" : " not"));
716 PrintAndLogEx(INFO, " * ENABLE PRIVACY command%s supported", ((recv[5] & 0x10) ? "" : " not"));
717 PrintAndLogEx(INFO, " * DESTROY command%s supported", ((recv[5] & 0x20) ? "" : " not"));
718 PrintAndLogEx(INFO, " * Additional 32 bits feature flags are%s transmitted", ((recv[5] & 0x80) ? "" : " not"));
720 if (support_easmode) {
721 reqlen = 0;
722 req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
723 req[reqlen++] = ISO15693_EAS_ALARM;
724 req[reqlen++] = 0x04; // IC manufacturer code
725 memcpy(req + 3, uid, 8); // add UID
726 reqlen += 8;
728 AddCrc15(req, reqlen);
729 reqlen += 2;
731 clearCommandBuffer();
732 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen);
734 if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
735 PrintAndLogEx(WARNING, "iso15693 timeout");
736 } else {
737 PrintAndLogEx(NORMAL, "");
739 status = resp.oldarg[0];
740 if (status < 2) {
741 PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is not active");
742 } else {
743 recv = resp.data.asBytes;
745 if (!(recv[0] & ISO15_RES_ERROR)) {
746 PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is active.");
747 PrintAndLogEx(INFO, " EAS sequence: %s", sprint_hex(recv + 1, 32));
753 if (support_signature) {
754 // Check if we can also read the signature
755 reqlen = 0;
756 req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
757 req[reqlen++] = ISO15693_READ_SIGNATURE;
758 req[reqlen++] = 0x04; // IC manufacturer code
759 memcpy(req + 3, uid, 8); // add UID
760 reqlen += 8;
762 AddCrc15(req, reqlen);
763 reqlen += 2;
765 clearCommandBuffer();
766 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen);
768 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
769 PrintAndLogEx(WARNING, "iso15693 timeout");
770 DropField();
771 return PM3_ETIMEOUT;
774 DropField();
776 status = resp.oldarg[0];
777 if (status < 2) {
778 PrintAndLogEx(WARNING, "iso15693 card doesn't answer to READ SIGNATURE command");
779 return PM3_EWRONGANSWER;
782 recv = resp.data.asBytes;
784 if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
785 PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
786 return PM3_EWRONGANSWER;
789 uint8_t signature[32] = {0x00};
790 memcpy(signature, recv + 1, 32);
792 nxp_15693_print_signature(uid, signature);
795 return PM3_SUCCESS;
799 * Commandline handling: HF15 CMD SYSINFO
800 * get system information from tag/VICC
802 static int CmdHF15Info(const char *Cmd) {
804 CLIParserContext *ctx;
805 CLIParserInit(&ctx, "hf 15 info",
806 "Uses the optional command `get_systeminfo` 0x2B to try and extract information",
807 "hf 15 info\n"
808 "hf 15 info -*\n"
809 "hf 15 info -u E011223344556677"
812 void *argtable[6 + 1] = {};
813 uint8_t arglen = arg_add_default(argtable);
814 argtable[arglen++] = arg_param_end;
816 CLIExecWithReturn(ctx, Cmd, argtable, true);
818 uint8_t uid[8];
819 int uidlen = 0;
820 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
821 bool unaddressed = arg_get_lit(ctx, 2);
822 bool scan = arg_get_lit(ctx, 3);
823 int fast = (arg_get_lit(ctx, 4) == false);
824 bool add_option = arg_get_lit(ctx, 5);
826 CLIParserFree(ctx);
828 // sanity checks
829 if ((scan + unaddressed + uidlen) > 1) {
830 PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
831 return PM3_EINVARG;
834 // default fallback to scan for tag.
835 if (unaddressed == false && uidlen != 8) {
836 scan = true;
839 // request to be sent to device/card
840 uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
841 uint8_t req[PM3_CMD_DATA_SIZE] = {flags, ISO15693_GET_SYSTEM_INFO};
842 uint16_t reqlen = 2;
844 if (scan) {
845 if (getUID(false, uid) != PM3_SUCCESS) {
846 PrintAndLogEx(WARNING, "no tag found");
847 return PM3_EINVARG;
849 uidlen = 8;
852 if (uidlen == 8) {
853 // add UID (scan, uid)
854 memcpy(req + reqlen, uid, sizeof(uid));
855 reqlen += sizeof(uid);
857 PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
860 AddCrc15(req, reqlen);
861 reqlen += 2;
863 uint8_t read_response = 1;
864 PacketResponseNG resp;
865 clearCommandBuffer();
866 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_response, req, reqlen);
867 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
868 PrintAndLogEx(WARNING, "iso15693 timeout");
869 DropField();
870 return PM3_ETIMEOUT;
873 DropField();
875 int status = resp.oldarg[0];
876 if (status == PM3_ETEAROFF) {
877 return status;
879 if (status < 2) {
880 PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", status);
881 return PM3_EWRONGANSWER;
884 uint8_t *data = resp.data.asBytes;
886 if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
887 PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0]));
888 return PM3_EWRONGANSWER;
891 memcpy(uid, data + 2, sizeof(uid));
892 PrintAndLogEx(NORMAL, "");
893 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
894 PrintAndLogEx(INFO, "-------------------------------------------------------------");
895 PrintAndLogEx(SUCCESS, " TYPE: " _YELLOW_("%s"), getTagInfo_15(data + 2));
896 PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
897 PrintAndLogEx(SUCCESS, " SYSINFO: %s", sprint_hex(data, status - 2));
899 // DSFID
900 if (data[1] & 0x01)
901 PrintAndLogEx(SUCCESS, " - DSFID supported [0x%02X]", data[10]);
902 else
903 PrintAndLogEx(SUCCESS, " - DSFID not supported");
905 // AFI
906 if (data[1] & 0x02)
907 PrintAndLogEx(SUCCESS, " - AFI supported [0x%02X]", data[11]);
908 else
909 PrintAndLogEx(SUCCESS, " - AFI not supported");
911 // IC reference
912 if (data[1] & 0x08)
913 PrintAndLogEx(SUCCESS, " - IC reference supported [0x%02X]", data[14]);
914 else
915 PrintAndLogEx(SUCCESS, " - IC reference not supported");
917 // memory
918 if (data[1] & 0x04) {
919 PrintAndLogEx(SUCCESS, " - Tag provides info on memory layout (vendor dependent)");
920 uint8_t blocks = data[12] + 1;
921 uint8_t size = (data[13] & 0x1F);
922 PrintAndLogEx(SUCCESS, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks);
923 } else {
924 PrintAndLogEx(SUCCESS, " - Tag does not provide information on memory layout");
927 // Check if SLIX2 and attempt to get NXP System Information
928 PrintAndLogEx(DEBUG, "4 & 08 :: %02x 7 == 1 :: %u 8 == 4 :: %u", data[4], data[7], data[8]);
929 if (data[8] == 0x04 && data[7] == 0x01 && data[4] & 0x80) {
930 return NxpSysInfo(uid);
933 PrintAndLogEx(NORMAL, "");
934 return PM3_SUCCESS;
937 // Sniff Activity without enabling carrier
938 static int CmdHF15Sniff(const char *Cmd) {
939 CLIParserContext *ctx;
940 CLIParserInit(&ctx, "hf 15 sniff",
941 "Sniff activity without enabling carrier",
942 "hf 15 sniff\n");
944 void *argtable[] = {
945 arg_param_begin,
946 arg_param_end
948 CLIExecWithReturn(ctx, Cmd, argtable, true);
949 CLIParserFree(ctx);
951 PacketResponseNG resp;
952 clearCommandBuffer();
953 SendCommandNG(CMD_HF_ISO15693_SNIFF, NULL, 0);
955 WaitForResponse(CMD_HF_ISO15693_SNIFF, &resp);
957 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 15 list") "` to view captured tracelog");
958 PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing");
959 return PM3_SUCCESS;
962 static int CmdHF15Reader(const char *Cmd) {
963 CLIParserContext *ctx;
964 CLIParserInit(&ctx, "hf 15 reader",
965 "Act as a ISO-15693 reader. Look for ISO-15693 tags until Enter or the pm3 button is pressed\n",
966 "hf 15 reader\n"
967 "hf 15 reader -@ -> Continuous mode");
969 void *argtable[] = {
970 arg_param_begin,
971 arg_lit0("@", NULL, "continuous reader mode"),
972 arg_param_end
974 CLIExecWithReturn(ctx, Cmd, argtable, true);
975 bool cm = arg_get_lit(ctx, 1);
976 CLIParserFree(ctx);
978 if (cm) {
979 PrintAndLogEx(INFO, "press " _GREEN_("`Enter`") " to exit");
981 readHF15Uid(cm, true);
982 return PM3_SUCCESS;
985 // Simulation is still not working very good
986 // helptext
987 static int CmdHF15Sim(const char *Cmd) {
989 CLIParserContext *ctx;
990 CLIParserInit(&ctx, "hf 15 sim",
991 "Simulate a ISO-15693 tag\n",
992 "hf 15 sim -u E011223344556677");
994 void *argtable[] = {
995 arg_param_begin,
996 arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"),
997 arg_param_end
999 CLIExecWithReturn(ctx, Cmd, argtable, false);
1001 struct {
1002 uint8_t uid[8];
1003 } PACKED payload;
1005 int uidlen = 0;
1006 CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
1007 CLIParserFree(ctx);
1009 if (uidlen != 8) {
1010 PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
1011 return PM3_EINVARG;
1014 PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid));
1015 PrintAndLogEx(INFO, "press " _YELLOW_("`Pm3 button`") " to cancel");
1017 PacketResponseNG resp;
1018 clearCommandBuffer();
1019 SendCommandNG(CMD_HF_ISO15693_SIMULATE, (uint8_t *)&payload, sizeof(payload));
1020 WaitForResponse(CMD_HF_ISO15693_SIMULATE, &resp);
1021 return PM3_SUCCESS;
1024 // finds the AFI (Application Family Identifier) of a card, by trying all values
1025 // (There is no standard way of reading the AFI, although some tags support this)
1026 // helptext
1027 static int CmdHF15FindAfi(const char *Cmd) {
1028 CLIParserContext *ctx;
1029 CLIParserInit(&ctx, "hf 15 findafi",
1030 "This command attempts to brute force AFI of an ISO-15693 tag\n"
1031 "Estimated execution time is around 2 minutes",
1032 "hf 15 findafi");
1034 void *argtable[] = {
1035 arg_param_begin,
1036 arg_param_end
1038 CLIExecWithReturn(ctx, Cmd, argtable, true);
1039 CLIParserFree(ctx);
1041 PrintAndLogEx(INFO, "click " _GREEN_("pm3 button") " or press " _GREEN_("Enter") " to exit");
1042 clearCommandBuffer();
1043 PacketResponseNG resp;
1044 SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0);
1046 uint32_t timeout = 0;
1047 for (;;) {
1049 if (kbd_enter_pressed()) {
1050 SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
1051 PrintAndLogEx(DEBUG, "User aborted");
1052 msleep(300);
1053 break;
1056 if (WaitForResponseTimeout(CMD_HF_ISO15693_FINDAFI, &resp, 2000)) {
1057 if (resp.status == PM3_EOPABORTED) {
1058 PrintAndLogEx(DEBUG, "Button pressed, user aborted");
1060 break;
1063 // should be done in about 2 minutes
1064 if (timeout > 180) {
1065 PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting...");
1066 break;
1068 timeout++;
1071 DropField();
1072 PrintAndLogEx(INFO, "Done");
1073 return PM3_SUCCESS;
1076 // Writes the AFI (Application Family Identifier) of a card
1077 static int CmdHF15WriteAfi(const char *Cmd) {
1078 CLIParserContext *ctx;
1079 CLIParserInit(&ctx, "hf 15 writeafi",
1080 "Write AFI on card",
1081 "hf 15 writeafi -* --afi 12\n"
1082 "hf 15 writeafi -u E011223344556677 --afi 12"
1085 void *argtable[6 + 2] = {};
1086 uint8_t arglen = arg_add_default(argtable);
1087 argtable[arglen++] = arg_int1(NULL, "afi", "<dec>", "AFI number (0-255)");
1088 argtable[arglen++] = arg_param_end;
1090 CLIExecWithReturn(ctx, Cmd, argtable, false);
1092 uint8_t uid[8];
1093 int uidlen = 0;
1094 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
1095 bool unaddressed = arg_get_lit(ctx, 2);
1096 bool scan = arg_get_lit(ctx, 3);
1097 int fast = (arg_get_lit(ctx, 4) == false);
1098 bool add_option = arg_get_lit(ctx, 5);
1100 int afi = arg_get_int_def(ctx, 6, 0);
1101 CLIParserFree(ctx);
1103 // sanity checks
1104 if ((scan + unaddressed + uidlen) > 1) {
1105 PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
1106 return PM3_EINVARG;
1109 // request to be sent to device/card
1110 uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
1111 uint8_t req[16] = {flags, ISO15693_WRITE_AFI};
1112 uint16_t reqlen = 2;
1114 if (unaddressed == false) {
1115 if (scan) {
1116 if (getUID(false, uid) != PM3_SUCCESS) {
1117 PrintAndLogEx(WARNING, "no tag found");
1118 return PM3_EINVARG;
1120 uidlen = 8;
1123 if (uidlen == 8) {
1124 // add UID (scan, uid)
1125 memcpy(req + reqlen, uid, sizeof(uid));
1126 reqlen += sizeof(uid);
1128 PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
1131 // enforce, since we are writing
1132 req[0] |= ISO15_REQ_OPTION;
1134 req[reqlen++] = (uint8_t)afi;
1136 AddCrc15(req, reqlen);
1137 reqlen += 2;
1139 // arg: len, speed, recv?
1140 // arg0 (datalen, cmd len? .arg0 == crc?)
1141 // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
1142 // arg2 (recv == 1 == expect a response)
1143 uint8_t read_respone = 1;
1145 PacketResponseNG resp;
1146 clearCommandBuffer();
1147 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen);
1149 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
1150 PrintAndLogEx(ERR, "iso15693 timeout");
1151 DropField();
1152 return PM3_ETIMEOUT;
1154 DropField();
1156 int status = resp.oldarg[0];
1157 if (status == PM3_ETEAROFF) {
1158 return status;
1161 uint8_t *data = resp.data.asBytes;
1163 if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
1164 PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0]));
1165 return PM3_EWRONGANSWER;
1168 PrintAndLogEx(NORMAL, "");
1169 PrintAndLogEx(SUCCESS, "Wrote AFI 0x%02X", afi);
1170 return PM3_SUCCESS;
1173 // Writes the DSFID (Data Storage Format Identifier) of a card
1174 static int CmdHF15WriteDsfid(const char *Cmd) {
1175 CLIParserContext *ctx;
1176 CLIParserInit(&ctx, "hf 15 writedsfid",
1177 "Write DSFID on card",
1178 "hf 15 writedsfid -* --dsfid 12\n"
1179 "hf 15 writedsfid -u E011223344556677 --dsfid 12"
1182 void *argtable[6 + 2] = {};
1183 uint8_t arglen = arg_add_default(argtable);
1184 argtable[arglen++] = arg_int1(NULL, "dsfid", "<dec>", "DSFID number (0-255)");
1185 argtable[arglen++] = arg_param_end;
1187 CLIExecWithReturn(ctx, Cmd, argtable, false);
1189 uint8_t uid[8];
1190 int uidlen = 0;
1191 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
1192 bool unaddressed = arg_get_lit(ctx, 2);
1193 bool scan = arg_get_lit(ctx, 3);
1194 int fast = (arg_get_lit(ctx, 4) == false);
1195 bool add_option = arg_get_lit(ctx, 5);
1197 int dsfid = arg_get_int_def(ctx, 6, 0);
1198 CLIParserFree(ctx);
1200 // sanity checks
1201 if ((scan + unaddressed + uidlen) > 1) {
1202 PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
1203 return PM3_EINVARG;
1206 // request to be sent to device/card
1207 uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
1208 uint8_t req[16] = {flags, ISO15693_WRITE_DSFID};
1209 // enforce, since we are writing
1210 req[0] |= ISO15_REQ_OPTION;
1211 uint16_t reqlen = 2;
1213 if (unaddressed == false) {
1214 if (scan) {
1215 if (getUID(false, uid) != PM3_SUCCESS) {
1216 PrintAndLogEx(WARNING, "no tag found");
1217 return PM3_EINVARG;
1219 uidlen = 8;
1222 if (uidlen == 8) {
1223 // add UID (scan, uid)
1224 memcpy(req + reqlen, uid, sizeof(uid));
1225 reqlen += sizeof(uid);
1227 PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
1230 // dsfid
1231 req[reqlen++] = (uint8_t)dsfid;
1233 AddCrc15(req, reqlen);
1234 reqlen += 2;
1237 // arg: len, speed, recv?
1238 // arg0 (datalen, cmd len? .arg0 == crc?)
1239 // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
1240 // arg2 (recv == 1 == expect a response)
1241 uint8_t read_respone = 1;
1243 PrintAndLogEx(DEBUG, "cmd %s", sprint_hex(req, reqlen));
1244 PacketResponseNG resp;
1245 clearCommandBuffer();
1246 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen);
1248 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
1249 PrintAndLogEx(ERR, "iso15693 timeout");
1250 DropField();
1251 return PM3_ETIMEOUT;
1254 DropField();
1255 int status = resp.oldarg[0];
1256 if (status == PM3_ETEAROFF) {
1257 return status;
1260 uint8_t *data = resp.data.asBytes;
1262 if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
1263 PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0]));
1264 return PM3_EWRONGANSWER;
1267 PrintAndLogEx(NORMAL, "");
1268 PrintAndLogEx(SUCCESS, "Wrote DSFID 0x%02X", dsfid);
1269 return PM3_SUCCESS;
1272 // Reads all memory pages
1273 // need to write to file
1274 static int CmdHF15Dump(const char *Cmd) {
1275 CLIParserContext *ctx;
1276 CLIParserInit(&ctx, "hf 15 dump",
1277 "This command dumps the contents of a ISO-15693 tag and save it to file",
1278 "hf 15 dump\n"
1279 "hf 15 dump -*\n"
1280 "hf 15 dump -u E011223344556677 -f hf-15-my-dump.bin"
1283 void *argtable[6 + 2] = {};
1284 uint8_t arglen = arg_add_default(argtable);
1285 argtable[arglen++] = arg_str0("f", "file", "<fn>", "filename of dump"),
1286 argtable[arglen++] = arg_param_end;
1288 CLIExecWithReturn(ctx, Cmd, argtable, true);
1290 uint8_t uid[8];
1291 int uidlen = 0;
1292 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
1293 bool unaddressed = arg_get_lit(ctx, 2);
1294 bool scan = arg_get_lit(ctx, 3);
1295 int fast = (arg_get_lit(ctx, 4) == false);
1296 bool add_option = arg_get_lit(ctx, 5);
1298 int fnlen = 0;
1299 char filename[FILE_PATH_SIZE] = {0};
1300 CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1302 CLIParserFree(ctx);
1304 // sanity checks
1305 if ((scan + unaddressed + uidlen) > 1) {
1306 PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
1307 return PM3_EINVARG;
1310 // default fallback to scan for tag.
1311 // overriding unaddress parameter :)
1312 if (uidlen != 8) {
1313 scan = true;
1316 // request to be sent to device/card
1317 uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
1318 uint8_t req[13] = {flags, ISO15693_READBLOCK};
1319 uint16_t reqlen = 2;
1321 if (scan) {
1322 if (getUID(false, uid) != PM3_SUCCESS) {
1323 PrintAndLogEx(WARNING, "no tag found");
1324 return PM3_EINVARG;
1326 uidlen = 8;
1329 if (uidlen == 8) {
1330 // add UID (scan, uid)
1331 memcpy(req + reqlen, uid, sizeof(uid));
1332 reqlen += sizeof(uid);
1334 PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
1336 // detect blocksize from card :)
1338 PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, uid));
1340 int blocknum = 0;
1341 // memory.
1342 t15memory_t mem[256];
1344 uint8_t data[256 * 4] = {0};
1345 memset(data, 0, sizeof(data));
1347 PrintAndLogEx(INFO, "." NOLF);
1348 for (int retry = 0; retry < 5; retry++) {
1350 req[10] = blocknum;
1351 AddCrc15(req, 11);
1353 // arg: len, speed, recv?
1354 // arg0 (datalen, cmd len? .arg0 == crc?)
1355 // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
1356 // arg2 (recv == 1 == expect a response)
1357 uint8_t read_respone = 1;
1358 PacketResponseNG resp;
1359 clearCommandBuffer();
1360 SendCommandMIX(CMD_HF_ISO15693_COMMAND, sizeof(req), fast, read_respone, req, sizeof(req));
1362 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
1364 int len = resp.oldarg[0];
1365 if (len == PM3_ETEAROFF) {
1366 continue;
1368 if (len < 2) {
1369 PrintAndLogEx(NORMAL, "");
1370 PrintAndLogEx(FAILED, "iso15693 command failed");
1371 continue;
1374 uint8_t *recv = resp.data.asBytes;
1376 if (CheckCrc15(recv, len) == false) {
1377 PrintAndLogEx(NORMAL, "");
1378 PrintAndLogEx(FAILED, "crc (" _RED_("fail") ")");
1379 continue;
1382 if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
1383 PrintAndLogEx(NORMAL, "");
1384 PrintAndLogEx(FAILED, "Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1]));
1385 break;
1388 mem[blocknum].lock = resp.data.asBytes[0];
1389 memcpy(mem[blocknum].block, resp.data.asBytes + 1, 4);
1390 memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4);
1392 retry = 0;
1393 blocknum++;
1395 PrintAndLogEx(NORMAL, "." NOLF);
1396 fflush(stdout);
1400 DropField();
1402 PrintAndLogEx(NORMAL, "");
1403 PrintAndLogEx(INFO, "block# | data |lck| ascii");
1404 PrintAndLogEx(INFO, "---------+--------------+---+----------");
1405 for (int i = 0; i < blocknum; i++) {
1406 char lck[16] = {0};
1407 if (mem[i].lock) {
1408 sprintf(lck, _RED_("%d"), mem[i].lock);
1409 } else {
1410 sprintf(lck, "%d", mem[i].lock);
1412 PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s"
1415 , sprint_hex(mem[i].block, 4)
1416 , lck
1417 , sprint_ascii(mem[i].block, 4)
1420 PrintAndLogEx(NORMAL, "");
1422 // user supplied filename ?
1423 if (strlen(filename) < 1) {
1424 char *fptr = filename;
1425 PrintAndLogEx(INFO, "Using UID as filename");
1426 fptr += snprintf(fptr, sizeof(filename), "hf-15-");
1427 FillFileNameByUID(fptr, SwapEndian64(uid, sizeof(uid), 8), "-dump", sizeof(uid));
1430 size_t datalen = blocknum * 4;
1431 saveFile(filename, ".bin", data, datalen);
1432 saveFileEML(filename, data, datalen, 4);
1433 saveFileJSON(filename, jsf15, data, datalen, NULL);
1434 return PM3_SUCCESS;
1437 static int CmdHF15List(const char *Cmd) {
1438 return CmdTraceListAlias(Cmd, "hf 15", "15");
1441 static int CmdHF15Raw(const char *Cmd) {
1442 CLIParserContext *ctx;
1443 CLIParserInit(&ctx, "hf 15 raw",
1444 "Sends raw bytes over ISO-15693 to card",
1445 "hf 15 raw -c -d 260100 --> add crc\n"
1446 "hf 15 raw -krc -d 260100 --> add crc, keep field on, skip response"
1449 void *argtable[] = {
1450 arg_param_begin,
1451 arg_lit0("2", NULL, "use slower '1 out of 256' mode"),
1452 arg_lit0("c", "crc", "calculate and append CRC"),
1453 arg_lit0("k", NULL, "keep signal field ON after receive"),
1454 arg_lit0("r", NULL, "do not read response"),
1455 arg_strx1("d", "data", "<hex>", "raw bytes to send"),
1456 arg_param_end
1458 CLIExecWithReturn(ctx, Cmd, argtable, false);
1459 int fast = (arg_get_lit(ctx, 1) == false);
1460 bool crc = arg_get_lit(ctx, 2);
1461 bool keep_field_on = arg_get_lit(ctx, 3);
1462 bool read_respone = (arg_get_lit(ctx, 4) == false);
1463 int datalen = 0;
1464 uint8_t data[300];
1465 CLIGetHexWithReturn(ctx, 5, data, &datalen);
1466 CLIParserFree(ctx);
1468 if (crc) {
1469 AddCrc15(data, datalen);
1470 datalen += 2;
1473 // arg: len, speed, recv?
1474 // arg0 (datalen, cmd len? .arg0 == crc?)
1475 // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
1476 // arg2 (recv == 1 == expect a response)
1477 PacketResponseNG resp;
1478 clearCommandBuffer();
1479 SendCommandMIX(CMD_HF_ISO15693_COMMAND, datalen, fast, read_respone, data, datalen);
1481 if (read_respone) {
1482 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
1483 int len = resp.oldarg[0];
1484 if (len == PM3_ETEAROFF) {
1485 DropField();
1486 return len;
1488 if (len < 2) {
1489 PrintAndLogEx(WARNING, "command failed");
1490 } else {
1491 PrintAndLogEx(SUCCESS, "received %i octets", len);
1492 PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, len));
1494 } else {
1495 PrintAndLogEx(WARNING, "timeout while waiting for reply");
1499 if (keep_field_on == false) {
1500 DropField();
1502 return PM3_SUCCESS;
1506 * Commandline handling: HF15 CMD READMULTI
1507 * Read multiple blocks at once (not all tags support this)
1509 static int CmdHF15Readmulti(const char *Cmd) {
1510 CLIParserContext *ctx;
1511 CLIParserInit(&ctx, "hf 15 rdmulti",
1512 "Read multiple pages on a ISO-15693 tag ",
1513 "hf 15 rdmulti -* -b 1 --cnt 6 -> read 6 blocks\n"
1514 "hf 15 rdmulti -u E011223344556677 -b 12 --cnt 3 -> read three blocks"
1517 void *argtable[6 + 3] = {};
1518 uint8_t arglen = arg_add_default(argtable);
1519 argtable[arglen++] = arg_int1("b", NULL, "<dec>", "first page number (0-255)");
1520 argtable[arglen++] = arg_int1(NULL, "cnt", "<dec>", "number of pages (1-6)");
1521 argtable[arglen++] = arg_param_end;
1523 CLIExecWithReturn(ctx, Cmd, argtable, false);
1525 uint8_t uid[8];
1526 int uidlen = 0;
1527 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
1528 bool unaddressed = arg_get_lit(ctx, 2);
1529 bool scan = arg_get_lit(ctx, 3);
1530 int fast = (arg_get_lit(ctx, 4) == false);
1531 bool add_option = arg_get_lit(ctx, 5);
1533 int block = arg_get_int_def(ctx, 6, 0);
1534 int blockcnt = arg_get_int_def(ctx, 7, 0);
1536 CLIParserFree(ctx);
1538 // sanity checks
1539 if (blockcnt > 6) {
1540 PrintAndLogEx(WARNING, "Page count must be 6 or less (%d)", blockcnt);
1541 return PM3_EINVARG;
1544 if ((scan + unaddressed + uidlen) > 1) {
1545 PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
1546 return PM3_EINVARG;
1549 // request to be sent to device/card
1550 uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
1551 uint8_t req[PM3_CMD_DATA_SIZE] = {flags, ISO15693_READ_MULTI_BLOCK};
1552 uint16_t reqlen = 2;
1554 if (unaddressed == false) {
1555 if (scan) {
1556 if (getUID(false, uid) != PM3_SUCCESS) {
1557 PrintAndLogEx(WARNING, "no tag found");
1558 return PM3_EINVARG;
1560 uidlen = 8;
1563 if (uidlen == 8) {
1564 // add UID (scan, uid)
1565 memcpy(req + reqlen, uid, sizeof(uid));
1566 reqlen += sizeof(uid);
1568 PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
1570 // add OPTION flag, in order to get lock-info
1571 req[0] |= ISO15_REQ_OPTION;
1573 // 0 means 1 page,
1574 // 1 means 2 pages, ...
1575 if (blockcnt > 0) blockcnt--;
1577 req[reqlen++] = block;
1578 req[reqlen++] = blockcnt;
1580 AddCrc15(req, reqlen);
1581 reqlen += 2;
1583 uint8_t read_respone = 1;
1584 PacketResponseNG resp;
1585 clearCommandBuffer();
1586 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen);
1588 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
1589 PrintAndLogEx(FAILED, "iso15693 card timeout");
1590 DropField();
1591 return PM3_ETIMEOUT;
1594 DropField();
1596 int status = resp.oldarg[0];
1597 if (status == PM3_ETEAROFF) {
1598 return status;
1601 if (status < 2) {
1602 PrintAndLogEx(FAILED, "iso15693 card readmulti failed");
1603 return PM3_EWRONGANSWER;
1606 uint8_t *data = resp.data.asBytes;
1608 if (CheckCrc15(data, status) == false) {
1609 PrintAndLogEx(FAILED, "crc (" _RED_("fail") ")");
1610 return PM3_ESOFT;
1613 if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
1614 PrintAndLogEx(FAILED, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0]));
1615 return PM3_EWRONGANSWER;
1618 // skip status byte
1619 int start = 1;
1620 int stop = (blockcnt + 1) * 5;
1621 int currblock = block;
1623 PrintAndLogEx(NORMAL, "");
1624 PrintAndLogEx(INFO, " # | data |lck| ascii");
1625 PrintAndLogEx(INFO, "---------+--------------+---+----------");
1627 for (int i = start; i < stop; i += 5) {
1628 char lck[16] = {0};
1629 if (data[i]) {
1630 sprintf(lck, _RED_("%d"), data[i]);
1631 } else {
1632 sprintf(lck, "%d", data[i]);
1634 PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s", currblock, currblock, sprint_hex(data + i + 1, 4), lck, sprint_ascii(data + i + 1, 4));
1635 currblock++;
1637 PrintAndLogEx(NORMAL, "");
1638 return PM3_SUCCESS;
1642 * Commandline handling: HF15 CMD READ
1643 * Reads a single Block
1645 static int CmdHF15Readblock(const char *Cmd) {
1646 CLIParserContext *ctx;
1647 CLIParserInit(&ctx, "hf 15 rdbl",
1648 "Read page on ISO-15693 tag",
1649 "hf 15 rdbl -* -b 12\n"
1650 "hf 15 rdbl -u E011223344556677 -b 12"
1653 void *argtable[6 + 2] = {};
1654 uint8_t arglen = arg_add_default(argtable);
1655 argtable[arglen++] = arg_int1("b", "blk", "<dec>", "page number (0-255)");
1656 argtable[arglen++] = arg_param_end;
1658 CLIExecWithReturn(ctx, Cmd, argtable, false);
1660 uint8_t uid[8];
1661 int uidlen = 0;
1662 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
1663 bool unaddressed = arg_get_lit(ctx, 2);
1664 bool scan = arg_get_lit(ctx, 3);
1665 int fast = (arg_get_lit(ctx, 4) == false);
1666 bool add_option = arg_get_lit(ctx, 5);
1668 int block = arg_get_int_def(ctx, 6, 0);
1669 CLIParserFree(ctx);
1671 // sanity checks
1672 if ((scan + unaddressed + uidlen) > 1) {
1673 PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
1674 return PM3_EINVARG;
1677 // default fallback to scan for tag.
1678 // overriding unaddress parameter :)
1679 if (uidlen != 8) {
1680 scan = true;
1683 // request to be sent to device/card
1684 uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
1685 uint8_t req[PM3_CMD_DATA_SIZE] = {flags, ISO15693_READBLOCK};
1686 uint16_t reqlen = 2;
1688 if (unaddressed == false) {
1689 if (scan) {
1690 if (getUID(false, uid) != PM3_SUCCESS) {
1691 PrintAndLogEx(WARNING, "no tag found");
1692 return PM3_EINVARG;
1694 uidlen = 8;
1697 if (uidlen == 8) {
1698 // add UID (scan, uid)
1699 memcpy(req + reqlen, uid, sizeof(uid));
1700 reqlen += sizeof(uid);
1702 PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
1704 // add OPTION flag, in order to get lock-info
1705 req[0] |= ISO15_REQ_OPTION;
1707 req[reqlen++] = (uint8_t)block;
1709 AddCrc15(req, reqlen);
1710 reqlen += 2;
1712 // arg: len, speed, recv?
1713 // arg0 (datalen, cmd len? .arg0 == crc?)
1714 // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 )
1715 // arg2 (recv == 1 == expect a response)
1716 uint8_t read_respone = 1;
1717 PacketResponseNG resp;
1718 clearCommandBuffer();
1719 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen);
1721 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
1722 PrintAndLogEx(ERR, "iso15693 timeout");
1723 DropField();
1724 return PM3_ETIMEOUT;
1727 DropField();
1729 int status = resp.oldarg[0];
1730 if (status == PM3_ETEAROFF) {
1731 return status;
1733 if (status < 2) {
1734 PrintAndLogEx(ERR, "iso15693 command failed");
1735 return PM3_EWRONGANSWER;
1738 uint8_t *data = resp.data.asBytes;
1740 if (CheckCrc15(data, status) == false) {
1741 PrintAndLogEx(FAILED, "crc (" _RED_("fail") ")");
1742 return PM3_ESOFT;
1745 if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
1746 PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0]));
1747 return PM3_EWRONGANSWER;
1750 // print response
1751 char lck[16] = {0};
1752 if (data[1]) {
1753 sprintf(lck, _RED_("%d"), data[1]);
1754 } else {
1755 sprintf(lck, "%d", data[1]);
1757 PrintAndLogEx(NORMAL, "");
1758 PrintAndLogEx(INFO, " #%3d |lck| ascii", block);
1759 PrintAndLogEx(INFO, "------------+---+------");
1760 PrintAndLogEx(INFO, "%s| %s | %s", sprint_hex(data + 2, status - 4), lck, sprint_ascii(data + 2, status - 4));
1761 PrintAndLogEx(NORMAL, "");
1762 return PM3_SUCCESS;
1765 static int hf_15_write_blk(bool verbose, bool fast, uint8_t *req, uint8_t reqlen) {
1767 uint8_t read_response = 1;
1768 clearCommandBuffer();
1769 SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_response, req, reqlen);
1770 PacketResponseNG resp;
1771 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
1772 PrintAndLogEx(FAILED, "iso15693 card timeout, data may be written anyway");
1773 DropField();
1774 return PM3_ETIMEOUT;
1777 DropField();
1778 int status = resp.oldarg[0];
1779 if (status == PM3_ETEAROFF) {
1780 return status;
1783 if (status < 2) {
1784 if (verbose) {
1785 PrintAndLogEx(FAILED, "iso15693 command failed");
1787 return PM3_EWRONGANSWER;
1790 uint8_t *recv = resp.data.asBytes;
1791 if (CheckCrc15(recv, status) == false) {
1792 if (verbose) {
1793 PrintAndLogEx(FAILED, "crc (" _RED_("fail") ")");
1795 return PM3_ESOFT;
1798 if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
1799 if (verbose) {
1800 PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0]));
1802 return PM3_EWRONGANSWER;
1804 return PM3_SUCCESS;
1808 * Commandline handling: HF15 CMD WRITE
1809 * Writes a single Block - might run into timeout, even when successful
1811 static int CmdHF15Write(const char *Cmd) {
1812 CLIParserContext *ctx;
1813 CLIParserInit(&ctx, "hf 15 wrbl",
1814 "Write block on ISO-15693 tag",
1815 "hf 15 wrbl -* -b 12 -d AABBCCDD\n"
1816 "hf 15 wrbl -u E011223344556677 -b 12 -d AABBCCDD"
1819 void *argtable[6 + 4] = {};
1820 uint8_t arglen = arg_add_default(argtable);
1821 argtable[arglen++] = arg_int1("b", "blk", "<dec>", "page number (0-255)");
1822 argtable[arglen++] = arg_str1("d", "data", "<hex>", "data, 4 bytes");
1823 argtable[arglen++] = arg_lit0("v", "verbose", "verbose output");
1824 argtable[arglen++] = arg_param_end;
1825 CLIExecWithReturn(ctx, Cmd, argtable, false);
1827 uint8_t uid[8];
1828 int uidlen = 0;
1829 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
1830 bool unaddressed = arg_get_lit(ctx, 2);
1831 bool scan = arg_get_lit(ctx, 3);
1832 int fast = (arg_get_lit(ctx, 4) == false);
1833 bool add_option = arg_get_lit(ctx, 5);
1835 int block = arg_get_int_def(ctx, 6, 0);
1836 uint8_t d[4];
1837 int dlen = 0;
1838 CLIGetHexWithReturn(ctx, 7, d, &dlen);
1840 bool verbose = arg_get_lit(ctx, 8);
1841 CLIParserFree(ctx);
1843 // sanity checks
1844 if ((scan + unaddressed + uidlen) > 1) {
1845 PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
1846 return PM3_EINVARG;
1849 if (dlen != 4) {
1850 PrintAndLogEx(WARNING, "expected data, 4 bytes, got %d", dlen);
1851 return PM3_EINVARG;
1854 // default fallback to scan for tag.
1855 // overriding unaddress parameter :)
1856 if (uidlen != 8) {
1857 scan = true;
1860 // request to be sent to device/card
1861 uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
1862 uint8_t req[17] = {flags, ISO15693_WRITEBLOCK};
1864 // enforce, since we are writing
1865 req[0] |= ISO15_REQ_OPTION;
1866 uint16_t reqlen = 2;
1868 if (unaddressed == false) {
1869 if (scan) {
1870 if (getUID(false, uid) != PM3_SUCCESS) {
1871 PrintAndLogEx(WARNING, "no tag found");
1872 return PM3_EINVARG;
1874 uidlen = 8;
1877 if (uidlen == 8) {
1878 // add UID (scan, uid)
1879 memcpy(req + reqlen, uid, sizeof(uid));
1880 reqlen += sizeof(uid);
1882 PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
1886 req[reqlen++] = (uint8_t)block;
1887 memcpy(req + reqlen, d, sizeof(d));
1888 reqlen += sizeof(d);
1890 AddCrc15(req, reqlen);
1891 reqlen += 2;
1893 PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data [ %s ] ", block, block, sprint_hex(req, reqlen));
1895 int res = hf_15_write_blk(verbose, fast, req, reqlen);
1896 if (res == PM3_SUCCESS)
1897 PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
1898 else
1899 PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
1901 return PM3_SUCCESS;
1904 static int CmdHF15Restore(const char *Cmd) {
1905 CLIParserContext *ctx;
1906 CLIParserInit(&ctx, "hf 15 restore",
1907 "This command restore the contents of a dump file onto a ISO-15693 tag",
1908 "hf 15 restore\n"
1909 "hf 15 restore -*\n"
1910 "hf 15 restore -u E011223344556677 -f hf-15-my-dump.bin"
1913 void *argtable[6 + 5] = {};
1914 uint8_t arglen = arg_add_default(argtable);
1915 argtable[arglen++] = arg_str0("f", "file", "<fn>", "filename of dump"),
1916 argtable[arglen++] = arg_int0("r", "retry", "<dec>", "number of retries (def 3)"),
1917 argtable[arglen++] = arg_int0(NULL, "bs", "<dec>", "block size (def 4)"),
1918 argtable[arglen++] = arg_lit0("v", "verbose", "verbose output");
1919 argtable[arglen++] = arg_param_end;
1920 CLIExecWithReturn(ctx, Cmd, argtable, true);
1922 uint8_t uid[8];
1923 int uidlen = 0;
1924 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
1925 bool unaddressed = arg_get_lit(ctx, 2);
1926 bool scan = arg_get_lit(ctx, 3);
1927 int fast = (arg_get_lit(ctx, 4) == false);
1928 bool add_option = arg_get_lit(ctx, 5);
1930 int fnlen = 0;
1931 char filename[FILE_PATH_SIZE] = {0};
1932 CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1933 int retries = arg_get_int_def(ctx, 7, 3);
1934 int blocksize = arg_get_int_def(ctx, 8, 4);
1935 bool verbose = arg_get_lit(ctx, 9);
1936 CLIParserFree(ctx);
1938 // sanity checks
1939 if ((scan + unaddressed + uidlen) > 1) {
1940 PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
1941 return PM3_EINVARG;
1943 if (fnlen == 0) {
1944 PrintAndLogEx(WARNING, "please provide a filename");
1945 return PM3_EINVARG;
1948 // default fallback to scan for tag.
1949 // overriding unaddress parameter :)
1950 if (uidlen != 8) {
1951 scan = true;
1954 // request to be sent to device/card
1955 uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
1956 uint8_t req[17] = {flags, ISO15693_WRITEBLOCK};
1957 // enforce, since we are writing
1958 req[0] |= ISO15_REQ_OPTION;
1959 uint16_t reqlen = 2;
1961 if (unaddressed == false) {
1962 if (scan) {
1963 if (getUID(false, uid) != PM3_SUCCESS) {
1964 PrintAndLogEx(WARNING, "no tag found");
1965 return PM3_EINVARG;
1967 uidlen = 8;
1970 if (uidlen == 8) {
1971 // add UID (scan, uid)
1972 memcpy(req + reqlen, uid, sizeof(uid));
1973 reqlen += sizeof(uid);
1975 PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
1976 } else {
1977 PrintAndLogEx(SUCCESS, "Using unaddressed mode");
1979 PrintAndLogEx(INFO, "Using block size... %d", blocksize);
1981 // 4bytes * 256 blocks. Should be enough..
1982 uint8_t *data = NULL;
1983 size_t datalen = 0;
1984 int res = PM3_SUCCESS;
1985 DumpFileType_t dftype = getfiletype(filename);
1986 switch (dftype) {
1987 case BIN: {
1988 res = loadFile_safe(filename, ".bin", (void **)&data, &datalen);
1989 break;
1991 case EML: {
1992 res = loadFileEML_safe(filename, (void **)&data, &datalen);
1993 break;
1995 case JSON: {
1996 data = calloc(4 * 256, sizeof(uint8_t));
1997 if (data == NULL) {
1998 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1999 return PM3_EMALLOC;
2001 res = loadFileJSON(filename, (void *)data, 256 * 4, &datalen, NULL);
2002 break;
2004 case DICTIONARY: {
2005 PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
2006 free(data);
2007 return PM3_EINVARG;
2011 if (res != PM3_SUCCESS) {
2012 free(data);
2013 return PM3_EFILE;
2016 if ((datalen % blocksize) != 0) {
2017 PrintAndLogEx(WARNING, "datalen %zu isn't dividable with blocksize %d", datalen, blocksize);
2018 free(data);
2019 return PM3_ESOFT;
2022 PrintAndLogEx(INFO, "restoring data blocks");
2023 PrintAndLogEx(INFO, "." NOLF);
2024 fflush(stdout);
2026 int retval = PM3_SUCCESS;
2027 size_t bytes = 0;
2028 uint16_t i = 0;
2029 while (bytes < datalen) {
2031 req[reqlen + 1] = i;
2032 // copy over the data to the request
2033 memcpy(req + reqlen + 1, data + bytes, blocksize);
2034 AddCrc15(req, reqlen + 1 + blocksize);
2036 uint8_t tried = 0;
2037 for (tried = 0; tried < retries; tried++) {
2039 retval = hf_15_write_blk(verbose, fast, req, (reqlen + 1 + blocksize + 2));
2040 if (retval == PM3_SUCCESS) {
2041 PrintAndLogEx(NORMAL, "." NOLF);
2042 fflush(stdout);
2043 break;
2047 if (tried >= retries) {
2048 free(data);
2049 PrintAndLogEx(NORMAL, "");
2050 PrintAndLogEx(FAILED, "restore failed. Too many retries.");
2051 return retval;
2053 bytes += blocksize;
2054 i++;
2056 free(data);
2058 PrintAndLogEx(NORMAL, "");
2059 PrintAndLogEx(INFO, "done");
2060 PrintAndLogEx(HINT, "try `" _YELLOW_("hf 15 dump") "` to read your card to verify");
2061 return PM3_SUCCESS;
2065 * Commandline handling: HF15 CMD CSETUID
2066 * Set UID for magic Chinese card
2068 static int CmdHF15CSetUID(const char *Cmd) {
2070 CLIParserContext *ctx;
2071 CLIParserInit(&ctx, "hf 15 csetuid",
2072 "Set UID for magic Chinese card (only works with such cards)\n",
2073 "hf 15 csetuid -u E011223344556677");
2075 void *argtable[] = {
2076 arg_param_begin,
2077 arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"),
2078 arg_param_end
2080 CLIExecWithReturn(ctx, Cmd, argtable, false);
2082 struct {
2083 uint8_t uid[8];
2084 } PACKED payload;
2086 int uidlen = 0;
2087 CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
2088 CLIParserFree(ctx);
2090 if (uidlen != 8) {
2091 PrintAndLogEx(WARNING, "UID must include 16 HEX symbols got ");
2092 return PM3_EINVARG;
2095 if (payload.uid[0] != 0xE0) {
2096 PrintAndLogEx(WARNING, "UID must begin with the byte " _YELLOW_("E0"));
2097 return PM3_EINVARG;
2100 PrintAndLogEx(SUCCESS, "reverse input UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid));
2102 PrintAndLogEx(INFO, "getting current card details...");
2103 uint8_t carduid[8] = {0x00};
2104 if (getUID(false, carduid) != PM3_SUCCESS) {
2105 PrintAndLogEx(FAILED, "no tag found");
2106 return PM3_ESOFT;
2109 PrintAndLogEx(INFO, "updating tag uid...");
2111 PacketResponseNG resp;
2112 clearCommandBuffer();
2113 SendCommandNG(CMD_HF_ISO15693_CSETUID, (uint8_t *)&payload, sizeof(payload));
2114 if (WaitForResponseTimeout(CMD_HF_ISO15693_CSETUID, &resp, 2000) == false) {
2115 PrintAndLogEx(WARNING, "timeout while waiting for reply");
2116 DropField();
2117 return PM3_ESOFT;
2120 PrintAndLogEx(INFO, "getting updated card details...");
2122 if (getUID(false, carduid) != PM3_SUCCESS) {
2123 PrintAndLogEx(FAILED, "no tag found");
2124 return PM3_ESOFT;
2127 // reverse cardUID to compare
2128 uint8_t revuid[8] = {0};
2129 uint8_t i = 0;
2130 while (i < sizeof(revuid)) {
2131 revuid[i] = carduid[7 - i];
2132 i++;
2135 if (memcmp(revuid, payload.uid, 8) != 0) {
2136 PrintAndLogEx(FAILED, "setting new UID (" _RED_("failed") ")");
2137 return PM3_ESOFT;
2138 } else {
2139 PrintAndLogEx(SUCCESS, "setting new UID (" _GREEN_("ok") ")");
2140 return PM3_SUCCESS;
2144 static int CmdHF15SlixDisable(const char *Cmd) {
2146 CLIParserContext *ctx;
2147 CLIParserInit(&ctx, "hf 15 slixdisable",
2148 "Disable privacy mode on SLIX ISO-15693 tag",
2149 "hf 15 slixdisable -p 0F0F0F0F");
2151 void *argtable[] = {
2152 arg_param_begin,
2153 arg_str1("p", "pwd", "<hex>", "password, 8 hex bytes"),
2154 arg_param_end
2156 CLIExecWithReturn(ctx, Cmd, argtable, false);
2157 struct {
2158 uint8_t pwd[4];
2159 } PACKED payload;
2160 int pwdlen = 0;
2161 CLIGetHexWithReturn(ctx, 1, payload.pwd, &pwdlen);
2162 CLIParserFree(ctx);
2164 PrintAndLogEx(INFO, "Trying to disabling privacy mode using password " _GREEN_("%s")
2165 , sprint_hex_inrow(payload.pwd, sizeof(payload.pwd))
2168 PacketResponseNG resp;
2169 clearCommandBuffer();
2170 SendCommandNG(CMD_HF_ISO15693_SLIX_L_DISABLE_PRIVACY, (uint8_t *)&payload, sizeof(payload));
2171 if (WaitForResponseTimeout(CMD_HF_ISO15693_SLIX_L_DISABLE_PRIVACY, &resp, 2000) == false) {
2172 PrintAndLogEx(WARNING, "timeout while waiting for reply");
2173 DropField();
2174 return PM3_ESOFT;
2177 switch (resp.status) {
2178 case PM3_ETIMEOUT: {
2179 PrintAndLogEx(WARNING, "no tag found");
2180 break;
2182 case PM3_EWRONGANSWER: {
2183 PrintAndLogEx(WARNING, "password was not accepted");
2184 break;
2186 case PM3_SUCCESS: {
2187 PrintAndLogEx(SUCCESS, "privacy mode is now disabled ( " _GREEN_("ok") " ) ");
2188 break;
2191 return resp.status;
2194 static command_t CommandTable[] = {
2195 {"-----------", CmdHF15Help, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
2196 {"help", CmdHF15Help, AlwaysAvailable, "This help"},
2197 {"list", CmdHF15List, AlwaysAvailable, "List ISO-15693 history"},
2198 {"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO-15693 from tag"},
2199 {"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO-15693 tag, save to file"},
2200 {"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
2201 {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO-15693 traffic"},
2202 {"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"},
2203 {"rdbl", CmdHF15Readblock, IfPm3Iso15693, "Read a block"},
2204 {"rdmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple blocks"},
2205 {"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO-15693 reader"},
2206 {"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO-15693 tag"},
2207 {"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire samples as reader (enables carrier, sends inquiry)"},
2208 {"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO-15693 tag"},
2209 {"slixdisable", CmdHF15SlixDisable, IfPm3Iso15693, "Disable privacy mode on SLIX ISO-15693 tag"},
2210 {"wrbl", CmdHF15Write, IfPm3Iso15693, "Write a block"},
2211 {"-----------", CmdHF15Help, IfPm3Iso15693, "----------------------- " _CYAN_("afi") " -----------------------"},
2212 {"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO-15693 tag"},
2213 {"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO-15693 tag"},
2214 {"writedsfid", CmdHF15WriteDsfid, IfPm3Iso15693, "Writes the DSFID on an ISO-15693 tag"},
2215 {"-----------", CmdHF15Help, IfPm3Iso15693, "----------------------- " _CYAN_("magic") " -----------------------"},
2216 {"csetuid", CmdHF15CSetUID, IfPm3Iso15693, "Set UID for magic card"},
2217 {NULL, NULL, NULL, NULL}
2220 static int CmdHF15Help(const char *Cmd) {
2221 (void)Cmd; // Cmd is not used so far
2222 CmdsHelp(CommandTable);
2223 return PM3_SUCCESS;
2226 int CmdHF15(const char *Cmd) {
2227 clearCommandBuffer();
2228 return CmdsParse(CommandTable, Cmd);