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 MIFARE ULTRALIGHT (C) commands
17 //-----------------------------------------------------------------------------
20 #include "cmdparser.h"
21 #include "commonutil.h"
22 #include "crypto/libpcrypto.h"
28 #include "protocols.h"
29 #include "generator.h"
31 #include "cliparser.h"
33 #include "amiibo.h" // amiiboo fcts
35 #include "fileutils.h" // saveFile
36 #include "cmdtrace.h" // trace list
37 #include "preferences.h" // setDeviceDebugLevel
38 #include "crypto/originality.h"
40 #define MAX_UL_BLOCKS 0x0F
41 #define MAX_ULC_BLOCKS 0x2F
42 #define MAX_ULEV1a_BLOCKS 0x13
43 #define MAX_ULEV1b_BLOCKS 0x28
44 #define MAX_NTAG_203 0x29
45 #define MAX_NTAG_210 0x13
46 #define MAX_NTAG_212 0x28
47 #define MAX_NTAG_213 0x2C
48 #define MAX_NTAG_215 0x86
49 #define MAX_NTAG_216 0xE6
50 #define MAX_NTAG_I2C_1K 0xE9
51 #define MAX_NTAG_I2C_2K 0xE9
52 #define MAX_MY_D_NFC 0xFF
53 #define MAX_MY_D_MOVE 0x25
54 #define MAX_MY_D_MOVE_LEAN 0x0F
55 #define MAX_UL_NANO_40 0x0A
56 #define MAX_UL_AES 0x37
57 #define MAX_ST25TN512 0x3F
58 #define MAX_ST25TN01K 0x3F
60 static int CmdHelp(const char *Cmd
);
62 static uint8_t default_aes_keys
[][16] = {
63 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // all zeroes
64 { 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key
65 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, // 0x00-0x0F
66 { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }, // NFC-key
67 { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // all ones
68 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // all FF
69 { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }, // 11 22 33
70 { 0x47, 0x45, 0x4D, 0x58, 0x50, 0x52, 0x45, 0x53, 0x53, 0x4F, 0x53, 0x41, 0x4D, 0x50, 0x4C, 0x45 }, // gemalto
71 { 0x56, 0x4c, 0x67, 0x56, 0x99, 0x69, 0x64, 0x9f, 0x17, 0xC6, 0xC6, 0x16, 0x01, 0x10, 0x4D, 0xCA } // Virtual Dorma Kaba
74 static uint8_t default_3des_keys
[][16] = {
75 { 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key
76 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // all zeroes
77 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, // 0x00-0x0F
78 { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }, // NFC-key
79 { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // all ones
80 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // all FF
81 { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }, // 11 22 33
82 { 0x47, 0x45, 0x4D, 0x58, 0x50, 0x52, 0x45, 0x53, 0x53, 0x4F, 0x53, 0x41, 0x4D, 0x50, 0x4C, 0x45 } // gemalto
85 static uint8_t default_pwd_pack
[][4] = {
86 {0xFF, 0xFF, 0xFF, 0xFF}, // PACK 0x00,0x00 -- factory default
87 {0x4E, 0x45, 0x78, 0x54}, // NExT
88 {0xB6, 0xAA, 0x55, 0x8D}, // copykey
91 static uint64_t UL_TYPES_ARRAY
[] = {
92 MFU_TT_UNKNOWN
, MFU_TT_UL
,
93 MFU_TT_UL_C
, MFU_TT_UL_EV1_48
,
94 MFU_TT_UL_EV1_128
, MFU_TT_NTAG
,
95 MFU_TT_NTAG_203
, MFU_TT_NTAG_210
,
96 MFU_TT_NTAG_212
, MFU_TT_NTAG_213
,
97 MFU_TT_NTAG_215
, MFU_TT_NTAG_216
,
98 MFU_TT_MY_D
, MFU_TT_MY_D_NFC
,
99 MFU_TT_MY_D_MOVE
, MFU_TT_MY_D_MOVE_NFC
,
100 MFU_TT_MY_D_MOVE_LEAN
, MFU_TT_NTAG_I2C_1K
,
101 MFU_TT_NTAG_I2C_2K
, MFU_TT_NTAG_I2C_1K_PLUS
,
102 MFU_TT_NTAG_I2C_2K_PLUS
, MFU_TT_FUDAN_UL
,
103 MFU_TT_NTAG_213_F
, MFU_TT_NTAG_216_F
,
104 MFU_TT_UL_EV1
, MFU_TT_UL_NANO_40
,
105 MFU_TT_NTAG_213_TT
, MFU_TT_NTAG_213_C
,
106 MFU_TT_MAGIC_1A
, MFU_TT_MAGIC_1B
,
107 MFU_TT_MAGIC_NTAG
, MFU_TT_NTAG_210u
,
108 MFU_TT_UL_MAGIC
, MFU_TT_UL_C_MAGIC
,
110 MFU_TT_ST25TN512
, MFU_TT_ST25TN01K
,
114 static uint8_t UL_MEMORY_ARRAY
[ARRAYLEN(UL_TYPES_ARRAY
)] = {
115 // UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128,
116 MAX_UL_BLOCKS
, MAX_UL_BLOCKS
, MAX_ULC_BLOCKS
, MAX_ULEV1a_BLOCKS
, MAX_ULEV1b_BLOCKS
,
117 // NTAG, NTAG_203, NTAG_210, NTAG_212,
118 MAX_NTAG_203
, MAX_NTAG_203
, MAX_NTAG_210
, MAX_NTAG_212
,
119 // NTAG_213, NTAG_215, NTAG_216,
120 MAX_NTAG_213
, MAX_NTAG_215
, MAX_NTAG_216
,
121 // MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN,
122 MAX_UL_BLOCKS
, MAX_MY_D_NFC
, MAX_MY_D_MOVE
, MAX_MY_D_MOVE
, MAX_MY_D_MOVE_LEAN
,
123 // NTAG_I2C_1K, NTAG_I2C_2K, NTAG_I2C_1K_PLUS, NTAG_I2C_2K_PLUS,
124 MAX_NTAG_I2C_1K
, MAX_NTAG_I2C_2K
, MAX_NTAG_I2C_1K
, MAX_NTAG_I2C_2K
,
125 // FUDAN_UL, NTAG_213_F, NTAG_216_F, UL_EV1, UL_NANO_40,
126 MAX_UL_BLOCKS
, MAX_NTAG_213
, MAX_NTAG_216
, MAX_ULEV1a_BLOCKS
, MAX_UL_NANO_40
,
127 // NTAG_213_TT, NTAG_213_C,
128 MAX_NTAG_213
, MAX_NTAG_213
,
129 // MAGIC_1A, MAGIC_1B, MAGIC_NTAG,
130 MAX_UL_BLOCKS
, MAX_UL_BLOCKS
, MAX_NTAG_216
,
131 // NTAG_210u, UL_MAGIC, UL_C_MAGIC
132 MAX_NTAG_210
, MAX_UL_BLOCKS
, MAX_ULC_BLOCKS
, MAX_UL_AES
,
133 // ST25TN512, ST25TN01K,
134 MAX_ST25TN512
, MAX_ST25TN01K
,
137 static const ul_family_t ul_family
[] = {
138 {"UL-C", "UL-C", "\x00\x00\x00\x00\x00\x00\x00\x00"},
139 {"UL", "MF0UL1001DUx", "\x00\x04\x03\x01\x00\x00\x0B\x03"},
140 {"UL EV1 48", "MF0UL1101DUx", "\x00\x04\x03\x01\x01\x00\x0B\x03"},
141 {"UL EV1 48", "MF0ULH1101DUx", "\x00\x04\x03\x02\x01\x00\x0B\x03"},
142 {"UL EV1 48", "MF0UL1141DUF", "\x00\x04\x03\x03\x01\x00\x0B\x03"},
143 {"UL EV1 128", "MF0UL2101Dxy", "\x00\x04\x03\x01\x01\x00\x0E\x03"},
144 {"UL EV1 128", "MF0UL2101DUx", "\x00\x04\x03\x02\x01\x00\x0E\x03"},
145 {"UL Ev1 n/a ", "MF0UL3101DUx", "\x00\x04\x03\x01\x01\x00\x11\x03"},
146 {"UL Ev1 n/a", "MF0ULH3101DUx", "\x00\x04\x03\x02\x01\x00\x11\x03"},
147 {"UL Ev1 n/a", "MF0UL5101DUx", "\x00\x04\x03\x01\x01\x00\x13\x03"},
148 {"NTAG 210", "NT2L1011F0DUx", "\x00\x04\x04\x01\x01\x00\x0B\x03"},
149 {"NTAG 210", "NT2H1011G0DUD", "\x00\x04\x04\x02\x01\x00\x0B\x03"},
150 {"NTAG 212", "NT2L1211F0DUx", "\x00\x04\x04\x01\x01\x00\x0E\x03"},
151 {"NTAG 213", "NT2H1311G0DUx", "\x00\x04\x04\x02\x01\x00\x0F\x03"},
152 {"NTAG", "NT2H1411G0DUx", "\x00\x04\x04\x02\x01\x01\x11\x03"},
153 {"NTAG 215", "NT2H1511G0DUx", "\x00\x04\x04\x02\x01\x00\x11\x03"},
154 {"NTAG 215", "NT2H1511F0Dxy", "\x00\x04\x04\x04\x01\x00\x11\x03"},
155 {"NTAG 216", "NT2H1611G0DUx", "\x00\x04\x04\x02\x01\x00\x13\x03"},
156 {"NTAG 213F", "NT2H1311F0Dxy", "\x00\x04\x04\x04\x01\x00\x0F\x03"},
157 {"NTAG 216F", "NT2H1611F0Dxy", "\x00\x04\x04\x04\x01\x00\x13\x03"},
158 {"NTAG 213C", "NT2H1311C1DTL", "\x00\x04\x04\x02\x01\x01\x0F\x03"},
159 {"NTAG 213TT", "NT2H1311TTDUx", "\x00\x04\x04\x02\x03\x00\x0F\x03"},
160 {"NTAG I2C 1k", "NT3H1101W0FHK", "\x00\x04\x04\x05\x02\x00\x13\x03"},
161 {"NTAG I2C 1k", "NT3H1101W0FHK_Variant", "\x00\x04\x04\x05\x02\x01\x13\x03"},
162 {"NTAG I2C 2k", "NT3H1201W0FHK", "\x00\x04\x04\x05\x02\x00\x15\x03"},
163 {"NTAG I2C 2k", "NT3H1201", "\x00\x04\x04\x05\x02\x01\x15\x03"},
164 {"NTAG I2C 1k Plus", "NT3H2111", "\x00\x04\x04\x05\x02\x02\x13\x03"},
165 {"NTAG I2C 2k Plus", "NT3H2211", "\x00\x04\x04\x05\x02\x02\x15\x03"},
166 {"NTAG unk", "nhs", "\x00\x04\x04\x06\x00\x00\x13\x03"},
167 {"UL NANO 40", "MF0UN0001DUx 17pF", "\x00\x04\x03\x01\x02\x00\x0B\x03"},
168 {"UL NANO", "MF0UN1001DUx 17pF", "\x00\x04\x03\x01\x03\x00\x0B\x03"},
169 {"UL NANO 40", "MF0UNH0001DUx 50pF", "\x00\x04\x03\x02\x02\x00\x0B\x03"},
170 {"UL NANO", "MF0UNH1001DUx 50pF", "\x00\x04\x03\x02\x03\x00\x0B\x03"},
171 {"NTAG 210u", "NT2L1001G0DUx", "\x00\x04\x04\x01\x02\x00\x0B\x03"},
172 {"NTAG 210u", "NT2H1001G0DUx", "\x00\x04\x04\x02\x02\x00\x0B\x03"},
173 {"UL EV1 128", "Mikron JSC Russia EV1", "\x00\x34\x21\x01\x01\x00\x0E\x03"},
174 {"NTAG 213", "Shanghai Feiju NTAG", "\x00\x53\x04\x02\x01\x00\x0F\x03"},
175 {"NTAG 215", "Shanghai Feiju NTAG", "\x00\x05\x34\x02\x01\x00\x11\x03"},
176 {"UL AES", "MF0AES2001DUD", "\x00\x04\x03\x01\x04\x00\x0F\x03"},
179 static bool compare_ul_family(const uint8_t *d
, uint8_t n
) {
188 for (int i
= 0; i
< ARRAYLEN(ul_family
); ++i
) {
189 if (memcmp(d
, ul_family
[i
].version
, n
) == 0) {
196 //------------------------------------
197 // get version nxp product type
198 static const char *getProductTypeStr(uint8_t id
) {
200 memset(buf
, 0, sizeof(buf
));
208 snprintf(buf
, sizeof(buf
), "%02X, unknown", id
);
213 static int ul_print_nxp_silicon_info(const uint8_t *card_uid
) {
215 if (card_uid
[0] != 0x04) {
220 memcpy(&uid
, card_uid
, 7);
222 uint16_t waferCoordX
= ((uid
[6] & 3) << 8) | uid
[1];
223 uint16_t waferCoordY
= ((uid
[6] & 12) << 6) | uid
[2];
224 uint32_t waferCounter
= (
226 ((uid
[6] & 0xF0) << 17) |
230 uint8_t testSite
= uid
[3] & 7;
232 PrintAndLogEx(NORMAL
, "");
233 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Silicon Information"));
234 PrintAndLogEx(INFO
, " Wafer Counter: %" PRId32
" ( 0x%02" PRIX32
" )", waferCounter
, waferCounter
);
235 PrintAndLogEx(INFO
, " Wafer Coordinates: x %" PRId16
", y %" PRId16
" (0x%02" PRIX16
", 0x%02" PRIX16
")"
241 PrintAndLogEx(INFO
, " Test Site: %u", testSite
);
245 static int get_ulc_3des_key_magic(uint64_t magic_type
, uint8_t *key
) {
247 mf_readblock_ex_t payload
= {
248 .read_cmd
= ISO14443A_CMD_READBLOCK
,
252 if ((magic_type
& MFU_TT_MAGIC_1A
) == MFU_TT_MAGIC_1A
) {
253 payload
.wakeup
= MF_WAKE_GEN1A
;
254 payload
.auth_cmd
= 0;
255 } else if ((magic_type
& MFU_TT_MAGIC_1B
) == MFU_TT_MAGIC_1B
) {
256 payload
.wakeup
= MF_WAKE_GEN1B
;
257 payload
.auth_cmd
= 0;
258 } else if ((magic_type
& MFU_TT_MAGIC_4
) == MFU_TT_MAGIC_4
) {
259 payload
.wakeup
= MF_WAKE_GDM_ALT
;
260 payload
.auth_cmd
= 0;
261 } else if ((magic_type
& MFU_TT_MAGIC_NTAG21X
) == MFU_TT_MAGIC_NTAG21X
) {
262 payload
.wakeup
= MF_WAKE_WUPA
;
263 payload
.auth_cmd
= 0;
265 payload
.wakeup
= MF_WAKE_WUPA
;
266 payload
.auth_cmd
= MIFARE_MAGIC_GDM_AUTH_KEY
;
269 clearCommandBuffer();
270 SendCommandNG(CMD_HF_MIFARE_READBL_EX
, (uint8_t *)&payload
, sizeof(payload
));
271 PacketResponseNG resp
;
272 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL_EX
, &resp
, 1500) == false) {
273 PrintAndLogEx(WARNING
, "command execution time out");
277 if (resp
.status
== PM3_SUCCESS
&& resp
.length
== MFBLOCK_SIZE
) {
278 uint8_t *d
= resp
.data
.asBytes
;
280 reverse_array(d
+ 8, 8);
281 memcpy(key
, d
, MFBLOCK_SIZE
);
288 The 7 MSBits (=n) code the storage size itself based on 2^n,
289 the LSBit is set to '0' if the size is exactly 2^n
290 and set to '1' if the storage size is between 2^n and 2^(n+1).
292 static const char *getUlev1CardSizeStr(uint8_t fsize
) {
295 memset(buf
, 0, sizeof(buf
));
297 uint16_t usize
= 1 << ((fsize
>> 1) + 1);
298 uint16_t lsize
= 1 << (fsize
>> 1);
302 snprintf(buf
, sizeof(buf
), "%02X, (%u <-> %u bytes)", fsize
, usize
, lsize
);
304 snprintf(buf
, sizeof(buf
), "%02X, (%u bytes)", fsize
, lsize
);
308 int ul_read_uid(uint8_t *uid
) {
310 PrintAndLogEx(WARNING
, "NUll parameter UID");
314 clearCommandBuffer();
315 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_RATS
, 0, 0, NULL
, 0);
316 PacketResponseNG resp
;
317 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
318 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
321 iso14a_card_select_t card
;
322 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
324 uint64_t select_status
= resp
.oldarg
[0];
328 // 3: proprietary Anticollision
329 if (select_status
== 0) {
330 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
333 memcpy(uid
, card
.uid
, 7);
335 if (card
.uidlen
!= 7) {
336 PrintAndLogEx(WARNING
, "Wrong sized UID, expected 7 bytes, got " _RED_("%d"), card
.uidlen
);
342 static void ul_switch_on_field(void) {
343 clearCommandBuffer();
344 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_DISCONNECT
| ISO14A_NO_RATS
, 0, 0, NULL
, 0);
347 static int ul_send_cmd_raw(const uint8_t *cmd
, uint8_t cmdlen
, uint8_t *response
, uint16_t responseLength
) {
348 clearCommandBuffer();
349 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_RAW
| ISO14A_NO_DISCONNECT
| ISO14A_APPEND_CRC
| ISO14A_NO_RATS
, cmdlen
, 0, cmd
, cmdlen
);
350 PacketResponseNG resp
;
351 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
355 if (!resp
.oldarg
[0] && responseLength
) {
356 return PM3_EWRONGANSWER
;
359 uint16_t resplen
= (resp
.oldarg
[0] < responseLength
) ? resp
.oldarg
[0] : responseLength
;
360 memcpy(response
, resp
.data
.asBytes
, resplen
);
364 static bool ul_select(iso14a_card_select_t
*card
) {
366 ul_switch_on_field();
368 PacketResponseNG resp
;
369 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000) == false) {
370 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
375 uint16_t len
= (resp
.oldarg
[1] & 0xFFFF);
377 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
383 memcpy(card
, resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
389 static bool ul_select_rats(iso14a_card_select_t
*card
) {
391 ul_switch_on_field();
393 PacketResponseNG resp
;
394 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
395 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
400 uint16_t len
= (resp
.oldarg
[1] & 0xFFFF);
402 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
408 memcpy(card
, resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
411 if (resp
.oldarg
[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
413 uint8_t rats
[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
414 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_RAW
| ISO14A_APPEND_CRC
| ISO14A_NO_DISCONNECT
, sizeof(rats
), 0, rats
, sizeof(rats
));
415 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
416 PrintAndLogEx(WARNING
, "command execution time out");
422 card
->ats_len
= resp
.oldarg
[0];
423 memcpy(card
->ats
, resp
.data
.asBytes
, card
->ats_len
);
430 // This read command will at least return 16bytes.
431 static int ul_read(uint8_t page
, uint8_t *response
, uint16_t responseLength
) {
433 uint8_t cmd
[] = {ISO14443A_CMD_READBLOCK
, page
};
434 return ul_send_cmd_raw(cmd
, sizeof(cmd
), response
, responseLength
);
437 static int ul_comp_write(uint8_t page
, const uint8_t *data
, uint8_t datalen
) {
444 memset(cmd
, 0x00, sizeof(cmd
));
445 datalen
= (datalen
> 16) ? 16 : datalen
;
447 cmd
[0] = ISO14443A_CMD_WRITEBLOCK
;
449 memcpy(cmd
+ 2, data
, datalen
);
451 uint8_t response
[1] = {0xFF};
452 ul_send_cmd_raw(cmd
, 2 + datalen
, response
, sizeof(response
));
454 if (response
[0] == 0x0a) {
458 return PM3_EWRONGANSWER
;
461 static int ulc_requestAuthentication(uint8_t *nonce
, uint16_t nonceLength
) {
463 uint8_t cmd
[] = {MIFARE_ULC_AUTH_1
, 0x00};
464 return ul_send_cmd_raw(cmd
, sizeof(cmd
), nonce
, nonceLength
);
467 static int ulev1_requestAuthentication(const uint8_t *pwd
, uint8_t *pack
, uint16_t packLength
) {
469 uint8_t cmd
[] = {MIFARE_ULEV1_AUTH
, pwd
[0], pwd
[1], pwd
[2], pwd
[3]};
470 int len
= ul_send_cmd_raw(cmd
, sizeof(cmd
), pack
, packLength
);
471 // NACK tables different tags, but between 0-9 is a NEGATIVE response.
473 if (len
== 1 && pack
[0] <= 0x09) {
474 return PM3_EWRONGANSWER
;
480 Default AES key is 00-00h. Both the data and UID one.
481 Data key is 00, UID is 01. Authenticity is 02h
482 Auth is 1A[Key ID][CRC] - AF[RndB] - AF[RndA][RndB'] - 00[RndA']
484 static int ulaes_requestAuthentication(const uint8_t *key
, uint8_t keyno
, bool switch_off_field
) {
491 payload
.turn_off_field
= switch_off_field
;
492 payload
.keyno
= keyno
;
493 memcpy(payload
.key
, key
, sizeof(payload
.key
));
495 clearCommandBuffer();
496 SendCommandNG(CMD_HF_MIFAREULAES_AUTH
, (uint8_t *)&payload
, sizeof(payload
));
497 PacketResponseNG resp
;
498 if (WaitForResponseTimeout(CMD_HF_MIFAREULAES_AUTH
, &resp
, 1500) == false) {
501 if (resp
.status
!= PM3_SUCCESS
) {
507 static int ulc_authentication(const uint8_t *key
, bool switch_off_field
) {
509 clearCommandBuffer();
510 SendCommandMIX(CMD_HF_MIFAREUC_AUTH
, switch_off_field
, 0, 0, key
, 16);
511 PacketResponseNG resp
;
512 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
515 if (resp
.oldarg
[0] == 1) {
521 static int trace_mfuc_try_key(uint8_t *key
, int state
, uint8_t (*authdata
)[16]) {
523 uint8_t RndB
[8] = {0};
524 uint8_t RndARndB
[16] = {0};
525 uint8_t RndA
[8] = {0};
526 mbedtls_des3_context ctx_des3
;
529 mbedtls_des3_set2key_dec(&ctx_des3
, key
);
530 mbedtls_des3_crypt_cbc(&ctx_des3
, MBEDTLS_DES_DECRYPT
,
531 8, iv
, authdata
[0], RndB
);
532 mbedtls_des3_crypt_cbc(&ctx_des3
, MBEDTLS_DES_DECRYPT
,
533 16, iv
, authdata
[1], RndARndB
);
534 if ((memcmp(&RndB
[1], &RndARndB
[8], 7) == 0) &&
535 (RndB
[0] == RndARndB
[15])) {
540 if (key
== NULL
) {// if no key was found
543 memcpy(iv
, authdata
[0], 8);
544 mbedtls_des3_set2key_dec(&ctx_des3
, key
);
545 mbedtls_des3_crypt_cbc(&ctx_des3
, MBEDTLS_DES_DECRYPT
,
546 16, iv
, authdata
[1], RndARndB
);
547 mbedtls_des3_crypt_cbc(&ctx_des3
, MBEDTLS_DES_DECRYPT
,
548 8, iv
, authdata
[2], RndA
);
549 if ((memcmp(&RndARndB
[1], RndA
, 7) == 0) &&
550 (RndARndB
[0] == RndA
[7])) {
560 int trace_mfuc_try_default_3des_keys(uint8_t **correct_key
, int state
, uint8_t (*authdata
)[16]) {
563 for (uint8_t i
= 0; i
< ARRAYLEN(default_3des_keys
); ++i
) {
564 uint8_t *key
= default_3des_keys
[i
];
565 if (trace_mfuc_try_key(key
, state
, authdata
) == PM3_SUCCESS
) {
572 return trace_mfuc_try_key(*correct_key
, state
, authdata
);
580 // param override, means we override hw debug levels.
581 static int try_default_3des_keys(bool override
, uint8_t **correct_key
) {
583 uint8_t dbg_curr
= DBG_NONE
;
585 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
589 if (setDeviceDebugLevel(DBG_NONE
, false) != PM3_SUCCESS
) {
596 PrintAndLogEx(INFO
, "");
597 PrintAndLogEx(SUCCESS
, "--- " _CYAN_("Known UL-C 3DES keys"));
599 for (uint8_t i
= 0; i
< ARRAYLEN(default_3des_keys
); ++i
) {
600 uint8_t *key
= default_3des_keys
[i
];
601 if (ulc_authentication(key
, true) == PM3_SUCCESS
) {
609 setDeviceDebugLevel(dbg_curr
, false);
614 // param override, means we override hw debug levels.
615 static int try_default_aes_keys(bool override
) {
617 uint8_t dbg_curr
= DBG_NONE
;
619 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
623 if (setDeviceDebugLevel(DBG_NONE
, false) != PM3_SUCCESS
) {
630 PrintAndLogEx(NORMAL
, "");
631 PrintAndLogEx(SUCCESS
, "--- " _CYAN_("Known UL-AES keys"));
633 for (uint8_t i
= 0; i
< ARRAYLEN(default_aes_keys
); ++i
) {
634 uint8_t *key
= default_aes_keys
[i
];
636 for (uint8_t keyno
= 0; keyno
< 3; keyno
++) {
638 if (ulaes_requestAuthentication(key
, keyno
, true) == PM3_SUCCESS
) {
640 char keystr
[20] = {0};
643 sprintf(keystr
, "Data key");
646 sprintf(keystr
, "UID key");
649 sprintf(keystr
, "Authenticity key");
654 PrintAndLogEx(SUCCESS
, "%02X " _YELLOW_("%s") " - %s ( "_GREEN_("ok") " )"
657 , sprint_hex_inrow(key
, 16)
666 setDeviceDebugLevel(dbg_curr
, false);
671 static int ul_auth_select(iso14a_card_select_t
*card
, uint64_t tagtype
, bool hasAuthKey
, uint8_t *authkey
, uint8_t *pack
, uint8_t packSize
) {
673 if (hasAuthKey
&& (tagtype
& MFU_TT_UL_C
)) {
674 //will select card automatically and close connection on error
675 if (ulc_authentication(authkey
, false) != PM3_SUCCESS
) {
676 PrintAndLogEx(WARNING
, "Authentication Failed UL-C");
681 if (ul_select(card
) == false) {
686 if (ulev1_requestAuthentication(authkey
, pack
, packSize
) == PM3_EWRONGANSWER
) {
688 PrintAndLogEx(WARNING
, "Authentication Failed UL-EV1/NTAG");
696 static int ntagtt_getTamperStatus(uint8_t *response
, uint16_t responseLength
) {
697 uint8_t cmd
[] = {NTAGTT_CMD_READ_TT
, 0x00};
698 return ul_send_cmd_raw(cmd
, sizeof(cmd
), response
, responseLength
);
701 static int ulev1_getVersion(uint8_t *response
, uint16_t responseLength
) {
702 uint8_t cmd
[] = {MIFARE_ULEV1_VERSION
};
703 return ul_send_cmd_raw(cmd
, sizeof(cmd
), response
, responseLength
);
706 static int ulev1_readCounter(uint8_t counter
, uint8_t *response
, uint16_t responseLength
) {
707 uint8_t cmd
[] = {MIFARE_ULEV1_READ_CNT
, counter
};
708 return ul_send_cmd_raw(cmd
, sizeof(cmd
), response
, responseLength
);
711 static int ulev1_readTearing(uint8_t counter
, uint8_t *response
, uint16_t responseLength
) {
712 uint8_t cmd
[] = {MIFARE_ULEV1_CHECKTEAR
, counter
};
713 return ul_send_cmd_raw(cmd
, sizeof(cmd
), response
, responseLength
);
716 static int ulev1_readSignature(uint8_t *response
, uint16_t responseLength
) {
717 uint8_t cmd
[] = {MIFARE_ULEV1_READSIG
, 0x00};
718 return ul_send_cmd_raw(cmd
, sizeof(cmd
), response
, responseLength
);
721 // Fudan check checks for which error is given for a command with incorrect crc
722 // NXP UL chip responds with 01, fudan 00.
723 // other possible checks:
725 // UL responds with 00, fudan doesn't respond
728 // UL doesn't respond, fudan responds with 00
730 // send 300000 + crc (read with extra byte(s))
731 // UL responds with read of page 0, fudan doesn't respond.
733 // make sure field is off before calling this function
734 static int ul_fudan_check(void) {
735 iso14a_card_select_t card
;
736 if (ul_select(&card
) == false) {
737 return MFU_TT_UL_ERROR
;
740 uint8_t cmd
[4] = {ISO14443A_CMD_READBLOCK
, 0x00, 0x02, 0xa7}; // wrong crc on purpose, should be 0xa8
741 clearCommandBuffer();
742 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_RAW
| ISO14A_NO_DISCONNECT
| ISO14A_NO_RATS
, 4, 0, cmd
, sizeof(cmd
));
743 PacketResponseNG resp
;
744 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
745 return MFU_TT_UL_ERROR
;
747 if (resp
.oldarg
[0] != 1) {
748 return MFU_TT_UL_ERROR
;
751 return (resp
.data
.asBytes
[0] == 0)
752 ? MFU_TT_FUDAN_UL
: MFU_TT_UL
; //if response == 0x00 then Fudan, else Genuine NXP
755 static int ul_print_default(uint8_t *data
, uint8_t *real_uid
) {
765 bool mful_uid_layout
= true;
767 if (memcmp(uid
, real_uid
, 7) != 0) {
768 mful_uid_layout
= false;
770 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(real_uid
, 7));
771 PrintAndLogEx(SUCCESS
, " UID[0]: %02X, %s", real_uid
[0], getTagInfo(real_uid
[0]));
772 if (real_uid
[0] == 0x05 && ((real_uid
[1] & 0xf0) >> 4) == 2) { // is infineon and 66RxxP
773 uint8_t chip
= (data
[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU
776 PrintAndLogEx(SUCCESS
, " IC type: SLE 66R04P 770 Bytes");
779 PrintAndLogEx(SUCCESS
, " IC type: SLE 66R16P 2560 Bytes");
782 PrintAndLogEx(SUCCESS
, " IC type: SLE 66R32P 5120 Bytes");
783 break; //512 pages /2 sectors
786 if (mful_uid_layout
) {
787 // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2
788 int crc0
= 0x88 ^ uid
[0] ^ uid
[1] ^ uid
[2];
790 PrintAndLogEx(SUCCESS
, " BCC0: %02X ( " _GREEN_("ok") " )", data
[3]);
792 PrintAndLogEx(NORMAL
, " BCC0: %02X, crc should be %02X", data
[3], crc0
);
794 int crc1
= uid
[3] ^ uid
[4] ^ uid
[5] ^ uid
[6];
796 PrintAndLogEx(SUCCESS
, " BCC1: %02X ( " _GREEN_("ok") " )", data
[8]);
798 PrintAndLogEx(NORMAL
, " BCC1: %02X, crc should be %02X", data
[8], crc1
);
799 if (uid
[0] == 0x04) {
800 PrintAndLogEx(SUCCESS
, " Internal: %02X ( %s )", data
[9], (data
[9] == 0x48) ? _GREEN_("default") : _RED_("not default"));
801 } else if (uid
[0] == 0x02) {
802 PrintAndLogEx(SUCCESS
, " Sysblock: %02X ( %s )", data
[9], (data
[9] == 0x2C) ? _GREEN_("default") : _RED_("not default"));
804 PrintAndLogEx(SUCCESS
, " Internal: %02X", data
[9]);
807 PrintAndLogEx(SUCCESS
, "Blocks 0-2: %s", sprint_hex(data
+ 0, 12));
810 PrintAndLogEx(SUCCESS
, " Lock: %s - %s",
811 sprint_hex(data
+ 10, 2),
812 sprint_bin(data
+ 10, 2)
815 PrintAndLogEx(SUCCESS
, " OTP: " _YELLOW_("%s") " - %s",
816 sprint_hex(data
+ 12, 4),
817 sprint_bin(data
+ 12, 4)
822 static int ndef_get_maxsize(const uint8_t *data
) {
829 else if (data
[2] == 0x12)
831 else if (data
[2] == 0x3E)
833 else if (data
[2] == 0x6D)
838 static int ndef_print_CC(uint8_t *data
) {
841 if (data
[0] != 0xE1 && data
[0] != 0xF1) {
845 //NFC Forum Type 1,2,3,4
849 // b7, b6 major version
850 // b5, b4 minor version
852 // 00 always, 01 rfu, 10 proprietary, 11 rfu
854 // 00 always, 01 rfo, 10 proprietary, 11 never
855 uint8_t cc_write
= data
[1] & 0x03;
856 uint8_t cc_read
= (data
[1] & 0x0C) >> 2;
857 uint8_t cc_minor
= (data
[1] & 0x30) >> 4;
858 uint8_t cc_major
= (data
[1] & 0xC0) >> 6;
863 wStr
= "Write access granted without any security";
869 wStr
= "Proprietary";
872 wStr
= "No write access";
881 rStr
= "Read access granted without any security";
888 rStr
= "Proprietary";
896 PrintAndLogEx(NORMAL
, "");
897 PrintAndLogEx(INFO
, "--- " _CYAN_("NDEF Message"));
898 PrintAndLogEx(SUCCESS
, "Capability Container: " _YELLOW_("%s"), sprint_hex_inrow(data
, 4));
899 PrintAndLogEx(SUCCESS
, " %02X: NDEF Magic Number", data
[0]);
901 // PrintAndLogEx(SUCCESS, " %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0F);
902 PrintAndLogEx(SUCCESS
, " %02X: version %d.%d supported by tag", data
[1], cc_major
, cc_minor
);
903 PrintAndLogEx(SUCCESS
, " : %s / %s", rStr
, wStr
);
905 PrintAndLogEx(SUCCESS
, " %02X: Physical Memory Size: %d bytes", data
[2], data
[2] * 8);
907 PrintAndLogEx(SUCCESS
, " %02X: NDEF Memory Size: %d bytes", data
[2], 48);
908 else if (data
[2] == 0x12)
909 PrintAndLogEx(SUCCESS
, " %02X: NDEF Memory Size: %d bytes", data
[2], 144);
910 else if (data
[2] == 0x3E)
911 PrintAndLogEx(SUCCESS
, " %02X: NDEF Memory Size: %d bytes", data
[2], 496);
912 else if (data
[2] == 0x6D)
913 PrintAndLogEx(SUCCESS
, " %02X: NDEF Memory Size: %d bytes", data
[2], 872);
915 uint8_t msb3
= (data
[3] & 0xE0) >> 5;
916 uint8_t sf
= (data
[3] & 0x10) >> 4;
917 uint8_t lb
= (data
[3] & 0x08) >> 3;
918 uint8_t mlrule
= (data
[3] & 0x06) >> 1;
919 uint8_t mbread
= (data
[3] & 0x01);
921 PrintAndLogEx(SUCCESS
, " %02X: Additional feature information", data
[3]);
923 uint8_t bits
[8 + 1] = {0};
924 num_to_bytebits(data
[3], 8, bits
);
925 const char *bs
= sprint_bytebits_bin(bits
, 8);
927 PrintAndLogEx(SUCCESS
, " %s", bs
);
929 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_NONE
, bs
, 8, 0, 3, "RFU"));
931 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_RED
, bs
, 8, 0, 3, "RFU"));
935 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_NONE
, bs
, 8, 3, 1, "Support special frame"));
937 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_NONE
, bs
, 8, 3, 1, "Don\'t support special frame"));
941 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_NONE
, bs
, 8, 4, 1, "Support lock block"));
943 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_NONE
, bs
, 8, 4, 1, "Don\'t support lock block"));
947 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_NONE
, bs
, 8, 5, 2, "RFU"));
949 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_RED
, bs
, 8, 5, 2, "RFU"));
953 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_NONE
, bs
, 8, 7, 1, "IC support multiple block reads"));
955 PrintAndLogEx(SUCCESS
, " %s", sprint_breakdown_bin(C_NONE
, bs
, 8, 7, 1, "IC don\'t support multiple block reads"));
960 int ul_print_type(uint64_t tagtype
, uint8_t spaces
) {
967 memset(typestr
, 0x00, sizeof(typestr
));
969 if (tagtype
& MFU_TT_UL
)
970 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1)"), spaces
, "");
971 else if (tagtype
& MFU_TT_UL_C
)
972 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC)"), spaces
, "");
973 else if (tagtype
& MFU_TT_UL_NANO_40
)
974 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("MIFARE Ultralight Nano 40bytes (MF0UNH00)"), spaces
, "");
975 else if (tagtype
& MFU_TT_UL_EV1_48
)
976 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 48bytes (MF0UL1101)"), spaces
, "");
977 else if (tagtype
& MFU_TT_UL_EV1_128
)
978 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 128bytes (MF0UL2101)"), spaces
, "");
979 else if (tagtype
& MFU_TT_UL_EV1
)
980 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 UNKNOWN"), spaces
, "");
981 else if (tagtype
& MFU_TT_UL_AES
)
982 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("MIFARE Ultralight AES"), spaces
, "");
983 else if (tagtype
& MFU_TT_NTAG
)
984 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG UNKNOWN"), spaces
, "");
985 else if (tagtype
& MFU_TT_NTAG_203
)
986 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 203 144bytes (NT2H0301F0DT)"), spaces
, "");
987 else if (tagtype
& MFU_TT_NTAG_210u
)
988 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 210u (micro) 48bytes (NT2L1001G0DU)"), spaces
, "");
989 else if (tagtype
& MFU_TT_NTAG_210
)
990 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 210 48bytes (NT2L1011G0DU)"), spaces
, "");
991 else if (tagtype
& MFU_TT_NTAG_212
)
992 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 212 128bytes (NT2L1211G0DU)"), spaces
, "");
993 else if (tagtype
& MFU_TT_NTAG_213
)
994 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spaces
, "");
995 else if (tagtype
& MFU_TT_NTAG_213_F
)
996 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spaces
, "");
997 else if (tagtype
& MFU_TT_NTAG_213_C
)
998 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 213C 144bytes (NT2H1311C1DTL)"), spaces
, "");
999 else if (tagtype
& MFU_TT_NTAG_213_TT
)
1000 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 213TT 144bytes (NT2H1311TTDU)"), spaces
, "");
1001 else if (tagtype
& MFU_TT_NTAG_215
)
1002 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 215 504bytes (NT2H1511G0DU)"), spaces
, "");
1003 else if (tagtype
& MFU_TT_NTAG_216
)
1004 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 216 888bytes (NT2H1611G0DU)"), spaces
, "");
1005 else if (tagtype
& MFU_TT_NTAG_216_F
)
1006 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG 216F 888bytes (NT2H1611F0DTL)"), spaces
, "");
1007 else if (tagtype
& MFU_TT_NTAG_I2C_1K
)
1008 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG I2C 888bytes (NT3H1101FHK)"), spaces
, "");
1009 else if (tagtype
& MFU_TT_NTAG_I2C_2K
)
1010 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG I2C 1904bytes (NT3H1201FHK)"), spaces
, "");
1011 else if (tagtype
& MFU_TT_NTAG_I2C_1K_PLUS
)
1012 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG I2C plus 888bytes (NT3H2111FHK)"), spaces
, "");
1013 else if (tagtype
& MFU_TT_NTAG_I2C_2K_PLUS
)
1014 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("NTAG I2C plus 1912bytes (NT3H2211FHK)"), spaces
, "");
1015 else if (tagtype
& MFU_TT_MY_D
)
1016 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 (SLE 66RxxS)"), spaces
, "");
1017 else if (tagtype
& MFU_TT_MY_D_NFC
)
1018 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 NFC (SLE 66RxxP)"), spaces
, "");
1019 else if (tagtype
& MFU_TT_MY_D_MOVE
)
1020 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move (SLE 66R01P)"), spaces
, "");
1021 else if (tagtype
& MFU_TT_MY_D_MOVE_NFC
)
1022 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move NFC (SLE 66R01P)"), spaces
, "");
1023 else if (tagtype
& MFU_TT_MY_D_MOVE_LEAN
)
1024 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move lean (SLE 66R01L)"), spaces
, "");
1025 else if (tagtype
& MFU_TT_FUDAN_UL
)
1026 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("FUDAN Ultralight Compatible (or other compatible)"), spaces
, "");
1027 else if (tagtype
& MFU_TT_ST25TN512
)
1028 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("ST ST25TN512 64bytes"), spaces
, "");
1029 else if (tagtype
& MFU_TT_ST25TN01K
)
1030 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("ST ST25TN01K 160bytes"), spaces
, "");
1032 snprintf(typestr
, sizeof(typestr
), "%*sTYPE: " _YELLOW_("Unknown %06" PRIx64
), spaces
, "", tagtype
);
1036 bool ismagic
= ((tagtype
& MFU_TT_MAGIC
) == MFU_TT_MAGIC
);
1038 tagtype
&= ~(MFU_TT_MAGIC
);
1041 snprintf(typestr
+ strlen(typestr
), 4, " ( ");
1044 snprintf(typestr
+ strlen(typestr
), sizeof(typestr
) - strlen(typestr
), "%s", ((tagtype
& MFU_TT_MAGIC_1A
) == MFU_TT_MAGIC_1A
) ? _GREEN_("Gen 1a") : "");
1045 snprintf(typestr
+ strlen(typestr
), sizeof(typestr
) - strlen(typestr
), "%s", ((tagtype
& MFU_TT_MAGIC_1B
) == MFU_TT_MAGIC_1B
) ? _GREEN_("Gen 1b") : "");
1046 snprintf(typestr
+ strlen(typestr
), sizeof(typestr
) - strlen(typestr
), "%s", ((tagtype
& MFU_TT_MAGIC_2
) == MFU_TT_MAGIC_2
) ? _GREEN_("Gen 2 / CUID") : "");
1047 snprintf(typestr
+ strlen(typestr
), sizeof(typestr
) - strlen(typestr
), "%s", ((tagtype
& MFU_TT_MAGIC_4
) == MFU_TT_MAGIC_4
) ? _GREEN_("USCUID-UL") : "");
1048 snprintf(typestr
+ strlen(typestr
), sizeof(typestr
) - strlen(typestr
), "%s", ((tagtype
& MFU_TT_MAGIC_NTAG
) == MFU_TT_MAGIC_NTAG
) ? _GREEN_("NTAG CUID") : "");
1049 snprintf(typestr
+ strlen(typestr
), sizeof(typestr
) - strlen(typestr
), "%s", ((tagtype
& MFU_TT_MAGIC_NTAG21X
) == MFU_TT_MAGIC_NTAG21X
) ? _GREEN_("NTAG21x") : "");
1053 snprintf(typestr
+ strlen(typestr
), 4, " )");
1056 PrintAndLogEx(SUCCESS
, "%s", typestr
);
1060 static int ulc_print_3deskey(uint8_t *data
) {
1061 PrintAndLogEx(INFO
, " deskey1 [44/0x2C]: %s [%s]", sprint_hex(data
, 4), sprint_ascii(data
, 4));
1062 PrintAndLogEx(INFO
, " deskey1 [45/0x2D]: %s [%s]", sprint_hex(data
+ 4, 4), sprint_ascii(data
+ 4, 4));
1063 PrintAndLogEx(INFO
, " deskey2 [46/0x2E]: %s [%s]", sprint_hex(data
+ 8, 4), sprint_ascii(data
+ 8, 4));
1064 PrintAndLogEx(INFO
, " deskey2 [47/0x2F]: %s [%s]", sprint_hex(data
+ 12, 4), sprint_ascii(data
+ 12, 4));
1065 PrintAndLogEx(INFO
, "3des key: " _GREEN_("%s"), sprint_hex_inrow(SwapEndian64(data
, 16, 8), 16));
1069 // Only takes 16 bytes of data. Now key data available here
1070 static int ulc_print_configuration(uint8_t *data
) {
1072 PrintAndLogEx(NORMAL
, "");
1073 PrintAndLogEx(INFO
, "--- " _CYAN_("UL-C Configuration") " --------------------------");
1074 PrintAndLogEx(INFO
, "Total memory....... " _YELLOW_("%u") " bytes", MAX_ULC_BLOCKS
* 4);
1075 PrintAndLogEx(INFO
, "Available memory... " _YELLOW_("%u") " bytes", (MAX_ULC_BLOCKS
- 4) * 4);
1076 PrintAndLogEx(INFO
, "40 / 0x28 | %s - %s Higher lockbits", sprint_hex(data
, 4), sprint_bin(data
, 2));
1077 PrintAndLogEx(INFO
, "41 / 0x29 | %s - %s Counter", sprint_hex(data
+ 4, 4), sprint_bin(data
+ 4, 2));
1079 bool validAuth
= (data
[8] >= 0x03 && data
[8] < 0x30);
1081 PrintAndLogEx(INFO
, "42 / 0x2A | %s Auth0 Page " _YELLOW_("%d") "/" _YELLOW_("0x%02X") " and above need authentication"
1082 , sprint_hex(data
+ 8, 4)
1088 PrintAndLogEx(INFO
, "42 / 0x2A | %s Auth0 default", sprint_hex(data
+ 8, 4));
1089 } else if (data
[8] == 0x30) {
1090 PrintAndLogEx(INFO
, "42 / 0x2A | %s Auth0 " _GREEN_("unlocked"), sprint_hex(data
+ 8, 4));
1092 PrintAndLogEx(INFO
, "42 / 0x2A | %s Auth0 " _RED_("byte is out-of-range"), sprint_hex(data
+ 8, 4));
1096 PrintAndLogEx(INFO
, "43 / 0x2B | %s Auth1 %s",
1097 sprint_hex(data
+ 12, 4),
1098 (data
[12] & 1) ? "write access restricted" : _RED_("R/W access restricted")
1104 static int ulaes_print_configuration(uint8_t *data
, uint8_t start_page
) {
1106 PrintAndLogEx(NORMAL
, "");
1107 PrintAndLogEx(INFO
, "--- " _CYAN_("UL-AES Configuration") " --------------------------");
1109 bool rid_act
= (data
[0] & 1);
1110 bool sec_msg_act
= (data
[0] & 2);
1111 bool prot
= (data
[4] & 0x80);
1112 bool cfglck
= (data
[4] & 0x40);
1113 bool cnt_inc_en
= (data
[4] & 8);
1114 bool cnt_rd_en
= (data
[4] & 4);
1115 uint16_t authlim
= (data
[6]) | ((data
[7] & 0x3) << 8);
1117 PrintAndLogEx(INFO
, " cfg0 [%u/0x%02X]: " _YELLOW_("%s"), start_page
, start_page
, sprint_hex_inrow(data
, 4));
1119 PrintAndLogEx(INFO
, " - Random ID is %s", (rid_act
) ? "enabled" : "disabled");
1120 PrintAndLogEx(INFO
, " - Secure messaging is %s", (sec_msg_act
) ? "enabled" : "disabled");
1121 if (data
[3] < 0x3c) {
1122 PrintAndLogEx(INFO
, " - page %d and above need authentication", data
[3]);
1124 PrintAndLogEx(INFO
, " - pages don't need authentication");
1126 PrintAndLogEx(INFO
, " cfg1 [%u/0x%02X]: " _YELLOW_("%s"), start_page
+ 1, start_page
+ 1, sprint_hex_inrow(data
+ 4, 4));
1129 PrintAndLogEx(INFO
, " - " _GREEN_("Unlimited authentication attempts"));
1131 PrintAndLogEx(INFO
, " - Max number of authentication attempts is " _YELLOW_("%d"), authlim
);
1133 PrintAndLogEx(INFO
, " - %s access requires authentication", prot
? "Read and write" : "Write");
1134 PrintAndLogEx(INFO
, " - User configuration is %s", cfglck
? _RED_("locked") : "unlocked");
1135 PrintAndLogEx(INFO
, " - Counter 2 increment access %s authentication", cnt_inc_en
? "does not require" : "requires");
1136 PrintAndLogEx(INFO
, " - Counter 2 read access %s authentication", cnt_rd_en
? "does not require" : "requires");
1140 static int ulev1_print_configuration(uint64_t tagtype
, uint8_t *data
, uint8_t startPage
) {
1142 PrintAndLogEx(NORMAL
, "");
1143 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Configuration"));
1145 bool strg_mod_en
= (data
[0] & 2);
1147 uint8_t authlim
= (data
[4] & 0x07);
1148 bool nfc_cnf_prot_pwd
= ((data
[4] & 0x08) == 0x08);
1149 bool nfc_cnf_en
= ((data
[4] & 0x10) == 0x10);
1150 bool cfglck
= ((data
[4] & 0x40) == 0x40);
1151 bool prot
= ((data
[4] & 0x80) == 0x80);
1153 uint8_t vctid
= data
[5];
1155 PrintAndLogEx(INFO
, " cfg0 [%u/0x%02X]: " _YELLOW_("%s"), startPage
, startPage
, sprint_hex_inrow(data
, 4));
1157 //NTAG213TT has different ASCII mirroring options and config bytes interpretation from other ulev1 class tags
1158 if (tagtype
& MFU_TT_NTAG_213_TT
) {
1159 uint8_t mirror_conf
= ((data
[0] & 0xE0) >> 5);
1160 uint8_t mirror_byte
= ((data
[0] & 0x18) >> 3);
1161 uint8_t mirror_page
= data
[2];
1163 switch (mirror_conf
) {
1165 PrintAndLogEx(INFO
, " - no ASCII mirror");
1168 PrintAndLogEx(INFO
, " - UID ASCII mirror");
1171 PrintAndLogEx(INFO
, " - NFC counter ASCII mirror");
1174 PrintAndLogEx(INFO
, " - UID and NFC counter ASCII mirror");
1177 PrintAndLogEx(INFO
, " - tag tamper ASCII mirror");
1180 PrintAndLogEx(INFO
, " - UID and tag tamper ASCII mirror");
1183 PrintAndLogEx(INFO
, " - NFC counter and tag tamper ASCII mirror");
1186 PrintAndLogEx(INFO
, " - UID, NFC counter, and tag tamper ASCII mirror");
1193 uint8_t mirror_user_mem_start_byte
= (4 * (mirror_page
- 4)) + mirror_byte
;
1194 uint8_t bytes_required_for_mirror_data
= 0;
1196 switch (mirror_conf
) {
1198 bytes_required_for_mirror_data
= 14;
1201 bytes_required_for_mirror_data
= 6;
1204 bytes_required_for_mirror_data
= 8;
1207 bytes_required_for_mirror_data
= 21;
1210 bytes_required_for_mirror_data
= 23;
1213 bytes_required_for_mirror_data
= 15;
1216 bytes_required_for_mirror_data
= 30;
1221 PrintAndLogEx(INFO
, " mirror start page %02X | byte pos %02X - %s"
1222 , mirror_page
, mirror_byte
1223 , (mirror_page
>= 0x4 && ((mirror_user_mem_start_byte
+ bytes_required_for_mirror_data
) <= 144)) ? _GREEN_("ok") : _YELLOW_("Invalid value")
1227 } else if (tagtype
& (MFU_TT_NTAG_213_F
| MFU_TT_NTAG_216_F
)) {
1228 uint8_t mirror_conf
= ((data
[0] & 0xC0) >> 6);
1229 uint8_t mirror_byte
= (data
[0] & 0x30);
1230 bool sleep_en
= (data
[0] & 0x08);
1231 strg_mod_en
= (data
[0] & 0x04);
1232 uint8_t fdp_conf
= (data
[0] & 0x03);
1234 switch (mirror_conf
) {
1236 PrintAndLogEx(INFO
, " - no ASCII mirror");
1239 PrintAndLogEx(INFO
, " - UID ASCII mirror");
1242 PrintAndLogEx(INFO
, " - NFC counter ASCII mirror");
1245 PrintAndLogEx(INFO
, " - UID and NFC counter ASCII mirror");
1251 PrintAndLogEx(INFO
, " - SLEEP mode %s", (sleep_en
) ? "enabled" : "disabled");
1255 PrintAndLogEx(INFO
, " - no field detect");
1258 PrintAndLogEx(INFO
, " - enabled by first State-of-Frame (start of communication)");
1261 PrintAndLogEx(INFO
, " - enabled by selection of the tag");
1264 PrintAndLogEx(INFO
, " - enabled by field presence");
1269 // valid mirror start page and byte position within start page.
1270 if (tagtype
& MFU_TT_NTAG_213_F
) {
1271 switch (mirror_conf
) {
1273 { PrintAndLogEx(INFO
, " mirror start block %02X | byte pos %02X - %s", data
[2], mirror_byte
, (data
[2] >= 0x4 && data
[2] <= 0x24) ? "OK" : "Invalid value"); break;}
1275 { PrintAndLogEx(INFO
, " mirror start block %02X | byte pos %02X - %s", data
[2], mirror_byte
, (data
[2] >= 0x4 && data
[2] <= 0x26) ? "OK" : "Invalid value"); break;}
1277 { PrintAndLogEx(INFO
, " mirror start block %02X | byte pos %02X - %s", data
[2], mirror_byte
, (data
[2] >= 0x4 && data
[2] <= 0x22) ? "OK" : "Invalid value"); break;}
1281 } else if (tagtype
& MFU_TT_NTAG_216_F
) {
1282 switch (mirror_conf
) {
1284 { PrintAndLogEx(INFO
, " mirror start block %02X | byte pos %02X - %s", data
[2], mirror_byte
, (data
[2] >= 0x4 && data
[2] <= 0xDE) ? "OK" : "Invalid value"); break;}
1286 { PrintAndLogEx(INFO
, " mirror start block %02X | byte pos %02X - %s", data
[2], mirror_byte
, (data
[2] >= 0x4 && data
[2] <= 0xE0) ? "OK" : "Invalid value"); break;}
1288 { PrintAndLogEx(INFO
, " mirror start block %02X | byte pos %02X - %s", data
[2], mirror_byte
, (data
[2] >= 0x4 && data
[2] <= 0xDC) ? "OK" : "Invalid value"); break;}
1294 PrintAndLogEx(INFO
, " - strong modulation mode %s", (strg_mod_en
) ? "enabled" : "disabled");
1297 PrintAndLogEx(INFO
, " - page %d and above need authentication", data
[3]);
1299 PrintAndLogEx(INFO
, " - pages don't need authentication");
1301 uint8_t tt_enabled
= 0;
1302 uint8_t tt_message
[4] = {0x00};
1303 uint8_t tt_msg_resp_len
= 0;
1304 uint8_t tt_status_resp
[5] = {0x00};
1306 if (tagtype
& MFU_TT_NTAG_213_TT
) {
1307 tt_enabled
= (data
[1] & 0x02);
1308 tt_msg_resp_len
= ul_read(45, tt_message
, 4);
1310 PrintAndLogEx(INFO
, " - tamper detection feature is %s"
1311 , (tt_enabled
) ? _GREEN_("ENABLED") : "disabled"
1314 switch (data
[1] & 0x06) {
1316 PrintAndLogEx(INFO
, " - tamper message is unlocked and read/write enabled");
1319 PrintAndLogEx(INFO
, " - tamper message is reversibly read/write locked in memory while the tamper feature is enabled");
1323 PrintAndLogEx(INFO
, " - tamper message is permanently read/write locked in memory");
1330 PrintAndLogEx(INFO
, " cfg1 [%u/0x%02X]: " _YELLOW_("%s"), startPage
+ 1, startPage
+ 1, sprint_hex_inrow(data
+ 4, 4));
1332 PrintAndLogEx(INFO
, " - " _GREEN_("Unlimited password attempts"));
1334 PrintAndLogEx(INFO
, " - Max number of password attempts is " _YELLOW_("%d"), authlim
);
1336 PrintAndLogEx(INFO
, " - NFC counter %s", (nfc_cnf_en
) ? "enabled" : "disabled");
1337 PrintAndLogEx(INFO
, " - NFC counter %s", (nfc_cnf_prot_pwd
) ? "password protection enabled" : "not protected");
1339 PrintAndLogEx(INFO
, " - user configuration %s", cfglck
? "permanently locked" : "writeable");
1340 PrintAndLogEx(INFO
, " - %s access is protected with password", prot
? "read and write" : "write");
1341 PrintAndLogEx(INFO
, " - %02X, Virtual Card Type Identifier is %sdefault", vctid
, (vctid
== 0x05) ? "" : "not ");
1342 PrintAndLogEx(INFO
, " PWD [%u/0x%02X]: %s ( cannot be read )", startPage
+ 2, startPage
+ 2, sprint_hex_inrow(data
+ 8, 4));
1343 PrintAndLogEx(INFO
, " PACK [%u/0x%02X]: %s ( cannot be read )", startPage
+ 3, startPage
+ 3, sprint_hex_inrow(data
+ 12, 2));
1344 PrintAndLogEx(INFO
, " RFU [%u/0x%02X]: %s ( cannot be read )", startPage
+ 3, startPage
+ 3, sprint_hex_inrow(data
+ 14, 2));
1346 if (tagtype
& MFU_TT_NTAG_213_TT
) {
1347 if (data
[1] & 0x06) {
1348 PrintAndLogEx(INFO
, "TT_MSG [45/0x2D]: %s (cannot be read)", sprint_hex_inrow(tt_message
, tt_msg_resp_len
));
1349 PrintAndLogEx(INFO
, " - tamper message is masked in memory");
1351 PrintAndLogEx(INFO
, "TT_MSG [45/0x2D]: %s", sprint_hex_inrow(tt_message
, tt_msg_resp_len
));
1352 PrintAndLogEx(INFO
, " - tamper message is %s and is readable/writablbe in memory", sprint_hex(tt_message
, tt_msg_resp_len
));
1356 //The NTAG213TT only returns meaningful information for the fields below if the tamper feature is enabled
1357 if ((tagtype
& MFU_TT_NTAG_213_TT
) && tt_enabled
) {
1359 int tt_status_len
= ntagtt_getTamperStatus(tt_status_resp
, 5);
1360 if (tt_status_len
!= 5) {
1361 PrintAndLogEx(WARNING
, "Error sending the READ_TT_STATUS command to tag\n");
1365 PrintAndLogEx(NORMAL
, "");
1366 PrintAndLogEx(INFO
, "--- " _CYAN_("Tamper Status"));
1367 PrintAndLogEx(INFO
, " READ_TT_STATUS: %s", sprint_hex_inrow(tt_status_resp
, 5));
1369 PrintAndLogEx(INFO
, " Tamper status result from this power-up:");
1370 switch (tt_status_resp
[4]) {
1372 PrintAndLogEx(INFO
, " - Tamper loop was detcted as closed during this power-up");
1375 PrintAndLogEx(INFO
, " - Tamper loop was detected as open during this power-up");
1378 PrintAndLogEx(INFO
, " - Tamper loop measurement was not enabled or not valid during this power-up");
1384 PrintAndLogEx(INFO
, " Tamper detection permanent memory:");
1385 if ((tt_status_resp
[0] | tt_status_resp
[1] | tt_status_resp
[2] | tt_status_resp
[3]) == 0x00)
1387 PrintAndLogEx(INFO
, " - Tamper loop has never been detected as open during power-up");
1389 PrintAndLogEx(INFO
, " - Tamper loop was detected as open during power-up at least once");
1390 PrintAndLogEx(INFO
, " - Tamper message returned by READ_TT_STATUS command: %s", sprint_hex(tt_status_resp
, 4));
1396 static int ulev1_print_counters(void) {
1397 PrintAndLogEx(NORMAL
, "");
1398 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Counters"));
1399 uint8_t tear
[1] = {0};
1400 uint8_t counter
[3] = {0, 0, 0};
1402 for (uint8_t i
= 0; i
< 3; ++i
) {
1403 ulev1_readTearing(i
, tear
, sizeof(tear
));
1404 len
= ulev1_readCounter(i
, counter
, sizeof(counter
));
1406 PrintAndLogEx(INFO
, " [%0d]: %s", i
, sprint_hex(counter
, 3));
1407 PrintAndLogEx(SUCCESS
, " - %02X tearing ( %s )"
1409 , (tear
[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
1416 static int ulev1_print_signature(uint64_t tagtype
, uint8_t *uid
, uint8_t *signature
, size_t signature_len
) {
1418 if (signature_len
== 32) {
1419 index
= originality_check_verify(uid
, 7, signature
, signature_len
, PK_MFUL
);
1420 } else if (signature_len
== 48) {
1421 index
= originality_check_verify(uid
, 7, signature
, signature_len
, PK_MFULAES
);
1423 PrintAndLogEx(NORMAL
, "");
1424 return originality_check_print(signature
, signature_len
, index
);
1427 static int ulev1_print_version(uint8_t *data
) {
1428 PrintAndLogEx(NORMAL
, "");
1429 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Version"));
1430 PrintAndLogEx(INFO
, " Raw bytes: " _YELLOW_("%s"), sprint_hex_inrow(data
, 8));
1431 PrintAndLogEx(INFO
, " Vendor ID: %02X, %s", data
[1], getTagInfo(data
[1]));
1432 PrintAndLogEx(INFO
, " Product type: %s", getProductTypeStr(data
[2]));
1433 PrintAndLogEx(INFO
, " Product subtype: %02X, %s", data
[3], (data
[3] == 1) ? "17 pF" : "50pF");
1434 PrintAndLogEx(INFO
, " Major version: %02X", data
[4]);
1435 PrintAndLogEx(INFO
, " Minor version: %02X", data
[5]);
1436 PrintAndLogEx(INFO
, " Size: %s", getUlev1CardSizeStr(data
[6]));
1437 PrintAndLogEx(INFO
, " Protocol type: %02X%s", data
[7], (data
[7] == 0x3) ? ", ISO14443-3 Compliant" : "");
1441 static int ntag_print_counter(void) {
1442 // NTAG has one counter. At address 0x02. With no tearing.
1443 PrintAndLogEx(NORMAL
, "");
1444 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Counter"));
1445 uint8_t counter
[3] = {0, 0, 0};
1447 len
= ulev1_readCounter(0x02, counter
, sizeof(counter
));
1448 PrintAndLogEx(INFO
, " [02]: %s", sprint_hex(counter
, 3));
1453 static int ulc_magic_test(){
1454 // Magic Ultralight test
1455 // Magic UL-C, by observation,
1456 // 1) it seems to have a static nonce response to 0x1A command.
1457 // 2) the deskey bytes is not-zero:d out on as datasheet states.
1458 // 3) UID - changeable, not only, but pages 0-1-2-3.
1459 // 4) use the ul_magic_test ! magic tags answers specially!
1460 int returnValue = UL_ERROR;
1461 iso14a_card_select_t card;
1462 uint8_t nonce1[11] = {0x00};
1463 uint8_t nonce2[11] = {0x00};
1464 if ( !ul_select(&card) ){
1465 return MFU_TT_UL_ERROR;
1467 int status = ulc_requestAuthentication(nonce1, sizeof(nonce1));
1468 if ( status <= 0 ) {
1469 status = ulc_requestAuthentication(nonce2, sizeof(nonce2));
1470 returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? MFU_TT_UL_C_MAGIC : MFU_TT_UL_C;
1472 returnValue = MFU_TT_UL;
1478 static uint64_t ul_magic_test(void) {
1479 // Magic Ultralight tests
1480 // 1) take present UID, and try to write it back. OBSOLETE
1481 // 2) make a wrong length write to page0, and see if tag answers with ACK/NACK:
1485 iso14a_card_select_t card
;
1486 if (ul_select_rats(&card
) == false) {
1487 return MFU_TT_UL_ERROR
;
1491 // iceman: how to proper identify RU based UID cards
1493 (memcmp(card.uid, "\xAA\x55\x39", 3) == 0) ||
1494 (memcmp(card.uid, "\xAA\x55\xC3", 3) == 0)
1496 // Ul-5 MFU Ev1 FUID,
1497 return MFU_TT_UL_EV1_MAGIC;
1500 PrintAndLogEx(DEBUG
, "%u - %s", card
.ats_len
, sprint_hex_inrow(card
.ats
, card
.ats_len
));
1503 if (card
.ats_len
== 18) {
1505 // USCUID-UL configuration
1506 // https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#uscuid-ul-configuration-guide
1507 // identify: ATS len 18,
1508 // First 8 bytes can vary depending on setup. next 8 bytes is GET VERSION data and finally 2 byte crc
1510 // \x85\x00\x00\xA0\x0A\x00\x0A\xC3 \x00\x04\x03\x01\x01\x00\x0B\x03 \xZZ\xZZ
1512 // 7AFF - back door enabled
1514 // if we ignore first 8 bytes we can identify regardless how card is configured
1516 if (compare_ul_family(card
.ats
+ 8, 8)) {
1517 return MFU_TT_MAGIC_4
| MFU_TT_MAGIC
;
1521 // Direct write alternative cards
1522 if (card
.ats_len
== 14) {
1524 // UL Direct Write , UL-C Direct write, NTAG 213 Direct write
1525 if (memcmp(card
.ats
, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
1526 return MFU_TT_MAGIC_2
;
1531 int status
= ul_comp_write(0, NULL
, 0);
1533 if (status
== PM3_SUCCESS
) {
1534 PrintAndLogEx(INFO
, "comp write pass");
1535 return MFU_TT_MAGIC_2
| MFU_TT_MAGIC
;
1538 // check for GEN1A, GEN1B and NTAG21x
1539 PacketResponseNG resp
;
1540 clearCommandBuffer();
1541 uint8_t payload
[] = { 0 };
1542 SendCommandNG(CMD_HF_MIFARE_CIDENT
, payload
, sizeof(payload
));
1544 uint16_t is_generation
= MAGIC_FLAG_NONE
;
1545 if (WaitForResponseTimeout(CMD_HF_MIFARE_CIDENT
, &resp
, 1500)) {
1546 if ((resp
.status
== PM3_SUCCESS
) && resp
.length
== sizeof(uint16_t)) {
1547 is_generation
= resp
.data
.asDwords
[0] & 0xFFFF;
1551 if ((is_generation
& MAGIC_FLAG_GEN_1A
) == MAGIC_FLAG_GEN_1A
) {
1552 return MFU_TT_MAGIC_1A
| MFU_TT_MAGIC
;
1555 if ((is_generation
& MAGIC_FLAG_GEN_1B
) == MAGIC_FLAG_GEN_1B
) {
1556 return MFU_TT_MAGIC_1B
| MFU_TT_MAGIC
;
1559 if ((is_generation
& MAGIC_FLAG_NTAG21X
) == MAGIC_FLAG_NTAG21X
) {
1560 return MFU_TT_MAGIC_NTAG21X
| MFU_TT_MAGIC
;
1563 return MFU_TT_UNKNOWN
;
1566 static char *mfu_generate_filename(const char *prefix
, const char *suffix
) {
1567 iso14a_card_select_t card
;
1568 if (ul_select(&card
) == false) {
1569 PrintAndLogEx(WARNING
, "No tag found.");
1573 char *fptr
= calloc(sizeof(char) * (strlen(prefix
) + strlen(suffix
)) + sizeof(card
.uid
) * 2 + 1, sizeof(uint8_t));
1574 strcpy(fptr
, prefix
);
1575 FillFileNameByUID(fptr
, card
.uid
, suffix
, card
.uidlen
);
1579 // used with the Amiibo dumps loading...
1580 // Not related to 'hf mfu dump'
1581 static int mfu_dump_tag(uint16_t pages
, void **pdata
, uint16_t *len
) {
1584 iso14a_card_select_t card
;
1585 if (ul_select(&card
) == false) {
1586 return PM3_ECARDEXCHANGE
;
1589 int res
= PM3_SUCCESS
;
1590 uint16_t maxbytes
= (pages
* MFU_BLOCK_SIZE
);
1592 *pdata
= calloc(maxbytes
, sizeof(uint8_t));
1593 if (*pdata
== NULL
) {
1594 PrintAndLogEx(FAILED
, "error, cannot allocate memory");
1600 uint8_t keytype
= 2;
1602 uint8_t key
[4] = {0};
1603 num_to_bytes(ul_ev1_pwdgenB(card
.uid
), 4, key
);
1605 clearCommandBuffer();
1606 SendCommandMIX(CMD_HF_MIFAREU_READCARD
, 0, pages
, keytype
, key
, 4);
1607 PacketResponseNG resp
;
1608 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
1609 PrintAndLogEx(WARNING
, "command execution time out");
1615 if (resp
.oldarg
[0] != 1) {
1616 PrintAndLogEx(WARNING
, "Failed reading card");
1623 uint32_t startindex
= resp
.oldarg
[2];
1624 uint32_t buffer_size
= resp
.oldarg
[1];
1625 if (buffer_size
> maxbytes
) {
1626 PrintAndLogEx(FAILED
, "Data exceeded buffer size!");
1627 buffer_size
= maxbytes
;
1630 if (GetFromDevice(BIG_BUF
, *pdata
, buffer_size
, startindex
, NULL
, 0, NULL
, 2500, false) == false) {
1631 PrintAndLogEx(WARNING
, "command execution time out");
1647 Version: 00 04 04 02 01 00 0F 03
1651 E1 10 12 00 01 03 A0 0C 34 03 13 D1 01 0F 54 02 65 6E
1659 uint32_t (*otp
)(const uint8_t *uid
);
1661 } mfu_otp_identify_t
;
1663 static mfu_otp_identify_t mfu_otp_ident_table
[] = {
1664 { "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA
, NULL
},
1665 { NULL
, 0, 0, NULL
, NULL
, NULL
}
1668 static mfu_otp_identify_t
*mfu_match_otp_fingerprint(uint8_t *uid
, uint8_t *data
) {
1672 uint8_t mtmp
[40] = {0};
1674 // static or dynamic created OTP to fingerprint.
1675 if (mfu_otp_ident_table
[i
].match
) {
1676 param_gethex_to_eol(mfu_otp_ident_table
[i
].match
, 0, mtmp
, sizeof(mtmp
), &ml
);
1678 uint32_t otp
= mfu_otp_ident_table
[i
].otp(uid
);
1679 num_to_bytes(otp
, 4, mtmp
);
1682 int min
= MIN(mfu_otp_ident_table
[i
].mlen
, 4);
1684 PrintAndLogEx(DEBUG
, "uid.... %s", sprint_hex_inrow(uid
, 7));
1685 PrintAndLogEx(DEBUG
, "calc... %s", sprint_hex_inrow(mtmp
, 4));
1686 PrintAndLogEx(DEBUG
, "dump... %s", sprint_hex_inrow(data
+ mfu_otp_ident_table
[i
].mpos
, min
));
1688 bool m2
= (memcmp(mtmp
, data
+ mfu_otp_ident_table
[i
].mpos
, min
) == 0);
1690 PrintAndLogEx(DEBUG
, "(fingerprint) found %s", mfu_otp_ident_table
[i
].desc
);
1691 return &mfu_otp_ident_table
[i
];
1693 } while (mfu_otp_ident_table
[++i
].desc
);
1699 const char *version
;
1703 uint32_t (*Pwd
)(const uint8_t *uid
);
1704 uint16_t (*Pack
)(const uint8_t *uid
);
1708 static mfu_identify_t mfu_ident_table
[] = {
1710 "Jooki", "0004040201000F03",
1711 12, 32, "E11012000103A00C340329D101255504732E6A6F6F6B692E726F636B732F732F",
1712 ul_ev1_pwdgen_def
, ul_ev1_packgen_def
,
1716 "Lego Dimensions", "0004040201000F03",
1717 12, 18, "E11012000103A00C340313D1010F5402656E",
1718 ul_ev1_pwdgenC
, ul_ev1_packgenC
,
1719 "hf mfu dump -k %08x"
1722 "Hotwheels", "0004040201000F03",
1724 ul_ev1_pwdgen_def
, ul_ev1_packgen_def
,
1725 "hf mfu dump -k %08x"
1728 "Minecraft Earth", "0004040201000F03",
1729 9, 26, "48F6FFE1101200037C91012C55027069642E6D617474656C2F4167",
1730 ul_ev1_pwdgen_def
, ul_ev1_packgen_def
,
1731 "hf mfu dump -k %08x"
1734 "Snackworld", "0004040101000B03",
1735 9, 7, "483000E1100600",
1740 "Amiibo", "0004040201001103",
1741 9, 9, "480FE0F110FFEEA500",
1742 ul_ev1_pwdgenB
, ul_ev1_packgenB
,
1743 "hf mfu dump -k %08x"
1746 "Amiibo - Power Up band", "0004040502021303",
1747 8, 10, "44000FE0F110FFEEA500",
1748 ul_ev1_pwdgenB
, ul_ev1_packgenB
,
1749 "hf mfu dump -k %08x"
1753 "Xiaomi AIR Purifier", "0004040201000F03",
1755 ul_ev1_pwdgenE, ul_ev1_packgenE,
1756 "hf mfu dump -k %08x"
1760 "Philips Toothbrush", "0004040201010F03",
1761 16, 20, "0310D1010C55027068696C6970732E636F6DFE00",
1762 ul_ev1_pwdgen_def
, ul_ev1_packgen_def
,
1766 "Philips Toothbrush", "0004040201010F03",
1767 16, 36, "0320D1011C55027068696C6970732E636F6D2F6E6663627275736868656164746170FE00",
1768 ul_ev1_pwdgen_def
, ul_ev1_packgen_def
,
1772 "Bank Of Archie brothers", "0004030101000B03",
1773 9, 11, "48F6FF0000000036343533",
1774 ul_ev1_pwdgen_def
, ul_ev1_packgen_def
,
1778 "Art-Dass NFT card", "0004040201000F03",
1779 16, 16, "033ED1013A5504617274646173732E6E",
1780 ul_ev1_pwdgen_def
, ul_ev1_packgen_def
,
1784 "Bonverde Coffe card", "0004030101000B03",
1786 ul_ev1_pwdgen_def
, ul_ev1_packgen_def
,
1789 {NULL
, NULL
, 0, 0, NULL
, NULL
, NULL
, NULL
}
1792 static mfu_identify_t
*mfu_match_fingerprint(const uint8_t *version
, const uint8_t *data
) {
1797 uint8_t vtmp
[10] = {0};
1798 param_gethex_to_eol(mfu_ident_table
[i
].version
, 0, vtmp
, sizeof(vtmp
), &vl
);
1800 bool m1
= (memcmp(vtmp
, version
, vl
) == 0);
1802 PrintAndLogEx(DEBUG
, "(fingerprint) wrong version");
1807 uint8_t mtmp
[40] = {0};
1808 param_gethex_to_eol(mfu_ident_table
[i
].match
, 0, mtmp
, sizeof(mtmp
), &ml
);
1810 bool m2
= (memcmp(mtmp
, data
+ mfu_ident_table
[i
].mpos
, mfu_ident_table
[i
].mlen
) == 0);
1812 PrintAndLogEx(DEBUG
, "(fingerprint) found %s", mfu_ident_table
[i
].desc
);
1813 return &mfu_ident_table
[i
];
1815 } while (mfu_ident_table
[++i
].desc
);
1819 static uint8_t mfu_max_len(void) {
1820 uint8_t n
= 0, i
= 0;
1822 uint8_t tmp
= mfu_ident_table
[i
].mpos
+ mfu_ident_table
[i
].mlen
;
1826 } while (mfu_ident_table
[++i
].desc
);
1830 static int mfu_get_version_uid(uint8_t *version
, uint8_t *uid
) {
1831 iso14a_card_select_t card
;
1832 if (ul_select(&card
) == false) {
1835 memcpy(uid
, card
.uid
, card
.uidlen
);
1837 uint8_t v
[10] = {0x00};
1838 int len
= ulev1_getVersion(v
, sizeof(v
));
1840 if (len
!= sizeof(v
)) {
1844 memcpy(version
, v
, 8);
1848 static int mfu_fingerprint(uint64_t tagtype
, bool hasAuthKey
, const uint8_t *authkey
, int ak_len
) {
1850 uint8_t dbg_curr
= DBG_NONE
;
1851 uint8_t *data
= NULL
;
1852 int res
= PM3_ESOFT
;
1853 PrintAndLogEx(INFO
, "");
1854 PrintAndLogEx(INFO
, "--- " _CYAN_("Fingerprint"));
1855 uint8_t maxbytes
= mfu_max_len();
1856 if (maxbytes
== 0) {
1857 PrintAndLogEx(ERR
, "fingerprint table wrong");
1862 maxbytes
= ((maxbytes
/ MFU_BLOCK_SIZE
) + 1) * MFU_BLOCK_SIZE
;
1863 data
= calloc(maxbytes
, sizeof(uint8_t));
1865 PrintAndLogEx(ERR
, "failed to allocate memory");
1870 uint8_t pages
= (maxbytes
/ MFU_BLOCK_SIZE
);
1871 uint8_t keytype
= 0;
1874 if (tagtype
& MFU_TT_UL_C
)
1875 keytype
= 1; // UL_C auth
1877 keytype
= 2; // UL_EV1/NTAG auth
1880 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
1885 if (setDeviceDebugLevel(DBG_NONE
, false) != PM3_SUCCESS
) {
1890 clearCommandBuffer();
1891 SendCommandMIX(CMD_HF_MIFAREU_READCARD
, 0, pages
, keytype
, authkey
, ak_len
);
1892 PacketResponseNG resp
;
1893 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
1894 PrintAndLogEx(WARNING
, "command execution time out");
1899 if (resp
.oldarg
[0] != 1) {
1900 PrintAndLogEx(WARNING
, "Failed reading card");
1906 uint32_t startindex
= resp
.oldarg
[2];
1907 uint32_t buffer_size
= resp
.oldarg
[1];
1909 if (buffer_size
> maxbytes
) {
1910 PrintAndLogEx(FAILED
, "Data exceeded buffer size!");
1911 buffer_size
= maxbytes
;
1914 if (GetFromDevice(BIG_BUF
, data
, buffer_size
, startindex
, NULL
, 0, NULL
, 2500, false) == false) {
1915 PrintAndLogEx(WARNING
, "command execution time out");
1920 uint8_t version
[8] = {0};
1921 uint8_t uid
[7] = {0};
1922 if (mfu_get_version_uid(version
, uid
) == PM3_SUCCESS
) {
1923 mfu_identify_t
*item
= mfu_match_fingerprint(version
, data
);
1925 PrintAndLogEx(SUCCESS
, _GREEN_("%s"), item
->desc
);
1931 snprintf(s
, sizeof(s
), item
->hint
, item
->Pwd(uid
));
1932 PrintAndLogEx(HINT
, "Use `" _YELLOW_("%s") "`", s
);
1934 PrintAndLogEx(HINT
, "Use `" _YELLOW_("%s") "`", item
->hint
);
1941 mfu_otp_identify_t
*item
= mfu_match_otp_fingerprint(uid
, data
);
1943 PrintAndLogEx(SUCCESS
, _GREEN_("%s"), item
->desc
);
1949 snprintf(s
, sizeof(s
), item
->hint
, item
->otp(uid
));
1950 PrintAndLogEx(HINT
, "Use `" _YELLOW_("%s") "`", s
);
1952 PrintAndLogEx(HINT
, "Use `" _YELLOW_("%s") "`", item
->hint
);
1959 if (res
!= PM3_SUCCESS
) {
1960 PrintAndLogEx(INFO
, "n/a");
1963 setDeviceDebugLevel(dbg_curr
, false);
1968 static int mfu_write_block(const uint8_t *data
, uint8_t datalen
, bool has_auth_key
, bool has_pwd
, const uint8_t *auth_key_ptr
, uint8_t blockno
) {
1972 memcpy(cmd
, data
, datalen
);
1974 // 0 - no pwd/key, no authentication
1975 // 1 - 3des key (16 bytes)
1976 // 2 - pwd (4 bytes)
1977 uint8_t keytype
= 0;
1978 size_t cmdlen
= datalen
;
1981 memcpy(cmd
+ datalen
, auth_key_ptr
, 16);
1983 } else if (has_pwd
) {
1985 memcpy(cmd
+ datalen
, auth_key_ptr
, 4);
1989 clearCommandBuffer();
1990 if (datalen
== 16) {
1991 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL_COMPAT
, blockno
, keytype
, 0, cmd
, cmdlen
);
1993 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, blockno
, keytype
, 0, cmd
, cmdlen
);
1995 PacketResponseNG resp
;
1996 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
1997 return PM3_ETIMEOUT
;
2000 uint8_t isOK
= resp
.oldarg
[0] & 0xFF;
2007 uint64_t GetHF14AMfU_Type(void) {
2009 uint64_t tagtype
= MFU_TT_UNKNOWN
;
2010 iso14a_card_select_t card
;
2012 if (ul_select(&card
) == false)
2013 return MFU_TT_UL_ERROR
;
2015 // Ultralight - ATQA / SAK
2016 if (card
.atqa
[1] != 0x00 || card
.atqa
[0] != 0x44 || card
.sak
!= 0x00) {
2017 //PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D |ST25TN [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak);
2019 return MFU_TT_UL_ERROR
;
2021 if (card
.uid
[0] == 0x02) {
2024 uint8_t data
[4] = {0x00};
2025 int status
= ul_read(0x02, data
, sizeof(data
));
2027 tagtype
= MFU_TT_UL
;
2029 status
= ul_read(data
[1] + 1, data
, sizeof(data
));
2031 tagtype
= MFU_TT_UL
;
2033 // data[3] == KID == 0x05 Key ID
2034 // data[2] == REV == 0x13 Product version
2035 if ((data
[1]==0x90) && (data
[0]==0x90)) {
2036 tagtype
= MFU_TT_ST25TN01K
;
2037 } else if ((data
[1]==0x90) && (data
[0]==0x91)) {
2038 tagtype
= MFU_TT_ST25TN512
;
2042 } else if (card
.uid
[0] == 0x05) {
2043 // Infineon MY-D tests Exam high nibble
2045 uint8_t nib
= (card
.uid
[1] & 0xf0) >> 4;
2047 // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k
2049 tagtype
= MFU_TT_MY_D
;
2050 break; // or SLE 66RxxS ... up to 512 pages of 8 user bytes...
2052 tagtype
= MFU_TT_MY_D_NFC
;
2053 break; // or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes)
2055 tagtype
= (MFU_TT_MY_D_MOVE
| MFU_TT_MY_D_MOVE_NFC
);
2056 break; // or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two
2058 tagtype
= MFU_TT_MY_D_MOVE_LEAN
;
2059 break; // or SLE 66R01L // 16 pages of 4 bytes
2063 uint8_t version
[10] = {0x00};
2064 int len
= ulev1_getVersion(version
, sizeof(version
));
2069 MF0UL1001DUx 0004030100000B03
2070 MF0UL1101DUx 0004030101000B03
2071 MF0ULH1101DUx 0004030201000B03
2072 MF0UL1141DUF 0004030301000B03
2073 MF0UL2101Dxy 0004030101000E03
2074 MF0UL2101DUx 0004030201000E03
2075 MF0UL3101DUx 0004030101001103
2076 MF0ULH3101DUx 0004030201001103
2077 MF0UL5101DUx 0004030101001303
2078 NT2L1011F0DUx 0004040101000B03
2079 NT2H1011G0DUD 0004040201000B03
2080 NT2L1211F0DUx 0004040101000E03
2081 NT2H1311G0DUx 0004040201000F03
2082 NT2H1311F0Dxy 0004040401000F03
2083 NT2H1411G0DUx 0004040201011103
2084 NT2H1511G0DUx 0004040201001103
2085 NT2H1511F0Dxy 0004040401001103
2086 NT2H1611G0DUx 0004040201001303
2087 NT2H1611F0Dxy 0004040401001303
2088 NT2H1311C1DTL 0004040201010F03
2089 NT2H1311TTDUx 0004040203000F03
2090 NT3H1101W0FHK 0004040502001303
2091 NT3H1201W0FHK 0004040502001503
2092 NT3H1101W0FHK_Variant 0004040502011303
2093 NT3H1201 0004040502011503
2094 NT3H2111 0004040502021303
2095 NT3H2211 0004040502021503
2096 nhs 0004040600001303
2097 MF0UN0001DUx 0004030102000B03
2098 MF0UNH0001DUx 0004030202000B03
2099 MF0UN1001DUx 0004030103000B03
2100 MF0UNH1001DUx 0004030203000B03
2101 NT2L1001G0DUx 0004040102000B03
2102 NT2H1001G0DUx 0004040202000B03
2103 NT2H1311TTDUx 0004040203000F03
2104 MF0AES2001DUD 0004030104000F03
2106 Micron UL 0034210101000E03
2107 Feiju NTAG 0053040201000F03
2108 Feiju NTAG 215 0005340201001103
2111 if (memcmp(version
, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { tagtype
= MFU_TT_UL_EV1_48
; break; }
2112 else if (memcmp(version
, "\x00\x04\x03\x01\x02\x00\x0B", 7) == 0) { tagtype
= MFU_TT_UL_NANO_40
; break; }
2113 else if (memcmp(version
, "\x00\x04\x03\x02\x01\x00\x0B", 7) == 0) { tagtype
= MFU_TT_UL_EV1_48
; break; }
2114 else if (memcmp(version
, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { tagtype
= MFU_TT_UL_EV1_128
; break; }
2115 else if (memcmp(version
, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { tagtype
= MFU_TT_UL_EV1_128
; break; }
2116 else if (memcmp(version
, "\x00\x04\x03\x01\x04\x00\x0F\x03", 8) == 0) { tagtype
= MFU_TT_UL_AES
; break; }
2117 else if (memcmp(version
, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { tagtype
= MFU_TT_UL_EV1_128
; break; } // Mikron JSC Russia EV1 41 pages tag
2118 else if (memcmp(version
, "\x00\x04\x04\x01\x01\x00\x0B", 7) == 0) { tagtype
= MFU_TT_NTAG_210
; break; }
2119 else if (memcmp(version
, "\x00\x04\x04\x01\x02\x00\x0B", 7) == 0) { tagtype
= MFU_TT_NTAG_210u
; break; }
2120 else if (memcmp(version
, "\x00\x04\x04\x02\x02\x00\x0B", 7) == 0) { tagtype
= MFU_TT_NTAG_210u
; break; }
2121 else if (memcmp(version
, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype
= MFU_TT_NTAG_212
; break; }
2122 else if (memcmp(version
, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype
= MFU_TT_NTAG_213
; break; }
2123 else if (memcmp(version
, "\x00\x53\x04\x02\x01\x00\x0F", 7) == 0) { tagtype
= MFU_TT_NTAG_213
; break; } // Shanghai Feiju Microelectronics Co. Ltd. China (Xiaomi Air Purifier filter)
2124 else if (memcmp(version
, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype
= MFU_TT_NTAG_213_C
; break; }
2125 else if (memcmp(version
, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype
= MFU_TT_NTAG_215
; break; }
2126 else if (memcmp(version
, "\x00\x05\x34\x02\x01\x00\x11", 7) == 0) { tagtype
= MFU_TT_NTAG_215
; break; } // Shanghai Feiju Microelectronics Co. Ltd. China
2127 else if (memcmp(version
, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype
= MFU_TT_NTAG_216
; break; }
2128 else if (memcmp(version
, "\x00\x04\x04\x04\x01\x00\x0F", 7) == 0) { tagtype
= MFU_TT_NTAG_213_F
; break; }
2129 else if (memcmp(version
, "\x00\x04\x04\x04\x01\x00\x13", 7) == 0) { tagtype
= MFU_TT_NTAG_216_F
; break; }
2130 else if (memcmp(version
, "\x00\x04\x04\x02\x03\x00\x0F", 7) == 0) { tagtype
= MFU_TT_NTAG_213_TT
; break; }
2131 else if (memcmp(version
, "\x00\x04\x04\x05\x02\x01\x13", 7) == 0) { tagtype
= MFU_TT_NTAG_I2C_1K
; break; }
2132 else if (memcmp(version
, "\x00\x04\x04\x05\x02\x01\x15", 7) == 0) { tagtype
= MFU_TT_NTAG_I2C_2K
; break; }
2133 else if (memcmp(version
, "\x00\x04\x04\x05\x02\x02\x13", 7) == 0) { tagtype
= MFU_TT_NTAG_I2C_1K_PLUS
; break; }
2134 else if (memcmp(version
, "\x00\x04\x04\x05\x02\x02\x15", 7) == 0) { tagtype
= MFU_TT_NTAG_I2C_2K_PLUS
; break; }
2135 else if (version
[2] == 0x04) { tagtype
= MFU_TT_NTAG
; break; }
2136 else if (version
[2] == 0x03) { tagtype
= MFU_TT_UL_EV1
; }
2140 tagtype
= MFU_TT_UL_C
;
2143 tagtype
= MFU_TT_UL
;
2146 case PM3_EWRONGANSWER
:
2147 tagtype
= (MFU_TT_UL
| MFU_TT_UL_C
| MFU_TT_NTAG_203
);
2148 break; // could be UL | UL_C magic tags
2150 tagtype
= MFU_TT_UNKNOWN
;
2153 // This is a test from cards that doesn't answer to GET_VERSION command
2154 // UL vs UL-C vs NTAG203 vs FUDAN FM11NT021 (which is NTAG213 compatiable)
2155 if (tagtype
& (MFU_TT_UL
| MFU_TT_UL_C
| MFU_TT_NTAG_203
)) {
2156 if (ul_select(&card
) == false) {
2157 return MFU_TT_UL_ERROR
;
2160 // do UL_C check first...
2161 uint8_t nonce
[11] = {0x00};
2162 int status
= ulc_requestAuthentication(nonce
, sizeof(nonce
));
2165 tagtype
= MFU_TT_UL_C
;
2167 // need to re-select after authentication error
2168 if (ul_select(&card
) == false) {
2169 return MFU_TT_UL_ERROR
;
2172 uint8_t data
[16] = {0x00};
2174 // read page 0x26-0x29 (last valid ntag203 page)
2175 // if error response, its ULTRALIGHT since doesn't have that memory block
2176 status
= ul_read(0x26, data
, sizeof(data
));
2178 tagtype
= MFU_TT_UL
;
2181 // read page 44 / 0x2C
2182 // if error response, its NTAG203 since doesn't have that memory block
2183 status
= ul_read(0x2C, data
, sizeof(data
));
2185 tagtype
= MFU_TT_NTAG_203
;
2188 // read page 48 / 0x30
2189 // if response, its FUDAN FM11NT021
2190 status
= ul_read(0x30, data
, sizeof(data
));
2191 if (status
== sizeof(data
)) {
2192 tagtype
= MFU_TT_NTAG_213
;
2194 tagtype
= MFU_TT_UNKNOWN
;
2202 if (tagtype
& MFU_TT_UL
) {
2203 tagtype
= ul_fudan_check();
2208 tagtype
|= ul_magic_test();
2209 if (tagtype
== (MFU_TT_UNKNOWN
| MFU_TT_MAGIC
)) {
2210 tagtype
= (MFU_TT_UL_MAGIC
);
2216 // extended tag information
2218 static int CmdHF14AMfUInfo(const char *Cmd
) {
2220 CLIParserContext
*ctx
;
2221 CLIParserInit(&ctx
, "hf mfu info",
2222 "Get info about MIFARE Ultralight Family styled tag.\n"
2223 "Sometimes the tags are locked down, and you may need a key to be able to read the information",
2225 "hf mfu info -k AABBCCDD\n"
2226 "hf mfu info --key 00112233445566778899AABBCCDDEEFF"
2229 void *argtable
[] = {
2231 arg_str0("k", "key", "<hex>", "Authentication key (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
2232 arg_lit0("l", NULL
, "Swap entered key's endianness"),
2233 // arg_lit0("v", "verbose", "verbose output"),
2234 arg_lit0(NULL
, "force", "override `hw dbg` settings"),
2237 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
2240 uint8_t authenticationkey
[16] = {0x00};
2241 CLIGetHexWithReturn(ctx
, 1, authenticationkey
, &ak_len
);
2242 bool swap_endian
= arg_get_lit(ctx
, 2);
2243 // bool verbose = arg_get_lit(ctx, 3);
2244 bool override
= (arg_get_lit(ctx
, 3) == false);
2248 if (ak_len
!= 16 && ak_len
!= 4) {
2249 PrintAndLogEx(WARNING
, "ERROR: Key is incorrect length\n");
2254 bool has_auth_key
= false;
2256 has_auth_key
= true;
2258 uint8_t authlim
= 0xff;
2259 uint8_t data
[16] = {0x00};
2260 iso14a_card_select_t card
;
2262 uint8_t *authkeyptr
= authenticationkey
;
2263 uint8_t pwd
[4] = {0, 0, 0, 0};
2265 uint8_t pack
[4] = {0, 0, 0, 0};
2268 uint64_t tagtype
= GetHF14AMfU_Type();
2269 if (tagtype
== MFU_TT_UL_ERROR
) {
2273 PrintAndLogEx(NORMAL
, "");
2274 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Information") " --------------------------");
2275 ul_print_type(tagtype
, 6);
2278 if (swap_endian
&& has_auth_key
) {
2279 authkeyptr
= SwapEndian64(authenticationkey
, ak_len
, (ak_len
== 16) ? 8 : 4);
2282 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2286 bool locked
= false;
2287 // read pages 0,1,2,3 (should read 4 pages)
2288 status
= ul_read(0, data
, sizeof(data
));
2291 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ");
2293 } else if (status
== 16) {
2294 ul_print_default(data
, card
.uid
);
2295 ndef_print_CC(data
+ 12);
2301 if ((tagtype
& MFU_TT_UL_C
)) {
2303 // read pages 0x28, 0x29, 0x2A, 0x2B
2304 uint8_t ulc_conf
[16] = {0x00};
2305 status
= ul_read(0x28, ulc_conf
, sizeof(ulc_conf
));
2307 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ UL-C");
2308 PrintAndLogEx(HINT
, "Hint: tag is likely fully read protected");
2314 ulc_print_configuration(ulc_conf
);
2319 mfu_fingerprint(tagtype
, has_auth_key
, authkeyptr
, ak_len
);
2323 if ((tagtype
& MFU_TT_MAGIC
) == MFU_TT_MAGIC
) {
2325 uint8_t ulc_deskey
[16] = {0x00};
2326 status
= ul_read(0x2C, ulc_deskey
, sizeof(ulc_deskey
));
2329 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ magic");
2334 ulc_print_3deskey(ulc_deskey
);
2337 PrintAndLogEx(NORMAL
, "");
2341 // if we called info with key, just return
2343 PrintAndLogEx(NORMAL
, "");
2347 // also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
2348 if (try_default_3des_keys(override
, &key
) == PM3_SUCCESS
) {
2349 PrintAndLogEx(SUCCESS
, "Found default 3des key: ");
2350 uint8_t keySwap
[16];
2351 memcpy(keySwap
, SwapEndian64(key
, 16, 8), 16);
2352 ulc_print_3deskey(keySwap
);
2354 PrintAndLogEx(INFO
, "n/a");
2357 PrintAndLogEx(NORMAL
, "");
2363 if (tagtype
& MFU_TT_UL_AES
) {
2365 // read pages 0x28, 0x29, 0x2A, 0x2B
2366 uint8_t ulaes_conf
[16] = {0x00};
2367 status
= ul_read(0x29, ulaes_conf
, sizeof(ulaes_conf
));
2369 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ UL-AES");
2375 ulaes_print_configuration(ulaes_conf
, 0x29);
2382 // also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
2383 if (try_default_aes_keys(override
) != PM3_SUCCESS
) {
2384 PrintAndLogEx(INFO
, "n/a");
2388 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2393 // do counters and signature first (don't neet auth)
2395 // ul counters are different than ntag counters
2396 if ((tagtype
& (MFU_TT_UL_EV1_48
| MFU_TT_UL_EV1_128
| MFU_TT_UL_EV1
))) {
2397 if (ulev1_print_counters() != 3) {
2398 // failed - re-select
2399 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2406 if ((tagtype
& (MFU_TT_NTAG_213
| MFU_TT_NTAG_213_F
| MFU_TT_NTAG_213_C
| MFU_TT_NTAG_213_TT
| MFU_TT_NTAG_215
| MFU_TT_NTAG_216
))) {
2407 if (ntag_print_counter()) {
2408 // failed - re-select
2409 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2415 // ST25TN info & signature
2416 if (tagtype
& (MFU_TT_ST25TN512
| MFU_TT_ST25TN01K
)) {
2417 status
= ul_read(0x02, data
, sizeof(data
));
2419 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ SYSBLOCK");
2423 status
= ul_read(data
[1] + 1, data
, sizeof(data
));
2425 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ SYSBLOCK");
2429 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag System Information"));
2430 PrintAndLogEx(INFO
, " Key ID: %02x", data
[3]);
2431 PrintAndLogEx(INFO
, " Product Version: %02x", data
[2]);
2432 PrintAndLogEx(INFO
, " Product Code: %02x%02x", data
[1], data
[0]);
2433 uint8_t signature
[32] = {0};
2434 for (int blkoff
=0; blkoff
<8; blkoff
++) {
2435 status
= ul_read(0x34 + blkoff
, signature
+ (blkoff
* 4), 4);
2437 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ SYSBLOCK");
2443 int index
= originality_check_verify_ex(card
.uid
, 7, signature
, sizeof(signature
), PK_ST25TN
, false, true);
2444 PrintAndLogEx(NORMAL
, "");
2445 originality_check_print(signature
, sizeof(signature
), index
);
2449 if ((tagtype
& (MFU_TT_UL_EV1_48
| MFU_TT_UL_EV1_128
| MFU_TT_UL_EV1
| MFU_TT_UL_NANO_40
|
2450 MFU_TT_NTAG_210u
| MFU_TT_NTAG_213
| MFU_TT_NTAG_213_F
| MFU_TT_NTAG_213_C
|
2451 MFU_TT_NTAG_213_TT
| MFU_TT_NTAG_215
| MFU_TT_NTAG_216
| MFU_TT_NTAG_216_F
|
2452 MFU_TT_NTAG_I2C_1K
| MFU_TT_NTAG_I2C_2K
| MFU_TT_NTAG_I2C_1K_PLUS
| MFU_TT_NTAG_I2C_2K_PLUS
|
2454 uint8_t ulev1_signature
[48] = {0x00};
2455 status
= ulev1_readSignature(ulev1_signature
, sizeof(ulev1_signature
));
2457 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ SIGNATURE");
2461 if (status
== 32 || status
== 34) {
2462 ulev1_print_signature(tagtype
, card
.uid
, ulev1_signature
, 32);
2463 } else if (status
== 48) {
2464 ulev1_print_signature(tagtype
, card
.uid
, ulev1_signature
, 48);
2467 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2472 // print silicon info
2473 ul_print_nxp_silicon_info(card
.uid
);
2476 uint8_t version
[10] = {0x00};
2477 status
= ulev1_getVersion(version
, sizeof(version
));
2479 PrintAndLogEx(ERR
, "Error: tag didn't answer to GETVERSION");
2482 } else if (status
== 10) {
2483 ulev1_print_version(version
);
2486 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2491 // Don't check config / passwords for Ul AES :)
2492 if (tagtype
== MFU_TT_UL_AES
) {
2496 uint8_t startconfigblock
= 0;
2497 uint8_t ulev1_conf
[16] = {0x00};
2499 for (uint8_t i
= 1; i
< ARRAYLEN(UL_TYPES_ARRAY
); i
++) {
2500 if ((tagtype
& UL_TYPES_ARRAY
[i
]) == UL_TYPES_ARRAY
[i
]) {
2501 startconfigblock
= UL_MEMORY_ARRAY
[i
] - 3;
2506 if (startconfigblock
) { // if we know where the config block is...
2507 status
= ul_read(startconfigblock
, ulev1_conf
, sizeof(ulev1_conf
));
2509 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ EV1");
2512 } else if (status
== 16) {
2513 // save AUTHENTICATION LIMITS for later:
2514 authlim
= (ulev1_conf
[4] & 0x07);
2515 // add pwd / pack if used from cli
2517 memcpy(ulev1_conf
+ 8, authkeyptr
, 4);
2518 memcpy(ulev1_conf
+ 12, pack
, 2);
2520 ulev1_print_configuration(tagtype
, ulev1_conf
, startconfigblock
);
2524 // AUTHLIMIT, (number of failed authentications)
2526 // 1-7 = limit. No automatic tries then.
2527 // hasAuthKey, if we was called with key, skip test.
2528 if (!authlim
&& (has_auth_key
== false)) {
2529 PrintAndLogEx(NORMAL
, "");
2530 PrintAndLogEx(SUCCESS
, "--- " _CYAN_("Known EV1/NTAG passwords"));
2533 num_to_bytes(ul_ev1_pwdgenA(card
.uid
), 4, key
);
2534 len
= ulev1_requestAuthentication(key
, pack
, sizeof(pack
));
2536 has_auth_key
= true;
2538 memcpy(authenticationkey
, key
, 4);
2539 PrintAndLogEx(SUCCESS
, "Password... " _GREEN_("%s") " pack... " _GREEN_("%02X%02X"), sprint_hex_inrow(key
, 4), pack
[0], pack
[1]);
2543 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2548 num_to_bytes(ul_ev1_pwdgenB(card
.uid
), 4, key
);
2549 len
= ulev1_requestAuthentication(key
, pack
, sizeof(pack
));
2551 has_auth_key
= true;
2553 memcpy(authenticationkey
, key
, 4);
2554 PrintAndLogEx(SUCCESS
, "Password... " _GREEN_("%s") " pack... " _GREEN_("%02X%02X"), sprint_hex_inrow(key
, 4), pack
[0], pack
[1]);
2558 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2563 num_to_bytes(ul_ev1_pwdgenC(card
.uid
), 4, key
);
2564 len
= ulev1_requestAuthentication(key
, pack
, sizeof(pack
));
2566 has_auth_key
= true;
2568 memcpy(authenticationkey
, key
, 4);
2569 PrintAndLogEx(SUCCESS
, "Password... " _GREEN_("%s") " pack... " _GREEN_("%02X%02X"), sprint_hex_inrow(key
, 4), pack
[0], pack
[1]);
2573 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2578 num_to_bytes(ul_ev1_pwdgenD(card
.uid
), 4, key
);
2579 len
= ulev1_requestAuthentication(key
, pack
, sizeof(pack
));
2581 has_auth_key
= true;
2583 memcpy(authenticationkey
, key
, 4);
2584 PrintAndLogEx(SUCCESS
, "Password... " _GREEN_("%s") " pack... " _GREEN_("%02X%02X"), sprint_hex_inrow(key
, 4), pack
[0], pack
[1]);
2588 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2592 for (uint8_t i
= 0; i
< ARRAYLEN(default_pwd_pack
); ++i
) {
2593 key
= default_pwd_pack
[i
];
2594 len
= ulev1_requestAuthentication(key
, pack
, sizeof(pack
));
2596 has_auth_key
= true;
2598 memcpy(authenticationkey
, key
, 4);
2599 PrintAndLogEx(SUCCESS
, "Password... " _GREEN_("%s") " pack... " _GREEN_("%02X%02X"), sprint_hex_inrow(key
, 4), pack
[0], pack
[1]);
2602 if (ul_auth_select(&card
, tagtype
, has_auth_key
, authkeyptr
, pack
, sizeof(pack
)) == PM3_ESOFT
) {
2608 PrintAndLogEx(WARNING
, _YELLOW_("password not known"));
2609 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`hf mfu pwdgen -r`") " to get see known pwd gen algo suggestions");
2613 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`hf mfu pwdgen -r`") " to get see known pwd gen algo suggestions");
2621 mfu_fingerprint(tagtype
, has_auth_key
, authkeyptr
, ak_len
);
2624 PrintAndLogEx(INFO
, "\nTag appears to be locked, try using a key to get more info");
2625 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`hf mfu pwdgen -r`") " to get see known pwd gen algo suggestions");
2628 if (tagtype
& (MFU_TT_MAGIC_1A
| MFU_TT_MAGIC_1B
| MFU_TT_MAGIC_2
)) {
2629 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`script run hf_mfu_setuid -h`") " to set UID");
2632 PrintAndLogEx(NORMAL
, "");
2637 // Write Single Block
2639 static int CmdHF14AMfUWrBl(const char *Cmd
) {
2641 CLIParserContext
*ctx
;
2642 CLIParserInit(&ctx
, "hf mfu wrbl",
2643 "Write a block. It autodetects card type.",
2644 "hf mfu wrbl -b 0 -d 01234567\n"
2645 "hf mfu wrbl -b 0 -d 01234567 -k AABBCCDD\n"
2646 "hf mfu wrbl -b 0 -d 01234567 -k 00112233445566778899AABBCCDDEEFF"
2649 void *argtable
[] = {
2651 arg_str0("k", "key", "<hex>", "Authentication key (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
2652 arg_lit0("l", NULL
, "Swap entered key's endianness"),
2653 arg_int1("b", "block", "<dec>", "Block number to write"),
2654 arg_str1("d", "data", "<hex>", "Block data (4 or 16 hex bytes, 16 hex bytes will do a compatibility write)"),
2655 arg_lit0(NULL
, "force", "Force operation even if address is out of range"),
2658 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2661 uint8_t authenticationkey
[16] = {0x00};
2662 CLIGetHexWithReturn(ctx
, 1, authenticationkey
, &ak_len
);
2663 bool swap_endian
= arg_get_lit(ctx
, 2);
2665 int blockno
= arg_get_int_def(ctx
, 3, -1);
2668 uint8_t data
[16] = {0x00};
2669 CLIGetHexWithReturn(ctx
, 4, data
, &datalen
);
2670 bool force
= arg_get_lit(ctx
, 5);
2673 bool has_auth_key
= false;
2674 bool has_pwd
= false;
2676 has_auth_key
= true;
2677 } else if (ak_len
== 4) {
2679 } else if (ak_len
!= 0) {
2680 PrintAndLogEx(WARNING
, "ERROR: Key is incorrect length\n");
2685 PrintAndLogEx(WARNING
, "Wrong block number");
2689 if (datalen
!= 16 && datalen
!= 4) {
2690 PrintAndLogEx(WARNING
, "Wrong data length. Expect 16 or 4, got %d", datalen
);
2694 uint8_t *auth_key_ptr
= authenticationkey
;
2696 // starting with getting tagtype
2697 uint64_t tagtype
= GetHF14AMfU_Type();
2698 if (tagtype
== MFU_TT_UL_ERROR
)
2701 uint8_t maxblockno
= 0;
2702 for (uint8_t idx
= 1; idx
< ARRAYLEN(UL_TYPES_ARRAY
); idx
++) {
2703 if ((tagtype
& UL_TYPES_ARRAY
[idx
]) == UL_TYPES_ARRAY
[idx
]) {
2704 maxblockno
= UL_MEMORY_ARRAY
[idx
];
2708 if ((blockno
> maxblockno
) && (!force
)) {
2709 PrintAndLogEx(WARNING
, "block number too large. Max block is %u/0x%02X \n", maxblockno
, maxblockno
);
2716 auth_key_ptr
= SwapEndian64(authenticationkey
, 16, 8);
2719 auth_key_ptr
= SwapEndian64(authenticationkey
, 4, 4);
2723 PrintAndLogEx(INFO
, "Special block: %0d (0x%02X) [ %s]", blockno
, blockno
, sprint_hex(data
, datalen
));
2725 PrintAndLogEx(INFO
, "Block: %0d (0x%02X) [ %s]", blockno
, blockno
, sprint_hex(data
, datalen
));
2728 PrintAndLogEx(INFO
, "Using %s " _GREEN_("%s"), (ak_len
== 16) ? "3des" : "pwd", sprint_hex(authenticationkey
, ak_len
));
2732 // Send write Block.
2735 if (datalen
== 16) {
2736 // Comp write may take 16bytes, but only write 4bytes. See UL-C datasheet
2737 for (uint8_t i
= 0; i
< 4; i
++) {
2739 res
= mfu_write_block(d
, 4, has_auth_key
, has_pwd
, auth_key_ptr
, blockno
+ i
);
2740 if (res
== PM3_SUCCESS
) {
2743 PrintAndLogEx(INFO
, "Write ( %s )", _RED_("fail"));
2748 if (res
== PM3_SUCCESS
) {
2749 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
2750 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf mfu rdbl -b %u") "` to verify ", blockno
);
2754 res
= mfu_write_block(data
, datalen
, has_auth_key
, has_pwd
, auth_key_ptr
, blockno
);
2757 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
2758 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf mfu rdbl -b %u") "` to verify ", blockno
);
2762 PrintAndLogEx(FAILED
, "Write ( " _RED_("fail") " )");
2763 PrintAndLogEx(HINT
, "Check password / key!");
2768 PrintAndLogEx(WARNING
, "command execution time out");
2777 // Read Single Block
2779 static int CmdHF14AMfURdBl(const char *Cmd
) {
2781 CLIParserContext
*ctx
;
2782 CLIParserInit(&ctx
, "hf mfu rdbl",
2783 "Read a block and print. It autodetects card type.",
2784 "hf mfu rdbl -b 0\n"
2785 "hf mfu rdbl -b 0 -k AABBCCDD\n"
2786 "hf mfu rdbl -b 0 --key 00112233445566778899AABBCCDDEEFF"
2789 void *argtable
[] = {
2791 arg_str0("k", "key", "<hex>", "Authentication key (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
2792 arg_lit0("l", NULL
, "Swap entered key's endianness"),
2793 arg_int1("b", "block", "<dec>", "Block number to read"),
2794 arg_lit0(NULL
, "force", "Force operation even if address is out of range"),
2797 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2800 uint8_t authenticationkey
[16] = {0x00};
2801 CLIGetHexWithReturn(ctx
, 1, authenticationkey
, &ak_len
);
2802 bool swap_endian
= arg_get_lit(ctx
, 2);
2803 int blockno
= arg_get_int_def(ctx
, 3, -1);
2804 bool force
= arg_get_lit(ctx
, 4);
2807 bool has_auth_key
= false;
2808 bool has_pwd
= false;
2810 has_auth_key
= true;
2811 } else if (ak_len
== 4) {
2813 } else if (ak_len
!= 0) {
2814 PrintAndLogEx(WARNING
, "ERROR: Key is incorrect length\n");
2819 PrintAndLogEx(WARNING
, "Wrong block number");
2823 uint8_t *authKeyPtr
= authenticationkey
;
2825 // start with getting tagtype
2826 uint64_t tagtype
= GetHF14AMfU_Type();
2827 if (tagtype
== MFU_TT_UL_ERROR
)
2830 uint8_t maxblockno
= 0;
2831 for (uint8_t idx
= 1; idx
< ARRAYLEN(UL_TYPES_ARRAY
); idx
++) {
2832 if ((tagtype
& UL_TYPES_ARRAY
[idx
]) == UL_TYPES_ARRAY
[idx
]) {
2833 maxblockno
= UL_MEMORY_ARRAY
[idx
];
2837 if ((blockno
> maxblockno
) && (!force
)) {
2838 PrintAndLogEx(WARNING
, "block number to large. Max block is %u/0x%02X \n", maxblockno
, maxblockno
);
2845 authKeyPtr
= SwapEndian64(authenticationkey
, ak_len
, 8);
2848 authKeyPtr
= SwapEndian64(authenticationkey
, ak_len
, 4);
2852 PrintAndLogEx(INFO
, "Using %s " _GREEN_("%s"), (ak_len
== 16) ? "3des" : "pwd", sprint_hex(authenticationkey
, ak_len
));
2856 uint8_t keytype
= 0;
2857 uint8_t datalen
= 0;
2861 } else if (has_pwd
) {
2866 clearCommandBuffer();
2867 SendCommandMIX(CMD_HF_MIFAREU_READBL
, blockno
, keytype
, 0, authKeyPtr
, datalen
);
2868 PacketResponseNG resp
;
2869 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
2870 uint8_t isOK
= resp
.oldarg
[0] & 0xff;
2872 uint8_t *d
= resp
.data
.asBytes
;
2873 PrintAndLogEx(NORMAL
, "");
2874 PrintAndLogEx(INFO
, "Block# | Data | Ascii");
2875 PrintAndLogEx(INFO
, "-----------------------------");
2876 PrintAndLogEx(INFO
, "%02d/0x%02X | %s| %s\n", blockno
, blockno
, sprint_hex(d
, 4), sprint_ascii(d
, 4));
2878 PrintAndLogEx(WARNING
, "Failed reading block: ( %02x )", isOK
);
2881 PrintAndLogEx(WARNING
, "command execution time out");
2886 void mfu_print_dump(mfu_dump_t
*card
, uint16_t pages
, uint8_t startpage
, bool dense_output
) {
2888 PrintAndLogEx(NORMAL
, "");
2889 PrintAndLogEx(INFO
, _CYAN_("MFU dump file information"));
2890 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
2891 PrintAndLogEx(INFO
, "Version..... " _YELLOW_("%s"), sprint_hex(card
->version
, sizeof(card
->version
)));
2892 PrintAndLogEx(INFO
, "TBD 0....... %s", sprint_hex(card
->tbo
, sizeof(card
->tbo
)));
2893 PrintAndLogEx(INFO
, "TBD 1....... %s", sprint_hex(card
->tbo1
, sizeof(card
->tbo1
)));
2894 PrintAndLogEx(INFO
, "Signature... %s", sprint_hex(card
->signature
, 16));
2895 PrintAndLogEx(INFO
, " %s", sprint_hex(card
->signature
+ 16, sizeof(card
->signature
) - 16));
2896 for (uint8_t i
= 0; i
< 3; i
++) {
2897 PrintAndLogEx(INFO
, "Counter %d... %s", i
, sprint_hex(card
->counter_tearing
[i
], 3));
2898 PrintAndLogEx(INFO
, "Tearing %d... %s", i
, sprint_hex(card
->counter_tearing
[i
] + 3, 1));
2901 // 0-bases index, to get total bytes, its +1 page.
2903 // Max index page is 47.
2904 // total pages is 48
2905 // total bytes is 192
2906 PrintAndLogEx(INFO
, "Max data page... " _YELLOW_("%d") " ( " _YELLOW_("%d") " bytes )", card
->pages
, (card
->pages
+ 1) * MFU_BLOCK_SIZE
);
2907 PrintAndLogEx(INFO
, "Header size..... %d bytes", MFU_DUMP_PREFIX_LENGTH
);
2910 bool lckbit
= false;
2911 uint8_t *data
= card
->data
;
2913 uint8_t lockbytes_sta
[] = {0, 0};
2914 uint8_t lockbytes_dyn
[] = {0, 0, 0};
2915 bool bit_stat
[16] = {0};
2916 bool bit_dyn
[16] = {0};
2918 // Load static lock bytes.
2919 memcpy(lockbytes_sta
, data
+ 10, sizeof(lockbytes_sta
));
2920 for (j
= 0; j
< 16; j
++) {
2921 bit_stat
[j
] = lockbytes_sta
[j
/ 8] & (1 << (7 - j
% 8));
2924 // Load dynamic lockbytes if available
2925 // TODO -- FIGURE OUT LOCK BYTES FOR TO EV1 and/or NTAG
2928 memcpy(lockbytes_dyn
, data
+ (40 * 4), sizeof(lockbytes_dyn
));
2930 for (j
= 0; j
< 16; j
++) {
2931 bit_dyn
[j
] = lockbytes_dyn
[j
/ 8] & (1 << (7 - j
% 8));
2933 PrintAndLogEx(INFO
, "Dynamic lock.... %s", sprint_hex(lockbytes_dyn
, 3));
2936 PrintAndLogEx(NORMAL
, "");
2937 PrintAndLogEx(INFO
, "-------------------------------------------------------------");
2938 PrintAndLogEx(INFO
, "block# | data |lck| ascii");
2939 PrintAndLogEx(INFO
, "---------+-------------+---+------");
2941 bool in_repeated_block
= false;
2943 for (uint16_t i
= 0; i
< pages
; ++i
) {
2945 PrintAndLogEx(INFO
, "%3d/0x%02X | " _RED_("%s")"| | %s",
2948 sprint_hex(data
+ i
* 4, 4),
2949 sprint_ascii(data
+ i
* 4, 4)
2955 lckbit
= bit_stat
[4];
2958 lckbit
= bit_stat
[3];
2961 lckbit
= bit_stat
[2];
2964 lckbit
= bit_stat
[1];
2967 lckbit
= bit_stat
[0];
2970 lckbit
= bit_stat
[15];
2973 lckbit
= bit_stat
[14];
2976 lckbit
= bit_stat
[13];
2979 lckbit
= bit_stat
[12];
2982 lckbit
= bit_stat
[11];
2985 lckbit
= bit_stat
[10];
2988 lckbit
= bit_stat
[9];
2991 lckbit
= bit_stat
[8];
2997 lckbit
= bit_dyn
[6];
3003 lckbit
= bit_dyn
[5];
3009 lckbit
= bit_dyn
[4];
3015 lckbit
= bit_dyn
[2];
3021 lckbit
= bit_dyn
[1];
3027 lckbit
= bit_dyn
[0];
3030 lckbit
= bit_dyn
[12];
3033 lckbit
= bit_dyn
[11];
3036 lckbit
= bit_dyn
[10];
3039 lckbit
= bit_dyn
[9];
3046 // suppress repeating blocks, truncate as such that the first and last block with the same data is shown
3047 // but the blocks in between are replaced with a single line of "......" if dense_output is enabled
3048 const uint8_t *blk
= data
+ (i
* MFU_BLOCK_SIZE
);
3052 (in_repeated_block
== false) &&
3053 (memcmp(blk
, blk
- MFU_BLOCK_SIZE
, MFU_BLOCK_SIZE
) == 0) &&
3054 (memcmp(blk
, blk
+ MFU_BLOCK_SIZE
, MFU_BLOCK_SIZE
) == 0) &&
3055 (memcmp(blk
, blk
+ (MFU_BLOCK_SIZE
* 2), MFU_BLOCK_SIZE
) == 0)
3057 // we're in a user block that isn't the first user block nor last two user blocks,
3058 // and the current block data is the same as the previous and next two block
3059 in_repeated_block
= true;
3060 PrintAndLogEx(INFO
, " ......");
3061 } else if (in_repeated_block
&&
3062 (memcmp(blk
, blk
+ MFU_BLOCK_SIZE
, MFU_BLOCK_SIZE
) || i
== pages
)
3064 // in a repeating block, but the next block doesn't match anymore, or we're at the end block
3065 in_repeated_block
= false;
3069 if (in_repeated_block
== false) {
3070 PrintAndLogEx(INFO
, "%3d/0x%02X | %s| %s | %s"
3073 , sprint_hex(data
+ i
* 4, 4)
3074 , (lckbit
) ? _RED_("1") : "0"
3075 , sprint_ascii(data
+ i
* 4, 4)
3079 PrintAndLogEx(INFO
, "---------------------------------");
3083 // Mifare Ultralight / Ultralight-C / Ultralight-EV1
3084 // Read and Dump Card Contents, using auto detection of tag size.
3085 static int CmdHF14AMfUDump(const char *Cmd
) {
3087 CLIParserContext
*ctx
;
3088 CLIParserInit(&ctx
, "hf mfu dump",
3089 "Dump MIFARE Ultralight/NTAG tag to files (bin/json)\n"
3090 "It autodetects card type."
3092 "Ultralight, Ultralight-C, Ultralight EV1\n"
3093 "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216\n",
3094 "hf mfu dump -f myfile\n"
3095 "hf mfu dump -k AABBCCDD -> dump whole tag using pwd AABBCCDD\n"
3096 "hf mfu dump -p 10 -> start at page 10 and dump rest of blocks\n"
3097 "hf mfu dump -p 10 -q 2 -> start at page 10 and dump two blocks\n"
3098 "hf mfu dump --key 00112233445566778899AABBCCDDEEFF"
3101 void *argtable
[] = {
3103 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
3104 arg_str0("k", "key", "<hex>", "Key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
3105 arg_lit0("l", NULL
, "Swap entered key's endianness"),
3106 arg_int0("p", "page", "<dec>", "Manually set start page number to start from"),
3107 arg_int0("q", "qty", "<dec>", "Manually set number of pages to dump"),
3108 arg_lit0(NULL
, "ns", "no save to file"),
3109 arg_lit0("z", "dense", "dense dump output style"),
3112 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3115 char filename
[FILE_PATH_SIZE
] = {0};
3116 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3119 uint8_t authenticationkey
[16] = {0x00};
3120 uint8_t *authKeyPtr
= authenticationkey
;
3121 CLIGetHexWithReturn(ctx
, 2, authenticationkey
, &ak_len
);
3122 bool swap_endian
= arg_get_lit(ctx
, 3);
3123 int start_page
= arg_get_int_def(ctx
, 4, 0);
3124 int pages
= arg_get_int_def(ctx
, 5, 16);
3125 bool nosave
= arg_get_lit(ctx
, 6);
3126 bool dense_output
= (g_session
.dense_output
|| arg_get_lit(ctx
, 7));
3129 bool has_auth_key
= false;
3130 bool has_pwd
= false;
3132 has_auth_key
= true;
3133 } else if (ak_len
== 4) {
3135 } else if (ak_len
!= 0) {
3136 PrintAndLogEx(WARNING
, "ERROR: Key is incorrect length\n");
3140 bool manual_pages
= false;
3141 if (start_page
> 0) {
3142 manual_pages
= true;
3146 manual_pages
= true;
3149 uint8_t card_mem_size
= 0;
3154 authKeyPtr
= SwapEndian64(authenticationkey
, ak_len
, 8);
3158 authKeyPtr
= SwapEndian64(authenticationkey
, ak_len
, 4);
3162 uint64_t tagtype
= GetHF14AMfU_Type();
3163 if (tagtype
== MFU_TT_UL_ERROR
) {
3167 //get number of pages to read
3168 if (manual_pages
== false) {
3169 for (uint8_t idx
= 1; idx
< ARRAYLEN(UL_TYPES_ARRAY
); idx
++) {
3170 if ((tagtype
& UL_TYPES_ARRAY
[idx
]) == UL_TYPES_ARRAY
[idx
]) {
3171 //add one as maxblks starts at 0
3172 card_mem_size
= pages
= UL_MEMORY_ARRAY
[idx
] + 1;
3178 ul_print_type(tagtype
, 0);
3179 PrintAndLogEx(SUCCESS
, "Reading tag memory...");
3180 uint8_t keytype
= 0;
3181 if (has_auth_key
|| has_pwd
) {
3182 if ((tagtype
& MFU_TT_UL_C
) == MFU_TT_UL_C
)
3183 keytype
= 1; // UL_C auth
3185 keytype
= 2; // UL_EV1/NTAG auth
3188 uint8_t dbg_curr
= DBG_NONE
;
3189 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
3193 if (setDeviceDebugLevel(DBG_NONE
, false) != PM3_SUCCESS
) {
3197 clearCommandBuffer();
3198 SendCommandMIX(CMD_HF_MIFAREU_READCARD
, start_page
, pages
, keytype
, authKeyPtr
, ak_len
);
3199 PacketResponseNG resp
;
3200 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
3201 PrintAndLogEx(WARNING
, "command execution time out");
3202 return PM3_ETIMEOUT
;
3205 if (resp
.oldarg
[0] != 1) {
3206 PrintAndLogEx(WARNING
, "Failed dumping card");
3210 setDeviceDebugLevel(dbg_curr
, false);
3213 uint8_t data
[1024] = {0x00};
3214 memset(data
, 0x00, sizeof(data
));
3216 uint32_t startindex
= resp
.oldarg
[2];
3217 uint32_t buffer_size
= resp
.oldarg
[1];
3218 if (buffer_size
> sizeof(data
)) {
3219 PrintAndLogEx(FAILED
, "Data exceeded buffer size!");
3220 buffer_size
= sizeof(data
);
3223 if (GetFromDevice(BIG_BUF
, data
, buffer_size
, startindex
, NULL
, 0, NULL
, 2500, false) == false) {
3224 PrintAndLogEx(WARNING
, "command execution time out");
3225 return PM3_ETIMEOUT
;
3228 bool is_partial
= (pages
!= buffer_size
/ MFU_BLOCK_SIZE
);
3230 pages
= buffer_size
/ MFU_BLOCK_SIZE
;
3234 if ((tagtype
& MFU_TT_UL_C
) == MFU_TT_UL_C
) {
3235 if (card_mem_size
!= (pages
+ 4)) {
3236 PrintAndLogEx(INFO
, "Partial dump, got " _RED_("%d") " bytes - card mem size is %u bytes", pages
* MFU_BLOCK_SIZE
, card_mem_size
* MFU_BLOCK_SIZE
);
3237 PrintAndLogEx(HINT
, "Try using a key");
3240 PrintAndLogEx(HINT
, "Try using a pwd");
3244 iso14a_card_select_t card
;
3245 mfu_dump_t dump_file_data
;
3246 memset(&dump_file_data
, 0, sizeof(dump_file_data
));
3247 uint8_t get_version
[] = {0, 0, 0, 0, 0, 0, 0, 0};
3248 uint8_t get_counter_tearing
[][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
3249 uint8_t get_signature
[32];
3250 memset(get_signature
, 0, sizeof(get_signature
));
3252 // not ul_c and not std ul then attempt to collect info like
3253 // VERSION, SIGNATURE, COUNTERS, TEARING, PACK,
3254 if (!(tagtype
& MFU_TT_UL_C
|| tagtype
& MFU_TT_UL
|| tagtype
& MFU_TT_MY_D_MOVE
|| tagtype
& MFU_TT_MY_D_MOVE_LEAN
)) {
3255 // attempt to read pack
3256 bool has_key
= (has_auth_key
|| has_pwd
);
3257 uint8_t get_pack
[] = {0, 0};
3258 if (ul_auth_select(&card
, tagtype
, has_key
, authKeyPtr
, get_pack
, sizeof(get_pack
)) != PM3_SUCCESS
) {
3265 // only add pack if not partial read, and complete pages read.
3266 if (!is_partial
&& pages
== card_mem_size
) {
3268 // add pack to block read
3269 memcpy(data
+ (pages
* 4) - 4, get_pack
, sizeof(get_pack
));
3273 uint8_t dummy_pack
[] = {0, 0};
3274 ul_auth_select(&card
, tagtype
, has_auth_key
, authKeyPtr
, dummy_pack
, sizeof(dummy_pack
));
3279 ulev1_getVersion(get_version
, sizeof(get_version
));
3281 // ULEV-1 has 3 counters
3284 // NTAG has 1 counter, at 0x02
3285 if ((tagtype
& (MFU_TT_NTAG_213
| MFU_TT_NTAG_213_F
| MFU_TT_NTAG_213_C
| MFU_TT_NTAG_213_TT
| MFU_TT_NTAG_215
| MFU_TT_NTAG_216
))) {
3289 // NTAG can have nfc counter pwd protection enabled
3290 for (; n
< 3; n
++) {
3293 uint8_t dummy_pack
[] = {0, 0};
3294 ul_auth_select(&card
, tagtype
, has_auth_key
, authKeyPtr
, dummy_pack
, sizeof(dummy_pack
));
3298 ulev1_readCounter(n
, &get_counter_tearing
[n
][0], 3);
3301 uint8_t dummy_pack
[] = {0, 0};
3302 ul_auth_select(&card
, tagtype
, has_auth_key
, authKeyPtr
, dummy_pack
, sizeof(dummy_pack
));
3306 ulev1_readTearing(n
, &get_counter_tearing
[n
][3], 1);
3312 uint8_t dummy_pack
[] = {0, 0};
3313 ul_auth_select(&card
, tagtype
, has_auth_key
, authKeyPtr
, dummy_pack
, sizeof(dummy_pack
));
3318 ulev1_readSignature(get_signature
, sizeof(get_signature
));
3323 // format and add keys to block dump output
3324 // only add keys if not partial read, and complete pages read
3326 // UL-C add a working known key
3327 if (has_auth_key
&& (tagtype
& MFU_TT_UL_C
) == MFU_TT_UL_C
) { // add 4 pages of key
3329 // if we didn't swapendian before - do it now for the sprint_hex call
3330 // NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
3331 // need to swap to keep it the same
3332 if (swap_endian
== false) {
3333 authKeyPtr
= SwapEndian64(authenticationkey
, ak_len
, 8);
3335 authKeyPtr
= authenticationkey
;
3338 memcpy(data
+ pages
* MFU_BLOCK_SIZE
, authKeyPtr
, ak_len
);
3339 pages
+= ak_len
/ MFU_BLOCK_SIZE
;
3342 if (is_partial
&& pages
== card_mem_size
) {
3347 if (!is_partial
&& pages
== card_mem_size
&& has_pwd
) {
3348 // if we didn't swapendian before - do it now for the sprint_hex call
3349 // NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
3350 // need to swap to keep it the same
3351 if (swap_endian
== false) {
3352 authKeyPtr
= SwapEndian64(authenticationkey
, ak_len
, 4);
3354 authKeyPtr
= authenticationkey
;
3357 memcpy(data
+ (pages
* MFU_BLOCK_SIZE
) - 8, authenticationkey
, ak_len
);
3360 //add *special* blocks to dump
3361 // pack and pwd saved into last pages of dump, if was not partial read
3362 dump_file_data
.pages
= pages
- 1;
3363 memcpy(dump_file_data
.version
, get_version
, sizeof(dump_file_data
.version
));
3364 memcpy(dump_file_data
.signature
, get_signature
, sizeof(dump_file_data
.signature
));
3365 memcpy(dump_file_data
.counter_tearing
, get_counter_tearing
, sizeof(dump_file_data
.counter_tearing
));
3366 memcpy(dump_file_data
.data
, data
, pages
* MFU_BLOCK_SIZE
);
3368 mfu_print_dump(&dump_file_data
, pages
, start_page
, dense_output
);
3371 PrintAndLogEx(INFO
, "Called with no save option");
3372 PrintAndLogEx(NORMAL
, "");
3376 // user supplied filename?
3378 PrintAndLogEx(INFO
, "Using UID as filename");
3379 uint8_t uid
[7] = {0};
3380 memcpy(uid
, (uint8_t *)&dump_file_data
.data
, 3);
3381 memcpy(uid
+ 3, (uint8_t *)&dump_file_data
.data
+ 4, 4);
3382 strcat(filename
, "hf-mfu-");
3383 FillFileNameByUID(filename
, uid
, "-dump", sizeof(uid
));
3386 uint16_t datalen
= MFU_DUMP_PREFIX_LENGTH
+ (pages
* MFU_BLOCK_SIZE
);
3387 pm3_save_dump(filename
, (uint8_t *)&dump_file_data
, datalen
, jsfMfuMemory
);
3390 PrintAndLogEx(WARNING
, "Partial dump created. (%d of %d blocks)", pages
, card_mem_size
);
3395 static void wait4response(uint8_t b
) {
3396 PacketResponseNG resp
;
3397 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
3398 uint8_t isOK
= resp
.oldarg
[0] & 0xff;
3400 PrintAndLogEx(WARNING
, "failed to write block %d", b
);
3403 PrintAndLogEx(WARNING
, "command execution time out");
3408 //Configure tamper feature of NTAG 213TT
3410 int CmdHF14MfUTamper(const char *Cmd
) {
3411 CLIParserContext
*ctx
;
3412 CLIParserInit(&ctx
, "hf mfu tamper",
3413 "Set the configuration of the NTAG 213TT tamper feature\n"
3416 "hf mfu tamper -e -> enable tamper feature\n"
3417 "hf mfu tamper -d -> disable tamper feature\n"
3418 "hf mfu tamper -m 0A0A0A0A -> set the tamper message to 0A0A0A0A\n"
3419 "hf mfu tamper --lockmessage -> permanently lock the tamper message and mask it from memory\n"
3422 void *argtable
[] = {
3424 arg_lit0("e", "enable", "Enable the tamper feature"),
3425 arg_lit0("d", "disable", "Disable the tamper feature"),
3426 arg_str0("m", "message", "<hex>", "Set the tamper message (4 bytes)"),
3427 arg_lit0(NULL
, "lockmessage", "Permanently lock the tamper message and mask it from memory (does not lock tamper feature itself)"),
3430 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3432 int tt_cfg_page
= 41;
3433 int tt_msg_page
= 45;
3435 uint8_t msg_data
[4] = {0x00};
3436 CLIGetHexWithReturn(ctx
, 3, msg_data
, &msg_len
);
3437 bool use_msg
= (msg_len
> 0);
3439 if (use_msg
&& msg_len
!= 4) {
3440 PrintAndLogEx(WARNING
, "The tamper message must be 4 hex bytes if provided");
3446 bool lock_msg
= arg_get_lit(ctx
, 4);
3447 bool enable
= arg_get_lit(ctx
, 1);
3448 bool disable
= arg_get_lit(ctx
, 2);
3451 uint64_t tagtype
= GetHF14AMfU_Type();
3452 if (tagtype
== MFU_TT_UL_ERROR
) {
3453 PrintAndLogEx(WARNING
, "Tag type not detected");
3457 if (tagtype
!= MFU_TT_NTAG_213_TT
) {
3458 PrintAndLogEx(WARNING
, "Tag type not NTAG 213TT");
3464 iso14a_card_select_t card
;
3466 if (enable
&& disable
) {
3467 PrintAndLogEx(WARNING
, "You can only select one of the options enable/disable tamper feature");
3473 if (ul_select(&card
) == false) {
3475 return MFU_TT_UL_ERROR
;
3477 PrintAndLogEx(INFO
, "Trying to write tamper message");
3478 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, tt_msg_page
, 0, 0, msg_data
, 4);
3480 PacketResponseNG resp
;
3482 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
3483 uint8_t isOK
= resp
.oldarg
[0] & 0xff;
3485 PrintAndLogEx(WARNING
, "Failed to write tamper message");
3487 PrintAndLogEx(SUCCESS
, "Tamper message written successfully");
3489 PrintAndLogEx(WARNING
, "command execution time out");
3493 if (enable
|| disable
|| lock_msg
) {
3495 if (ul_select(&card
) == false) {
3496 PrintAndLogEx(ERR
, "Unable to select tag");
3498 return MFU_TT_UL_ERROR
;
3501 uint8_t cfg_page
[4] = {0x00};
3502 uint8_t cmd
[] = {ISO14443A_CMD_READBLOCK
, tt_cfg_page
};
3503 int status
= ul_send_cmd_raw(cmd
, sizeof(cmd
), cfg_page
, 4);
3507 PrintAndLogEx(WARNING
, "Problem reading current config from tag");
3513 cfg_page
[1] = cfg_page
[1] | 0x02;
3514 PrintAndLogEx(INFO
, "Enabling tamper feature");
3517 cfg_page
[1] = cfg_page
[1] & 0xFD;
3518 PrintAndLogEx(INFO
, "Disabling tamper feature");
3521 cfg_page
[1] = cfg_page
[1] | 0x04;
3522 PrintAndLogEx(INFO
, "Locking tamper message");
3525 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, tt_cfg_page
, 0, 0, cfg_page
, 4);
3526 PacketResponseNG resp
;
3528 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
3529 uint8_t isOK
= resp
.oldarg
[0] & 0xff;
3531 PrintAndLogEx(WARNING
, "Failed to write tamper configuration");
3533 PrintAndLogEx(SUCCESS
, "Tamper configuration written successfully");
3535 PrintAndLogEx(WARNING
, "command execution time out");
3544 // Restore dump file onto tag
3546 static int CmdHF14AMfURestore(const char *Cmd
) {
3547 CLIParserContext
*ctx
;
3548 CLIParserInit(&ctx
, "hf mfu restore",
3549 "Restore MIFARE Ultralight/NTAG dump file (bin/eml/json) to tag.\n",
3550 "hf mfu restore -f myfile -s -> special write\n"
3551 "hf mfu restore -f myfile -k AABBCCDD -s -> special write, use key\n"
3552 "hf mfu restore -f myfile -k AABBCCDD -ser -> special write, use key, write dump pwd, ..."
3555 void *argtable
[] = {
3557 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
3558 arg_str0("k", "key", "<hex>", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
3559 arg_lit0("l", NULL
, "swap entered key's endianness"),
3560 arg_lit0("s", NULL
, "enable special write UID -MAGIC TAG ONLY-"),
3561 arg_lit0("e", NULL
, "enable special write version/signature -MAGIC NTAG 21* ONLY-"),
3562 arg_lit0("r", NULL
, "use password found in dumpfile to configure tag. Requires " _YELLOW_("'-e'") " parameter to work"),
3563 arg_lit0("v", "verbose", "verbose output"),
3564 arg_lit0("z", "dense", "dense dump output style"),
3567 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3570 char filename
[FILE_PATH_SIZE
] = {0};
3571 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3574 uint8_t authkey
[16] = {0x00};
3575 uint8_t *p_authkey
= authkey
;
3576 CLIGetHexWithReturn(ctx
, 2, authkey
, &ak_len
);
3578 bool swap_endian
= arg_get_lit(ctx
, 3);
3579 bool write_special
= arg_get_lit(ctx
, 4);
3580 bool write_extra
= arg_get_lit(ctx
, 5);
3581 bool read_key
= arg_get_lit(ctx
, 6);
3582 bool verbose
= arg_get_lit(ctx
, 7);
3583 bool dense_output
= (g_session
.dense_output
|| arg_get_lit(ctx
, 8));
3586 bool has_key
= false;
3588 if (ak_len
!= 4 && ak_len
!= 16) {
3589 PrintAndLogEx(ERR
, "Wrong key length. expected 4 or 16, got %d", ak_len
);
3597 char *fptr
= mfu_generate_filename("hf-mfu-", "-dump.bin");
3599 strncpy(filename
, fptr
, sizeof(filename
) - 1);
3601 snprintf(filename
, sizeof(filename
), "dumpdata.bin");
3607 uint8_t *dump
= NULL
;
3608 size_t bytes_read
= 0;
3609 int res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, (MFU_MAX_BYTES
+ MFU_DUMP_PREFIX_LENGTH
));
3610 if (res
!= PM3_SUCCESS
) {
3614 if (bytes_read
< MFU_DUMP_PREFIX_LENGTH
) {
3615 PrintAndLogEx(ERR
, "Error, dump file is too small");
3620 res
= convert_mfu_dump_format(&dump
, &bytes_read
, verbose
);
3621 if (res
!= PM3_SUCCESS
) {
3622 PrintAndLogEx(FAILED
, "Failed convert on load to new Ultralight/NTAG format");
3627 mfu_dump_t
*mem
= (mfu_dump_t
*)dump
;
3628 uint8_t pages
= (bytes_read
- MFU_DUMP_PREFIX_LENGTH
) / MFU_BLOCK_SIZE
;
3630 if (pages
- 1 != mem
->pages
) {
3631 PrintAndLogEx(ERR
, "Error, invalid dump, wrong page count");
3632 PrintAndLogEx(INFO
, " %u vs mempg %u", pages
- 1, mem
->pages
);
3637 PrintAndLogEx(INFO
, "Restoring " _YELLOW_("%s")" to card", filename
);
3639 mfu_print_dump(mem
, pages
, 0, dense_output
);
3642 if (swap_endian
&& has_key
) {
3644 p_authkey
= SwapEndian64(authkey
, ak_len
, 8);
3646 p_authkey
= SwapEndian64(authkey
, ak_len
, 4);
3649 uint8_t data
[20] = {0};
3650 uint8_t keytype
= 0;
3651 // set key - only once
3653 keytype
= (ak_len
== 16) ? 1 : 2;
3654 memcpy(data
+ 4, p_authkey
, ak_len
);
3657 // write version, signature, pack
3658 // only magic NTAG cards
3661 #define MFU_NTAG_SPECIAL_PWD 0xF0
3662 #define MFU_NTAG_SPECIAL_PACK 0xF1
3663 #define MFU_NTAG_SPECIAL_VERSION 0xFA
3664 #define MFU_NTAG_SPECIAL_SIGNATURE 0xF2
3666 if (has_key
|| read_key
) {
3668 memcpy(data
, p_authkey
, 4);
3670 // try reading key from dump and use.
3671 memcpy(data
, mem
->data
+ (bytes_read
- MFU_DUMP_PREFIX_LENGTH
- 8), 4);
3674 PrintAndLogEx(INFO
, "special PWD block written 0x%X - %s", MFU_NTAG_SPECIAL_PWD
, sprint_hex(data
, 4));
3675 clearCommandBuffer();
3676 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, MFU_NTAG_SPECIAL_PWD
, keytype
, 0, data
, sizeof(data
));
3678 wait4response(MFU_NTAG_SPECIAL_PWD
);
3682 memcpy(authkey
, data
, 4);
3683 memcpy(data
+ 4, authkey
, 4);
3687 memcpy(data
, mem
->data
+ (bytes_read
- MFU_DUMP_PREFIX_LENGTH
- 4), 2);
3690 PrintAndLogEx(INFO
, "special PACK block written 0x%X - %s", MFU_NTAG_SPECIAL_PACK
, sprint_hex(data
, 4));
3691 clearCommandBuffer();
3692 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, MFU_NTAG_SPECIAL_PACK
, keytype
, 0, data
, sizeof(data
));
3693 wait4response(MFU_NTAG_SPECIAL_PACK
);
3696 for (uint8_t s
= MFU_NTAG_SPECIAL_SIGNATURE
, i
= 0; s
< MFU_NTAG_SPECIAL_SIGNATURE
+ 8; s
++, i
+= 4) {
3697 memcpy(data
, mem
->signature
+ i
, 4);
3698 PrintAndLogEx(INFO
, "special SIG block written 0x%X - %s", s
, sprint_hex(data
, 4));
3699 clearCommandBuffer();
3700 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, s
, keytype
, 0, data
, sizeof(data
));
3705 for (uint8_t s
= MFU_NTAG_SPECIAL_VERSION
, i
= 0; s
< MFU_NTAG_SPECIAL_VERSION
+ 2; s
++, i
+= 4) {
3706 memcpy(data
, mem
->version
+ i
, 4);
3707 PrintAndLogEx(INFO
, "special VERSION block written 0x%X - %s", s
, sprint_hex(data
, 4));
3708 clearCommandBuffer();
3709 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, s
, keytype
, 0, data
, sizeof(data
));
3714 PrintAndLogEx(INFO
, "Restoring data blocks.");
3715 PrintAndLogEx(INFO
, "." NOLF
);
3716 // write all other data
3717 // Skip block 0,1,2,3 (only magic tags can write to them)
3718 // Skip last 5 blocks usually is configuration
3719 for (uint8_t b
= 4; b
< pages
- 5; b
++) {
3722 memcpy(data
, mem
->data
+ (b
* 4), 4);
3723 clearCommandBuffer();
3724 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, b
, keytype
, 0, data
, sizeof(data
));
3726 PrintAndLogEx(NORMAL
, "." NOLF
);
3729 PrintAndLogEx(NORMAL
, "");
3731 // write special data last
3732 if (write_special
) {
3734 PrintAndLogEx(INFO
, "Restoring configuration blocks");
3736 PrintAndLogEx(INFO
, "Authentication with keytype[%x] %s\n", (uint8_t)(keytype
& 0xff), sprint_hex(p_authkey
, 4));
3739 // otp, uid, lock, dynlockbits, cfg0, cfg1, pwd, pack
3740 uint8_t blocks
[] = {3, 0, 1, 2, pages
- 5, pages
- 4, pages
- 3, pages
- 2, pages
- 1};
3742 // otp, uid, lock, dynlockbits, cfg0, cfg1
3743 uint8_t blocks
[] = {3, 0, 1, 2, pages
- 5, pages
- 4, pages
- 3};
3745 for (uint8_t i
= 0; i
< ARRAYLEN(blocks
); i
++) {
3746 uint8_t b
= blocks
[i
];
3747 memcpy(data
, mem
->data
+ (b
* 4), 4);
3748 clearCommandBuffer();
3749 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, b
, keytype
, 0, data
, sizeof(data
));
3751 PrintAndLogEx(INFO
, "special block written " _YELLOW_("%u") " - %s", b
, sprint_hex(data
, 4));
3757 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mfu dump --ns") "` to verify");
3758 PrintAndLogEx(INFO
, "Done!");
3762 // Load emulator with dump file
3764 static int CmdHF14AMfUeLoad(const char *Cmd
) {
3766 CLIParserContext
*ctx
;
3767 CLIParserInit(&ctx
, "hf mfu eload",
3768 "Load emulator memory with data from (bin/eml/json) dump file\n",
3769 "hf mfu eload -f hf-mfu-04010203040506.bin\n"
3770 "hf mfu eload -f hf-mfu-04010203040506.bin -q 57 -> load 57 blocks from myfile"
3773 void *argtable
[] = {
3775 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
3776 arg_int0("q", "qty", "<dec>", "Number of blocks to load from eml file"),
3777 arg_lit0("v", "verbose", "verbose output"),
3780 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3783 size_t nc_len
= strlen(Cmd
) + 6;
3784 char *nc
= calloc(nc_len
, 1);
3786 return CmdHF14AMfELoad(Cmd
);
3789 snprintf(nc
, nc_len
, "%s --ul", Cmd
);
3790 int res
= CmdHF14AMfELoad(nc
);
3793 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mfu sim -t 7`") " to simulate an Amiibo.");
3794 PrintAndLogEx(INFO
, "Done!");
3801 static int CmdHF14AMfUSim(const char *Cmd
) {
3802 CLIParserContext
*ctx
;
3803 CLIParserInit(&ctx
, "hf mfu sim",
3804 "Simulate MIFARE Ultralight family type based upon\n"
3805 "ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"
3806 "from emulator memory. See `hf mfu eload` first. \n"
3807 "The UID from emulator memory will be used if not specified.\n"
3808 "See `hf 14a sim -h` to see available types. You want 2 or 7 usually.",
3809 "hf mfu sim -t 2 --uid 11223344556677 -> MIFARE Ultralight\n"
3810 "hf mfu sim -t 7 --uid 11223344556677 -n 5 -> MFU EV1 / NTAG 215 Amiibo\n"
3811 "hf mfu sim -t 7 -> MFU EV1 / NTAG 215 Amiibo"
3814 void *argtable
[] = {
3816 arg_int1("t", "type", "<1..12> ", "Simulation type to use"),
3817 arg_str0("u", "uid", "<hex>", "<4|7|10> hex bytes UID"),
3818 arg_int0("n", "num", "<dec>", "Exit simulation after <numreads> blocks. 0 = infinite"),
3819 arg_lit0("v", "verbose", "Verbose output"),
3822 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3824 return CmdHF14ASim(Cmd
);
3827 //-------------------------------------------------------------------------------
3828 // Ultralight C Methods
3829 //-------------------------------------------------------------------------------
3831 // Ultralight C Authentication
3833 static int CmdHF14AMfUCAuth(const char *Cmd
) {
3834 CLIParserContext
*ctx
;
3835 CLIParserInit(&ctx
, "hf mfu cauth",
3836 "Tests 3DES password on Mifare Ultralight-C tag.\n"
3837 "If password is not specified, a set of known defaults will be tested.",
3839 "hf mfu cauth --key 000102030405060708090a0b0c0d0e0f"
3842 void *argtable
[] = {
3844 arg_str0(NULL
, "key", "<hex>", "Authentication key (UL-C 16 hex bytes)"),
3845 arg_lit0("l", NULL
, "Swap entered key's endianness"),
3846 arg_lit0("k", NULL
, "Keep field on (only if a password is provided)"),
3849 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3852 uint8_t authenticationkey
[16] = {0x00};
3853 uint8_t *authKeyPtr
= authenticationkey
;
3854 CLIGetHexWithReturn(ctx
, 1, authenticationkey
, &ak_len
);
3855 bool swap_endian
= arg_get_lit(ctx
, 2);
3856 bool keep_field_on
= arg_get_lit(ctx
, 3);
3859 if (ak_len
!= 16 && ak_len
!= 0) {
3860 PrintAndLogEx(WARNING
, "ERROR: Key is incorrect length");
3865 if (swap_endian
&& ak_len
) {
3866 authKeyPtr
= SwapEndian64(authenticationkey
, 16, 8);
3871 // If no hex key is specified, try default keys
3873 isok
= try_default_3des_keys(false, &authKeyPtr
);
3875 // try user-supplied
3876 isok
= ulc_authentication(authKeyPtr
, !keep_field_on
);
3879 if (isok
== PM3_SUCCESS
) {
3880 PrintAndLogEx(SUCCESS
, "Authentication 3DES key... " _GREEN_("%s") " ( " _GREEN_("ok")" )", sprint_hex_inrow(authKeyPtr
, 16));
3882 PrintAndLogEx(WARNING
, "Authentication ( " _RED_("fail") " )");
3888 A test function to validate that the polarssl-function works the same
3889 was as the openssl-implementation.
3890 Commented out, since it requires openssl
3892 static int CmdTestDES(const char * cmd)
3894 uint8_t key[16] = {0x00};
3896 memcpy(key,key3_3des_data,16);
3897 DES_cblock RndA, RndB;
3899 PrintAndLogEx(NORMAL, "----------OpenSSL DES implementation----------");
3901 uint8_t e_RndB[8] = {0x00};
3902 unsigned char RndARndB[16] = {0x00};
3904 DES_cblock iv = { 0 };
3905 DES_key_schedule ks1,ks2;
3906 DES_cblock key1,key2;
3908 memcpy(key,key3_3des_data,16);
3910 memcpy(key2,key+8,8);
3913 DES_set_key((DES_cblock *)key1,&ks1);
3914 DES_set_key((DES_cblock *)key2,&ks2);
3916 DES_random_key(&RndA);
3917 PrintAndLogEx(NORMAL, " RndA:%s",sprint_hex(RndA, 8));
3918 PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(e_RndB, 8));
3919 //void DES_ede2_cbc_encrypt(const unsigned char *input,
3920 // unsigned char *output, long length, DES_key_schedule *ks1,
3921 // DES_key_schedule *ks2, DES_cblock *ivec, int enc);
3922 DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0);
3924 PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(RndB, 8));
3926 memcpy(RndARndB,RndA,8);
3927 memcpy(RndARndB+8,RndB,8);
3928 PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(RndARndB, 16));
3929 DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1);
3930 PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(RndARndB, 16));
3933 PrintAndLogEx(NORMAL, "----------PolarSSL implementation----------");
3935 uint8_t random_a[8] = { 0 };
3936 uint8_t enc_random_a[8] = { 0 };
3937 uint8_t random_b[8] = { 0 };
3938 uint8_t enc_random_b[8] = { 0 };
3939 uint8_t random_a_and_b[16] = { 0 };
3940 des3_context ctx = { 0 };
3942 memcpy(random_a, RndA,8);
3944 uint8_t output[8] = { 0 };
3945 uint8_t iv[8] = { 0 };
3947 PrintAndLogEx(NORMAL, " RndA :%s",sprint_hex(random_a, 8));
3948 PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(enc_random_b, 8));
3950 des3_set2key_dec(&ctx, key);
3952 des3_crypt_cbc(&ctx // des3_context *ctx
3953 , DES_DECRYPT // int mode
3954 , sizeof(random_b) // size_t length
3955 , iv // unsigned char iv[8]
3956 , enc_random_b // const unsigned char *input
3957 , random_b // unsigned char *output
3960 PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(random_b, 8));
3963 memcpy(random_a_and_b ,random_a,8);
3964 memcpy(random_a_and_b+8,random_b,8);
3966 PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(random_a_and_b, 16));
3968 des3_set2key_enc(&ctx, key);
3970 des3_crypt_cbc(&ctx // des3_context *ctx
3971 , DES_ENCRYPT // int mode
3972 , sizeof(random_a_and_b) // size_t length
3973 , enc_random_b // unsigned char iv[8]
3974 , random_a_and_b // const unsigned char *input
3975 , random_a_and_b // unsigned char *output
3978 PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(random_a_and_b, 16));
3985 // Mifare Ultralight C - Set password
3987 static int CmdHF14AMfUCSetPwd(const char *Cmd
) {
3988 CLIParserContext
*ctx
;
3989 CLIParserInit(&ctx
, "hf mfu setpwd",
3990 "Set the 3DES key on MIFARE Ultralight-C tag. ",
3991 "hf mfu setpwd --key 000102030405060708090a0b0c0d0e0f"
3994 void *argtable
[] = {
3996 arg_str0("k", "key", "<hex>", "New key (16 hex bytes)"),
3999 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4002 uint8_t key
[16] = {0x00};
4003 CLIGetHexWithReturn(ctx
, 1, key
, &k_len
);
4007 PrintAndLogEx(WARNING
, "Key must be 16 hex bytes");
4011 clearCommandBuffer();
4012 SendCommandMIX(CMD_HF_MIFAREUC_SETPWD
, 0, 0, 0, key
, sizeof(key
));
4014 PacketResponseNG resp
;
4015 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
4016 if ((resp
.oldarg
[0] & 0xff) == 1) {
4017 PrintAndLogEx(INFO
, "Ultralight-C new key... " _GREEN_("%s"), sprint_hex_inrow(key
, sizeof(key
)));
4019 PrintAndLogEx(WARNING
, "Failed writing at block %u", (uint8_t)(resp
.oldarg
[1] & 0xFF));
4023 PrintAndLogEx(WARNING
, "command execution time out");
4024 return PM3_ETIMEOUT
;
4030 // Magic UL / UL-C tags - Set UID
4032 static int CmdHF14AMfUCSetUid(const char *Cmd
) {
4034 CLIParserContext
*ctx
;
4035 CLIParserInit(&ctx
, "hf mfu setuid",
4036 "Set UID on MIFARE Ultralight tag.\n"
4037 "This only works for `magic Ultralight` tags.",
4038 "hf mfu setuid --uid 11223344556677"
4041 void *argtable
[] = {
4043 arg_str0("u", "uid", "<hex>", "New UID (7 hex bytes)"),
4046 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4049 uint8_t uid
[7] = {0x00};
4050 CLIGetHexWithReturn(ctx
, 1, uid
, &u_len
);
4054 PrintAndLogEx(WARNING
, "UID must be 7 hex bytes");
4058 PrintAndLogEx(INFO
, "Please ignore possible transient BCC warnings");
4061 PacketResponseNG resp
;
4062 clearCommandBuffer();
4063 SendCommandMIX(CMD_HF_MIFAREU_READBL
, 2, 0, 0, NULL
, 0);
4064 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
4065 PrintAndLogEx(WARNING
, "command execution time out");
4066 return PM3_ETIMEOUT
;
4070 uint8_t oldblock2
[4] = {0x00};
4071 memcpy(oldblock2
, resp
.data
.asBytes
, 4);
4073 // Enforce bad BCC handling temporarily as BCC will be wrong between
4074 // block 1 write and block2 write
4075 hf14a_config config
;
4076 SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG
, NULL
, 0);
4077 if (!WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG
, &resp
, 2000)) {
4078 PrintAndLogEx(WARNING
, "command execution time out");
4079 return PM3_ETIMEOUT
;
4081 memcpy(&config
, resp
.data
.asBytes
, sizeof(hf14a_config
));
4082 int8_t oldconfig_bcc
= config
.forcebcc
;
4083 if (oldconfig_bcc
!= 2) {
4084 config
.forcebcc
= 2;
4085 SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG
, (uint8_t *)&config
, sizeof(hf14a_config
));
4093 data
[3] = 0x88 ^ uid
[0] ^ uid
[1] ^ uid
[2];
4094 clearCommandBuffer();
4095 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, 0, 0, 0, data
, sizeof(data
));
4096 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
4097 PrintAndLogEx(WARNING
, "command execution time out");
4098 return PM3_ETIMEOUT
;
4106 clearCommandBuffer();
4107 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, 1, 0, 0, data
, sizeof(data
));
4108 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
4109 PrintAndLogEx(WARNING
, "command execution time out");
4110 return PM3_ETIMEOUT
;
4114 data
[0] = uid
[3] ^ uid
[4] ^ uid
[5] ^ uid
[6];
4115 data
[1] = oldblock2
[1];
4116 data
[2] = oldblock2
[2];
4117 data
[3] = oldblock2
[3];
4118 clearCommandBuffer();
4119 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, 2, 0, 0, data
, sizeof(data
));
4120 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
4121 PrintAndLogEx(WARNING
, "command execution time out");
4122 return PM3_ETIMEOUT
;
4125 // restore BCC config
4126 if (oldconfig_bcc
!= 2) {
4127 config
.forcebcc
= oldconfig_bcc
;
4128 SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG
, (uint8_t *)&config
, sizeof(hf14a_config
));
4133 static int CmdHF14AMfUKeyGen(const char *Cmd
) {
4134 CLIParserContext
*ctx
;
4135 CLIParserInit(&ctx
, "hf mfu keygen",
4136 "Calculate MFC keys based ",
4137 "hf mfu keygen -r\n"
4138 "hf mfu keygen --uid 11223344556677"
4141 void *argtable
[] = {
4143 arg_str0("u", "uid", "<hex>", "<4|7> hex byte UID"),
4144 arg_lit0("r", NULL
, "Read UID from tag"),
4145 arg_u64_0("b", "blk", "<dec>", "Block number"),
4148 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4152 CLIGetHexWithReturn(ctx
, 1, uid
, &ulen
);
4153 bool read_tag
= arg_get_lit(ctx
, 2);
4154 uint8_t block
= arg_get_u64_def(ctx
, 3, 1) & 0xFF;
4158 // read uid from tag
4159 clearCommandBuffer();
4160 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_RATS
, 0, 0, NULL
, 0);
4161 PacketResponseNG resp
;
4162 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
4163 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
4164 return PM3_ETIMEOUT
;
4167 iso14a_card_select_t card
;
4168 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
4170 uint64_t select_status
= resp
.oldarg
[0];
4171 // 0: couldn't read,
4174 // 3: proprietary Anticollision
4176 if (select_status
== 0) {
4177 PrintAndLogEx(WARNING
, "iso14443a card select failed");
4181 if (card
.uidlen
!= 4 && card
.uidlen
!= 7) {
4182 PrintAndLogEx(WARNING
, "Wrong sized UID, expected 4|7 bytes got %d", card
.uidlen
);
4186 memcpy(uid
, card
.uid
, card
.uidlen
);
4188 if (ulen
!= 4 && ulen
!= 7) {
4189 PrintAndLogEx(ERR
, "Must supply 4 or 7 hex byte uid");
4194 uint8_t iv
[8] = { 0x00 };
4196 uint8_t mifarekeyA
[] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 };
4197 uint8_t mifarekeyB
[] = { 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5 };
4198 uint8_t dkeyA
[8] = { 0x00 };
4199 uint8_t dkeyB
[8] = { 0x00 };
4201 uint8_t masterkey
[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
4202 uint8_t mix
[8] = { 0x00 };
4203 uint8_t divkey
[8] = { 0x00 };
4205 memcpy(mix
, mifarekeyA
, 4);
4207 mix
[4] = mifarekeyA
[4] ^ uid
[0];
4208 mix
[5] = mifarekeyA
[5] ^ uid
[1];
4209 mix
[6] = block
^ uid
[2];
4212 mbedtls_des3_context ctx_des3
;
4213 mbedtls_des3_set2key_enc(&ctx_des3
, masterkey
);
4215 mbedtls_des3_crypt_cbc(&ctx_des3
// des3_context
4216 , MBEDTLS_DES_ENCRYPT
// int mode
4217 , sizeof(mix
) // length
4223 PrintAndLogEx(SUCCESS
, "-- 3DES version");
4224 PrintAndLogEx(SUCCESS
, "Masterkey......... %s", sprint_hex(masterkey
, sizeof(masterkey
)));
4225 PrintAndLogEx(SUCCESS
, "UID............... %s", sprint_hex(uid
, ulen
));
4226 PrintAndLogEx(SUCCESS
, "block............. %0d", block
);
4227 PrintAndLogEx(SUCCESS
, "Mifare key........ %s", sprint_hex(mifarekeyA
, sizeof(mifarekeyA
)));
4228 PrintAndLogEx(SUCCESS
, "Message........... %s", sprint_hex(mix
, sizeof(mix
)));
4229 PrintAndLogEx(SUCCESS
, "Diversified key... %s", sprint_hex(divkey
+ 1, 6));
4231 for (int i
= 0; i
< ARRAYLEN(mifarekeyA
); ++i
) {
4232 dkeyA
[i
] = (mifarekeyA
[i
] << 1) & 0xff;
4233 dkeyA
[6] |= ((mifarekeyA
[i
] >> 7) & 1) << (i
+ 1);
4236 for (int i
= 0; i
< ARRAYLEN(mifarekeyB
); ++i
) {
4237 dkeyB
[1] |= ((mifarekeyB
[i
] >> 7) & 1) << (i
+ 1);
4238 dkeyB
[2 + i
] = (mifarekeyB
[i
] << 1) & 0xff;
4241 uint8_t zeros
[8] = {0x00};
4242 uint8_t newpwd
[8] = {0x00};
4243 uint8_t dmkey
[24] = {0x00};
4244 memcpy(dmkey
, dkeyA
, 8);
4245 memcpy(dmkey
+ 8, dkeyB
, 8);
4246 memcpy(dmkey
+ 16, dkeyA
, 8);
4247 memset(iv
, 0x00, 8);
4249 mbedtls_des3_set3key_enc(&ctx_des3
, dmkey
);
4251 mbedtls_des3_crypt_cbc(&ctx_des3
// des3_context
4252 , MBEDTLS_DES_ENCRYPT
// int mode
4253 , sizeof(newpwd
) // length
4259 PrintAndLogEx(SUCCESS
, "\n-- DES version");
4260 PrintAndLogEx(SUCCESS
, "MIFARE dkeyA...... %s", sprint_hex(dkeyA
, sizeof(dkeyA
)));
4261 PrintAndLogEx(SUCCESS
, "MIFARE dkeyB...... %s", sprint_hex(dkeyB
, sizeof(dkeyB
)));
4262 PrintAndLogEx(SUCCESS
, "MIFARE ABA........ %s", sprint_hex(dmkey
, sizeof(dmkey
)));
4263 PrintAndLogEx(SUCCESS
, "MIFARE PWD........ %s", sprint_hex(newpwd
, sizeof(newpwd
)));
4265 mbedtls_des3_free(&ctx_des3
);
4267 mbedtls_aes_context ctx_aes
;
4268 uint8_t aes_iv
[16] = { 0x00 };
4269 uint8_t aes_masterkey
[] = { 0x00, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
4270 uint8_t aes_input
[16] = {0x01, 0x04, 0x2A, 0x2E, 0x19, 0x70, 0x1C, 0x80, 0x01, 0x04, 0x2A, 0x2E, 0x19, 0x70, 0x1C, 0x80};
4271 uint8_t aes_output
[16] = {0x00};
4272 mbedtls_aes_setkey_enc(&ctx_aes
, aes_masterkey
, 128);
4273 mbedtls_aes_crypt_cbc(&ctx_aes
, MBEDTLS_AES_ENCRYPT
, 16, aes_iv
, aes_input
, aes_output
);
4274 mbedtls_aes_free(&ctx_aes
);
4276 PrintAndLogEx(SUCCESS
, "\n-- AES version");
4277 PrintAndLogEx(SUCCESS
, "MIFARE AES mk..... %s", sprint_hex(aes_masterkey
, sizeof(aes_masterkey
)));
4278 PrintAndLogEx(SUCCESS
, "MIFARE Div........ %s", sprint_hex(aes_output
, sizeof(aes_output
)));
4280 // next. from the diversify_key method.
4284 static int CmdHF14AMfUPwdGen(const char *Cmd
) {
4285 CLIParserContext
*ctx
;
4286 CLIParserInit(&ctx
, "hf mfu pwdgen",
4287 "Generate different passwords from known pwdgen algos",
4288 "hf mfu pwdgen -r\n"
4289 "hf mfu pwdgen --uid 11223344556677\n"
4290 "hf mfu pwdgen --test"
4293 void *argtable
[] = {
4295 arg_str0("u", "uid", "<hex>", "UID (7 hex bytes)"),
4296 arg_lit0("r", NULL
, "Read UID from tag"),
4297 arg_lit0(NULL
, "test", "self test"),
4300 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4303 uint8_t uid
[7] = {0x00};
4304 CLIGetHexWithReturn(ctx
, 1, uid
, &u_len
);
4305 bool use_tag
= arg_get_lit(ctx
, 2);
4306 bool selftest
= arg_get_lit(ctx
, 3);
4310 return generator_selftest();
4313 uint8_t philips_mfg
[10] = {0};
4316 // read uid from tag
4317 int res
= ul_read_uid(uid
);
4318 if (res
== PM3_ELENGTH
) {
4319 // got 4 byte UID, lets adapt to 7 bytes :)
4320 memset(uid
+ 4, 0x00, 3);
4324 if (res
!= PM3_SUCCESS
) {
4328 iso14a_card_select_t card
;
4329 if (ul_select(&card
)) {
4330 // Philips toothbrush needs page 0x21-0x23
4331 uint8_t data
[16] = {0x00};
4332 int status
= ul_read(0x21, data
, sizeof(data
));
4334 PrintAndLogEx(DEBUG
, "Error: tag didn't answer to READ");
4335 } else if (status
== 16) {
4336 memcpy(philips_mfg
, data
+ 2, sizeof(philips_mfg
));
4342 if (u_len
!= 7 && u_len
!= 4) {
4343 PrintAndLogEx(WARNING
, "Key must be 7 hex bytes");
4345 } else if (u_len
== 4) {
4346 // adapt to 7 bytes :)
4347 memset(uid
+ 4, 0x00, 3);
4352 PrintAndLogEx(INFO
, "-----------------------------------");
4353 PrintAndLogEx(INFO
, " UID 4b... " _YELLOW_("%s"), sprint_hex(uid
, 4));
4354 PrintAndLogEx(INFO
, " UID 7b... " _YELLOW_("%s"), sprint_hex(uid
, 7));
4355 PrintAndLogEx(INFO
, "-----------------------------------");
4356 PrintAndLogEx(INFO
, " algo pwd pack");
4357 PrintAndLogEx(INFO
, "-----------------------------+-----");
4358 PrintAndLogEx(INFO
, " Transport EV1..... %08X | %04X", ul_ev1_pwdgenA(uid
), ul_ev1_packgenA(uid
));
4359 PrintAndLogEx(INFO
, " Amiibo............ %08X | %04X", ul_ev1_pwdgenB(uid
), ul_ev1_packgenB(uid
));
4360 PrintAndLogEx(INFO
, " Lego Dimension.... %08X | %04X", ul_ev1_pwdgenC(uid
), ul_ev1_packgenC(uid
));
4361 PrintAndLogEx(INFO
, " XYZ 3D printer.... %08X | %04X", ul_ev1_pwdgenD(uid
), ul_ev1_packgenD(uid
));
4362 PrintAndLogEx(INFO
, " Xiaomi purifier... %08X | %04X", ul_ev1_pwdgenE(uid
), ul_ev1_packgenE(uid
));
4363 PrintAndLogEx(INFO
, " NTAG tools........ %08X | %04X", ul_ev1_pwdgenF(uid
), ul_ev1_packgen_def(uid
));
4364 if (philips_mfg
[0] != 0) {
4365 PrintAndLogEx(INFO
, " Philips Toothbrush | %08X | %04X", ul_ev1_pwdgenG(uid
, philips_mfg
), ul_ev1_packgenG(uid
, philips_mfg
));
4367 PrintAndLogEx(INFO
, "-----------------------------+-----");
4368 PrintAndLogEx(INFO
, _CYAN_("Vingcard"));
4370 mfc_algo_saflok_one(uid
, 0, 0, &key
);
4371 PrintAndLogEx(INFO
, " Saflok algo | %012" PRIX64
, key
);
4372 PrintAndLogEx(INFO
, " SALTO algo");
4373 PrintAndLogEx(INFO
, " Dorma Kaba algo");
4374 PrintAndLogEx(INFO
, " STiD algo");
4375 PrintAndLogEx(INFO
, "-------------------------------------");
4377 mfc_algo_bambu_one(uid
, 0, MF_KEY_A
, &key
);
4378 PrintAndLogEx(INFO
, " Bambu........ %012" PRIX64
, key
);
4383 // MFU TearOff against OTP
4386 static int CmdHF14AMfuOtpTearoff(const char *Cmd
) {
4387 CLIParserContext
*ctx
;
4388 CLIParserInit(&ctx
, "hf mfu otptear",
4389 "Tear-off test against OTP block",
4390 "hf mfu otptear -b 3\n"
4391 "hf mfu otptear -b 3 -i 100 -s 1000\n"
4392 "hf mfu otptear -b 3 -i 1 -e 200\n"
4393 "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE\n"
4394 "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE -m 00000000 -> quit when OTP is reset"
4397 void *argtable
[] = {
4399 arg_u64_0("b", "blk", "<dec>", "target block (def 8)"),
4400 arg_u64_0("i", "inc", "<dec>", "increase time steps (def 500 us)"),
4401 arg_u64_0("e", "end", "<dec>", "end time (def 3000 us)"),
4402 arg_u64_0("s", "start", "<dec>", "start time (def 0 us)"),
4403 arg_str0("d", "data", "<hex>", "initialise data before run (4 bytes)"),
4404 arg_str0("t", "test", "<hex>", "test write data (4 bytes, 00000000 by default)"),
4405 arg_str0("m", "match", "<hex>", "exit criteria, if block matches this value (4 bytes)"),
4408 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4410 uint8_t blockno
= arg_get_u32_def(ctx
, 1, 8);
4411 uint32_t steps
= arg_get_u32_def(ctx
, 2, 500);
4412 uint32_t end
= arg_get_u32_def(ctx
, 3, 3000);
4413 uint32_t start
= arg_get_u32_def(ctx
, 4, 0);
4416 uint8_t data
[4] = {0x00};
4417 CLIGetHexWithReturn(ctx
, 5, data
, &d_len
);
4418 bool use_data
= (d_len
> 0);
4421 uint8_t test
[4] = {0x00};
4422 CLIGetHexWithReturn(ctx
, 6, test
, &t_len
);
4425 uint8_t match
[4] = {0x00};
4426 CLIGetHexWithReturn(ctx
, 7, match
, &m_len
);
4427 bool use_match
= (m_len
> 0);
4431 PrintAndLogEx(WARNING
, "Block number must be larger than 2.");
4435 PrintAndLogEx(WARNING
, "end time smaller than increase value");
4439 PrintAndLogEx(WARNING
, "end time - out of 1 .. 43000 range");
4442 if (start
> (end
- steps
)) {
4443 PrintAndLogEx(WARNING
, "Start time larger than (end time + steps)");
4447 if (d_len
&& d_len
!= 4) {
4448 PrintAndLogEx(WARNING
, "data must be 4 hex bytes");
4452 if (t_len
&& t_len
!= 4) {
4453 PrintAndLogEx(WARNING
, "test data must be 4 hex bytes");
4457 if (m_len
&& m_len
!= 4) {
4458 PrintAndLogEx(WARNING
, "match data must be 4 hex bytes");
4462 uint8_t teardata
[4] = {0x00};
4463 memcpy(teardata
, test
, sizeof(test
));
4465 PrintAndLogEx(INFO
, "----------------- " _CYAN_("MFU Tear off") " ---------------------");
4466 PrintAndLogEx(INFO
, "Starting Tear-off test");
4467 PrintAndLogEx(INFO
, "Target block no: %u", blockno
);
4469 PrintAndLogEx(INFO
, "Target initial block data : %s", sprint_hex_inrow(data
, 4));
4471 PrintAndLogEx(INFO
, "Target write block data : %s", sprint_hex_inrow(teardata
, 4));
4473 PrintAndLogEx(INFO
, "Target match block data : %s", sprint_hex_inrow(match
, 4));
4475 PrintAndLogEx(INFO
, "----------------------------------------------------");
4477 bool lock_on
= false;
4478 uint8_t pre
[4] = {0};
4479 uint8_t post
[4] = {0};
4480 uint32_t current
= start
;
4481 int phase_begin_clear
= -1;
4482 int phase_end_clear
= -1;
4483 int phase_begin_newwr
= -1;
4484 int phase_end_newwr
= -1;
4485 bool skip_phase1
= false;
4486 uint8_t retries
= 0;
4487 uint8_t error_retries
= 0;
4489 while ((current
<= (end
- steps
)) && (error_retries
< 10)) {
4491 if (kbd_enter_pressed()) {
4492 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
4496 PrintAndLogEx(INFO
, "Using tear-off delay " _GREEN_("%" PRIu32
) " us", current
);
4498 clearCommandBuffer();
4499 PacketResponseNG resp
;
4502 SendCommandMIX(CMD_HF_MIFAREU_WRITEBL
, blockno
, 0, 0, data
, d_len
);
4503 bool got_written
= false;
4504 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
4505 isOK
= resp
.oldarg
[0] & 0xff;
4510 if (! got_written
) {
4511 PrintAndLogEx(FAILED
, "Failed to write block BEFORE");
4513 continue; // try again
4517 SendCommandMIX(CMD_HF_MIFAREU_READBL
, blockno
, 0, 0, NULL
, 0);
4519 bool got_pre
= false;
4520 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
4521 isOK
= resp
.oldarg
[0] & 0xFF;
4523 memcpy(pre
, resp
.data
.asBytes
, sizeof(pre
));
4528 PrintAndLogEx(FAILED
, "Failed to read block BEFORE");
4530 continue; // try again
4532 clearCommandBuffer();
4533 SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF
, blockno
, current
, 0, teardata
, sizeof(teardata
));
4535 // we be getting ACK that we are silently ignoring here..
4537 if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF
, &resp
, 2000)) {
4538 PrintAndLogEx(WARNING
, "Failed");
4542 if (resp
.status
!= PM3_SUCCESS
) {
4543 PrintAndLogEx(WARNING
, "Tear off reporting failure to select tag");
4548 bool got_post
= false;
4549 clearCommandBuffer();
4550 SendCommandMIX(CMD_HF_MIFAREU_READBL
, blockno
, 0, 0, NULL
, 0);
4551 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
4552 isOK
= resp
.oldarg
[0] & 0xFF;
4554 memcpy(post
, resp
.data
.asBytes
, sizeof(post
));
4559 PrintAndLogEx(FAILED
, "Failed to read block BEFORE");
4561 continue; // try again
4564 char prestr
[20] = {0};
4565 snprintf(prestr
, sizeof(prestr
), "%s", sprint_hex_inrow(pre
, sizeof(pre
)));
4566 char poststr
[20] = {0};
4567 snprintf(poststr
, sizeof(poststr
), "%s", sprint_hex_inrow(post
, sizeof(post
)));
4569 if (memcmp(pre
, post
, sizeof(pre
)) == 0) {
4571 PrintAndLogEx(INFO
, "Current : %02d (0x%02X) %s"
4577 PrintAndLogEx(INFO
, _CYAN_("Tear off occurred") " : %02d (0x%02X) %s => " _RED_("%s")
4586 uint32_t post32
= bytes_to_num(post
, 4);
4587 uint32_t pre32
= bytes_to_num(pre
, 4);
4589 if ((phase_begin_clear
== -1) && (bitcount32(pre32
) > bitcount32(post32
)))
4590 phase_begin_clear
= current
;
4592 if ((phase_begin_clear
> -1) && (phase_end_clear
== -1) && (bitcount32(post32
) == 0))
4593 phase_end_clear
= current
;
4595 if ((current
== start
) && (phase_end_clear
> -1))
4597 // new write phase must be atleast 100us later..
4598 if (((bitcount32(pre32
) == 0) || (phase_end_clear
> -1)) && (phase_begin_newwr
== -1) && (bitcount32(post32
) != 0) && (skip_phase1
|| (current
> (phase_end_clear
+ 100))))
4599 phase_begin_newwr
= current
;
4601 if ((phase_begin_newwr
> -1) && (phase_end_newwr
== -1) && (memcmp(post
, teardata
, sizeof(teardata
)) == 0))
4602 phase_end_newwr
= current
;
4605 if (use_match
&& memcmp(post
, match
, sizeof(post
)) == 0) {
4606 PrintAndLogEx(SUCCESS
, "Block matches stop condition!\n");
4610 /* TEMPORALLY DISABLED
4611 uint8_t d0, d1, d2, d3;
4612 d0 = *resp.data.asBytes;
4613 d1 = *(resp.data.asBytes + 1);
4614 d2 = *(resp.data.asBytes + 2);
4615 d3 = *(resp.data.asBytes + 3);
4616 if ((d0 != 0xFF) || (d1 != 0xFF) || (d2 != 0xFF) || (d3 = ! 0xFF)) {
4617 PrintAndLogEx(NORMAL, "---------------------------------");
4618 PrintAndLogEx(NORMAL, " EFFECT AT: %d us", actualTime);
4619 PrintAndLogEx(NORMAL, "---------------------------------\n");
4625 if (lock_on
== false) {
4626 if (++retries
== 20) {
4631 PrintAndLogEx(INFO
, _CYAN_("Retried %u times, increased delay with 1us"), retries
);
4637 PrintAndLogEx(INFO
, "----------------------------------------------------");
4638 if ((phase_begin_clear
> - 1) && (phase_begin_clear
!= start
)) {
4639 PrintAndLogEx(INFO
, "Erase phase start boundary around " _YELLOW_("%5d") " us", phase_begin_clear
);
4641 if ((phase_end_clear
> - 1) && (phase_end_clear
!= start
)) {
4642 PrintAndLogEx(INFO
, "Erase phase end boundary around " _YELLOW_("%5d") " us", phase_end_clear
);
4644 if (phase_begin_newwr
> - 1) {
4645 PrintAndLogEx(INFO
, "Write phase start boundary around " _YELLOW_("%5d") " us", phase_begin_newwr
);
4647 if (phase_end_newwr
> - 1) {
4648 PrintAndLogEx(INFO
, "Write phase end boundary around " _YELLOW_("%5d") " us", phase_end_newwr
);
4650 PrintAndLogEx(NORMAL
, "");
4655 static int counter_reset_tear(iso14a_card_select_t *card, uint8_t cnt_no) {
4657 PrintAndLogEx(INFO, "Reset tear check");
4659 uint8_t cw[6] = { MIFARE_ULEV1_INCR_CNT, cnt_no, 0x00, 0x00, 0x00, 0x00};
4660 uint8_t ct[1] = {0};
4661 uint8_t resp[10] = {0};
4663 if (ul_select(card) == false) {
4664 PrintAndLogEx(FAILED, "failed to select card, exiting...");
4667 if (ul_send_cmd_raw(cw, sizeof(cw), resp, sizeof(resp)) < 0) {
4668 PrintAndLogEx(FAILED, "failed to write all ZEROS");
4671 if (ulev1_readTearing(cnt_no, ct, sizeof(ct)) < 0) {
4672 PrintAndLogEx(FAILED, "AFTER, failed to read ANTITEAR, exiting...");
4677 if (ct[0] != 0xBD) {
4678 PrintAndLogEx(INFO, "Resetting seem to have failed, WHY!?");
4686 static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) {
4688 CLIParserContext *ctx;
4689 CLIParserInit(&ctx, "hf mfu countertear",
4690 "Tear-off test against a Ev1 counter",
4691 "hf mfu countertear\n"
4692 "hf mfu countertear -s 200 -l 2500 -> target counter 0, start delay 200\n"
4693 "hf mfu countertear -i 2 -s 200 -l 400 -> target counter 0, start delay 200\n"
4696 void *argtable[] = {
4698 arg_int0("c", "cnt", "<0,1,2>", "Target this EV1 counter (0,1,2)"),
4699 arg_int0("i", "inc", "<dec>", "time interval to increase in each iteration - default 10 us"),
4700 arg_int0("l", "limit", "<dec>", "test upper limit time - default 3000 us"),
4701 arg_int0("s", "start", "<dec>", "test start time - default 0 us"),
4702 arg_int0(NULL, "fix", "<dec>", "test fixed loop delay"),
4703 arg_str0("x", "hex", NULL, "3 byte hex to increase counter with"),
4706 CLIExecWithReturn(ctx, Cmd, argtable, false);
4709 int time_limit, start_time = 0;
4710 int counter = arg_get_int_def(ctx, 1, 0);
4711 int fixed = arg_get_int_def(ctx, 5, -1);
4713 if ( fixed == -1 ) {
4714 interval = arg_get_int_def(ctx, 2, 10);
4715 time_limit = arg_get_int_def(ctx, 3, 3000);
4716 start_time = arg_get_int_def(ctx, 4, 0);
4723 uint8_t newvalue[5] = {0};
4724 int newvaluelen = 0;
4725 CLIGetHexWithReturn(ctx, 6, newvalue, &newvaluelen);
4729 if (start_time > (time_limit - interval)) {
4730 PrintAndLogEx(WARNING, "Wrong start time number");
4733 if (time_limit < interval) {
4734 PrintAndLogEx(WARNING, "Wrong time limit number");
4737 if (time_limit > 43000) {
4738 PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
4742 if (counter < 0 || counter > 2) {
4743 PrintAndLogEx(WARNING, "Counter must 0, 1 or 2");
4747 cnt_no = (uint8_t)counter;
4749 iso14a_card_select_t card;
4751 // reset counter tear
4752 counter_reset_tear(&card, cnt_no);
4754 if (ul_select(&card) == false) {
4755 PrintAndLogEx(INFO, "failed to select card, exiting...");
4759 uint8_t initial_cnt[3] = {0, 0, 0};
4760 int len = ulev1_readCounter(cnt_no, initial_cnt, sizeof(initial_cnt));
4761 if ( len != sizeof(initial_cnt) ) {
4762 PrintAndLogEx(WARNING, "failed to read counter");
4766 uint8_t initial_tear[1] = {0};
4767 len = ulev1_readTearing(cnt_no, initial_tear, sizeof(initial_tear));
4769 if ( len != sizeof(initial_tear) ) {
4770 PrintAndLogEx(WARNING, "failed to read ANTITEAR, exiting... %d", len);
4774 uint32_t wr_value = ( newvalue[0] | newvalue[1] << 8 | newvalue[2] << 16 );
4775 uint32_t initial_value = ( initial_cnt[0] | initial_cnt[1] << 8 | initial_cnt[2] << 16 );;
4777 PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Ev1 Counter Tear off") " ---------------------");
4778 PrintAndLogEx(INFO, "Target counter no [ " _GREEN_("%u") " ]", counter);
4779 PrintAndLogEx(INFO, " counter value [ " _GREEN_("%s") " ]", sprint_hex_inrow(initial_cnt, sizeof(initial_cnt)));
4780 PrintAndLogEx(INFO, " anti-tear value [ " _GREEN_("%02X") " ]", initial_tear[0]);
4781 PrintAndLogEx(INFO, " increase value [ " _GREEN_("%s") " ]", sprint_hex_inrow(newvalue, newvaluelen));
4782 PrintAndLogEx(INFO, "----------------------------------------------------");
4784 uint8_t pre_tear = 0, post_tear = 0;
4785 uint8_t pre[3] = {0};
4786 uint8_t post[3] = {0};
4787 uint32_t actual_time = start_time;
4788 uint32_t a = 0, b = 0;
4793 while (actual_time <= (time_limit - interval)) {
4799 if (kbd_enter_pressed()) {
4800 PrintAndLogEx(INFO, "\naborted via keyboard!\n");
4804 PrintAndLogEx(INPLACE, "Using tear-off delay " _GREEN_("%" PRIu32) " µs (attempt %u)", actual_time, loop);
4806 if (ul_select(&card) == false) {
4807 PrintAndLogEx(FAILED, "BEFORE, failed to select card, looping...");
4811 uint8_t cntresp[3] = {0, 0, 0};
4812 int rlen = ulev1_readCounter(cnt_no, cntresp, sizeof(cntresp));
4813 if ( rlen == sizeof(cntresp) ) {
4814 memcpy(pre, cntresp, sizeof(pre));
4816 PrintAndLogEx(NORMAL, "");
4817 PrintAndLogEx(FAILED, "BEFORE, failed to read COUNTER, exiting...");
4821 uint8_t tear[1] = {0};
4822 int tlen = ulev1_readTearing(cnt_no, tear, sizeof(tear));
4823 if ( tlen == sizeof(tear) ) {
4826 PrintAndLogEx(NORMAL, "");
4827 PrintAndLogEx(FAILED, "BEFORE, failed to read ANTITEAR, exiting... %d", tlen);
4835 uint32_t tearoff_time;
4838 payload.counter = cnt_no;
4839 payload.tearoff_time = actual_time;
4840 memcpy(payload.value, newvalue, sizeof(payload.value));
4842 clearCommandBuffer();
4843 PacketResponseNG resp;
4844 SendCommandNG(CMD_HF_MFU_COUNTER_TEAROFF, (uint8_t*)&payload, sizeof(payload));
4845 if (!WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000)) {
4846 PrintAndLogEx(WARNING, "\ntear off command failed");
4850 if (ul_select(&card) == false) {
4851 PrintAndLogEx(FAILED, "AFTER, failed to select card, exiting...");
4855 rlen = ulev1_readCounter(cnt_no, cntresp, sizeof(cntresp));
4856 if ( rlen == sizeof(cntresp) ) {
4857 memcpy(post, cntresp, sizeof(post));
4859 PrintAndLogEx(NORMAL, "");
4860 PrintAndLogEx(FAILED, "AFTER, failed to read COUNTER, exiting...");
4865 tlen = ulev1_readTearing(cnt_no, tear, sizeof(tear));
4866 if ( tlen == sizeof(tear) ) {
4867 post_tear = tear[0];
4869 PrintAndLogEx(NORMAL, "");
4870 PrintAndLogEx(FAILED, "AFTER, failed to read ANTITEAR, exiting...");
4876 char prestr[20] = {0};
4877 snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre)));
4878 char poststr[20] = {0};
4879 snprintf(poststr, sizeof(poststr), "%s", sprint_hex_inrow(post, sizeof(post)));
4881 bool post_tear_check = (post_tear == 0xBD);
4882 a = (pre[0] | pre[1] << 8 | pre[2] << 16);
4883 b = (post[0] | post[1] << 8 | post[2] << 16);
4886 if (memcmp(pre, post, sizeof(pre)) != 0) {
4889 PrintAndLogEx(NORMAL, "");
4891 if (initial_value != a ) {
4893 if ( initial_value != b )
4894 PrintAndLogEx(INFO, "pre %08x, post %08x != initial %08x | tear: 0x%02X == 0x%02X", a, b, initial_value, pre_tear, post_tear);
4896 PrintAndLogEx(INFO, "pre %08x != initial and post %08x == initial %08x | tear: 0x%02X == 0x%02X", a, b, initial_value, pre_tear, post_tear);
4899 if ( initial_value != b )
4900 PrintAndLogEx(INFO, "pre %08x == initial and post %08x != initial %08x | tear: 0x%02X == 0x%02X", a, b, initial_value, pre_tear, post_tear);
4904 PrintAndLogEx(INFO, _CYAN_("Tear off occurred (ZEROS value!) -> ") "%s vs " _GREEN_("%s") " Tear status: 0x%02X == 0x%02X ( %s )"
4909 , post_tear_check ? _GREEN_("ok") : _RED_("DETECTED")
4915 PrintAndLogEx(INFO, _CYAN_("Tear off occurred " _RED_("( LESS )") " -> ") "%s vs " _GREEN_("%s") " Tear status: 0x%02X == 0x%02X ( %s )"
4920 , post_tear_check ? _GREEN_("ok") : _RED_("DETECTED")
4924 if (counter_reset_tear(&card, cnt_no) != PM3_SUCCESS){
4925 PrintAndLogEx(FAILED, "failed to reset tear, exiting...");
4929 uint32_t bar = (0x1000000 - b) + 2;
4931 // newvalue[0] = (bar) & 0xFF;
4932 // newvalue[1] = ((bar >> 8) & 0xFF);
4933 // newvalue[2] = ((bar >> 16) & 0xFF);
4940 PrintAndLogEx(INFO, " 0x1000000 - 0x%x == 0x%x", b, bar);
4941 PrintAndLogEx(INFO, " new increase value 0x%x" , wr_value);
4942 PrintAndLogEx(INFO, " because BAR + post == 0x%x" , bar + b);
4944 PrintAndLogEx(INFO, "New increase value " _YELLOW_("%s"), sprint_hex_inrow(newvalue, newvaluelen));
4948 PrintAndLogEx(NORMAL, "");
4949 PrintAndLogEx(INFO, _CYAN_("Tear off occurred (+1) (too late) -> ") "%s vs %s Tear: 0x%02X == 0x%02X ( %s )"
4954 , post_tear_check ? _GREEN_("ok") : _RED_("DETECTED")
4957 if ( post_tear_check && b == initial_value) {
4958 PrintAndLogEx(INFO, "Reverted to previous value");
4961 if ( wr_value != 0 ) {
4963 //uint32_t bar = (0x1000000 - b) + 2;
4969 if ( b >= (initial_value + (2 * wr_value))) {
4970 PrintAndLogEx(INFO, "Large " _YELLOW_("( JUMP )") " detected");
4974 // newvalue[0] = (bar) & 0xFF;
4975 // newvalue[1] = ((bar >> 8) & 0xFF);
4976 // newvalue[2] = ((bar >> 16) & 0xFF);
4980 // newvalue[0] = (bar) & 0xFF;
4981 // newvalue[1] = ((bar >> 8) & 0xFF);
4982 // newvalue[2] = ((bar >> 16) & 0xFF);
4990 PrintAndLogEx(INFO, "New increase value " _YELLOW_("%s"), sprint_hex_inrow(newvalue, newvaluelen));
4996 PrintAndLogEx(NORMAL, "");
4997 PrintAndLogEx(INFO, _CYAN_("Status: same value! -> ") "%s == %s Tear: 0x%02X == 0x%02X ( %s )"
5002 , post_tear_check ? _GREEN_("ok") : _RED_("DETECTED")
5005 if ( post_tear_check ) {
5011 if ( b == initial_value ) {
5012 PrintAndLogEx(INFO, "Reverted to previous value");
5017 if (counter_reset_tear(&card, cnt_no) != PM3_SUCCESS){
5018 PrintAndLogEx(FAILED, "failed to reset tear, exiting...");
5025 actual_time += interval;
5030 PrintAndLogEx(INFO, " Sent %u tear offs ", loop);
5032 counter_reset_tear(&card, cnt_no);
5034 PrintAndLogEx(INFO, "hf 14a raw -s -c 3900 --> read counter 0");
5035 PrintAndLogEx(INFO, "hf 14a raw -s -c 3e00 --> read tearing 0");
5036 PrintAndLogEx(NORMAL, "");
5037 char read_cnt_str[30];
5038 snprintf(read_cnt_str, sizeof(read_cnt_str), "hf 14a raw -s -c 39%02x", counter);
5039 CommandReceived(read_cnt_str);
5040 char read_tear_str[30];
5041 snprintf(read_tear_str, sizeof(read_tear_str), "hf 14a raw -s -c 3e%02x", counter);
5042 CommandReceived(read_tear_str);
5049 // name, identifying bytes, decode function, hints text
5051 // 1. getversion data must match.
5052 // 2. magic bytes in the readable payload
5055 int CmdHF14MfuNDEFRead(const char *Cmd
) {
5058 int maxsize
= 16, status
;
5059 bool hasAuthKey
= false;
5060 bool swapEndian
= false;
5062 iso14a_card_select_t card
;
5063 uint8_t data
[16] = {0x00};
5064 uint8_t key
[16] = {0x00};
5065 uint8_t *p_key
= key
;
5066 uint8_t pack
[4] = {0, 0, 0, 0};
5068 CLIParserContext
*ctx
;
5069 CLIParserInit(&ctx
, "hf mfu ndefread",
5070 "Prints NFC Data Exchange Format (NDEF)",
5071 "hf mfu ndefread -> shows NDEF data\n"
5072 "hf mfu ndefread -k ffffffff -> shows NDEF data with key\n"
5073 "hf mfu ndefread -f myfilename -> save raw NDEF to file"
5076 void *argtable
[] = {
5078 arg_str0("k", "key", "Replace default key for NDEF", NULL
),
5079 arg_lit0("l", NULL
, "Swap entered key's endianness"),
5080 arg_str0("f", "file", "<fn>", "Save raw NDEF to file"),
5081 arg_lit0("v", "verbose", "Verbose output"),
5084 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5085 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
5086 swapEndian
= arg_get_lit(ctx
, 2);
5088 char filename
[FILE_PATH_SIZE
] = {0};
5089 CLIParamStrToBuf(arg_get_str(ctx
, 3), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
5090 bool verbose
= arg_get_lit(ctx
, 4);
5101 PrintAndLogEx(WARNING
, "ERROR: Key is incorrect length\n");
5106 uint64_t tagtype
= GetHF14AMfU_Type();
5107 if (tagtype
== MFU_TT_UL_ERROR
) {
5108 PrintAndLogEx(WARNING
, "No Ultralight / NTAG based tag found");
5115 if (swapEndian
&& hasAuthKey
) p_key
= SwapEndian64(key
, keylen
, (keylen
== 16) ? 8 : 4);
5118 if (ul_auth_select(&card
, tagtype
, hasAuthKey
, p_key
, pack
, sizeof(pack
)) == PM3_ESOFT
) return PM3_ESOFT
;
5120 // read pages 0,1,2,3 (should read 4pages)
5121 status
= ul_read(0, data
, sizeof(data
));
5124 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ");
5126 } else if (status
== 16) {
5128 status
= ndef_print_CC(data
+ 12);
5129 if (status
== PM3_ESOFT
) {
5131 PrintAndLogEx(ERR
, "Error: tag didn't contain a NDEF Container");
5136 maxsize
= ndef_get_maxsize(data
+ 12);
5139 // iceman: maybe always take MIN of tag identified size vs NDEF reported size?
5140 // fix: UL_EV1 48bytes != NDEF reported size
5141 for (uint8_t idx
= 1; idx
< ARRAYLEN(UL_TYPES_ARRAY
); idx
++) {
5142 if ((tagtype
& UL_TYPES_ARRAY
[idx
]) == UL_TYPES_ARRAY
[idx
]) {
5144 if (maxsize
!= (UL_MEMORY_ARRAY
[idx
] * 4)) {
5145 PrintAndLogEx(INFO
, "Tag reported size vs NDEF reported size mismatch. Using smallest value");
5147 maxsize
= MIN(maxsize
, (UL_MEMORY_ARRAY
[idx
] * 4));
5152 // The following read will read in blocks of 16 bytes.
5153 // ensure maxsize is rounded up to a multiple of 16
5154 maxsize
= maxsize
+ (16 - (maxsize
% 16));
5156 uint8_t *records
= calloc(maxsize
, sizeof(uint8_t));
5157 if (records
== NULL
) {
5162 // read NDEF records.
5163 for (uint32_t i
= 0, j
= 0; i
< maxsize
; i
+= 16, j
+= 4) {
5164 status
= ul_read(4 + j
, records
+ i
, 16);
5167 PrintAndLogEx(ERR
, "Error: tag didn't answer to READ");
5175 status
= NDEFRecordsDecodeAndPrint(records
, (size_t)maxsize
, verbose
);
5176 if (status
!= PM3_SUCCESS
) {
5177 status
= NDEFDecodeAndPrint(records
, (size_t)maxsize
, verbose
);
5180 // get total NDEF length before save. If fails, we save it all
5182 if (NDEFGetTotalLength(records
, maxsize
, &n
) != PM3_SUCCESS
)
5185 pm3_save_dump(filename
, records
, n
, jsfNDEF
);
5188 char *jooki
= strstr((char *)records
, "s.jooki.rocks/s/?s=");
5192 if ((*jooki
) != '=')
5197 strncpy(s
, jooki
, 16);
5198 PrintAndLogEx(HINT
, "Use `" _YELLOW_("hf jooki decode -d %s") "` to decode", s
);
5203 char *mattel
= strstr((char *)records
, ".pid.mattel/");
5207 if ((*mattel
) != '/')
5212 strncpy(b64
, mattel
, 32);
5213 uint8_t arr
[24] = {0};
5215 mbedtls_base64_decode(arr
, sizeof(arr
), &arrlen
, (const unsigned char *)b64
, 32);
5217 PrintAndLogEx(INFO
, "decoded... %s", sprint_hex(arr
, arrlen
));
5227 // utility function. Retrieves emulator memory
5228 static int GetMfuDumpFromEMul(mfu_dump_t
**buf
) {
5230 mfu_dump_t
*dump
= calloc(1, sizeof(mfu_dump_t
));
5232 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
5236 PrintAndLogEx(INFO
, "downloading from emulator memory");
5237 if (!GetFromDevice(BIG_BUF_EML
, (uint8_t *)dump
, MFU_MAX_BYTES
+ MFU_DUMP_PREFIX_LENGTH
, 0, NULL
, 0, NULL
, 2500, false)) {
5238 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
5240 return PM3_ETIMEOUT
;
5244 return PM3_SUCCESS
;
5247 static int CmdHF14AMfuEView(const char *Cmd
) {
5248 CLIParserContext
*ctx
;
5249 CLIParserInit(&ctx
, "hf mfu eview",
5250 "Displays emulator memory\n"
5251 "By default number of pages shown depends on defined tag type.\n"
5252 "You can override this with option --end.",
5254 "hf mfu eview --end 255 -> dumps whole memory"
5257 void *argtable
[] = {
5259 arg_int0("e", "end", "<dec>", "index of last block"),
5260 arg_lit0("z", "dense", "dense dump output style"),
5264 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5265 int end
= arg_get_int_def(ctx
, 1, -1);
5266 bool dense_output
= (g_session
.dense_output
|| arg_get_lit(ctx
, 2));
5269 bool override_end
= (end
!= -1) ;
5271 if (override_end
&& (end
< 0 || end
> MFU_MAX_BLOCKS
)) {
5272 PrintAndLogEx(WARNING
, "Invalid value for end: %d Must be be positive integer < %d", end
, MFU_MAX_BLOCKS
);
5273 return PM3_EINVARG
;
5277 int res
= GetMfuDumpFromEMul(&dump
) ;
5278 if (res
!= PM3_SUCCESS
) {
5285 end
= dump
->pages
+ 1;
5288 mfu_print_dump(dump
, end
, 0, dense_output
);
5293 static int CmdHF14AMfuESave(const char *Cmd
) {
5294 CLIParserContext
*ctx
;
5295 CLIParserInit(&ctx
, "hf mfu esave",
5296 "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/json)\n"
5297 "By default number of pages saved depends on defined tag type.\n"
5298 "You can override this with option --end.",
5300 "hf mfu esave --end 255 -> saves whole memory\n"
5301 "hf mfu esave -f hf-mfu-04010203040506-dump"
5304 void *argtable
[] = {
5306 arg_int0("e", "end", "<dec>", "index of last block"),
5307 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
5311 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5312 int end
= arg_get_int_def(ctx
, 1, -1);
5314 char filename
[FILE_PATH_SIZE
];
5316 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
5320 bool override_end
= (end
!= -1) ;
5322 if (override_end
&& (end
< 0 || end
> MFU_MAX_BLOCKS
)) {
5323 PrintAndLogEx(WARNING
, "Invalid value for end:%d. Must be be positive integer <= %d.", end
, MFU_MAX_BLOCKS
);
5324 return PM3_EINVARG
;
5327 // get dump from memory
5329 int res
= GetMfuDumpFromEMul(&dump
) ;
5330 if (res
!= PM3_SUCCESS
) {
5334 // initialize filename
5336 PrintAndLogEx(INFO
, "Using UID as filename");
5337 uint8_t uid
[7] = {0};
5338 memcpy(uid
, (uint8_t *) & (dump
->data
), 3);
5339 memcpy(uid
+ 3, (uint8_t *) & (dump
->data
) + 4, 4);
5340 strcat(filename
, "hf-mfu-");
5341 FillFileNameByUID(filename
, uid
, "-dump", sizeof(uid
));
5350 // save dump. Last block contains PACK + RFU
5351 uint16_t datalen
= (end
+ 1) * MFU_BLOCK_SIZE
+ MFU_DUMP_PREFIX_LENGTH
;
5352 res
= pm3_save_dump(filename
, (uint8_t *)dump
, datalen
, jsfMfuMemory
);
5358 static int CmdHF14AMfuView(const char *Cmd
) {
5360 CLIParserContext
*ctx
;
5361 CLIParserInit(&ctx
, "hf mfu view",
5362 "Print a MIFARE Ultralight/NTAG dump file (bin/eml/json)",
5363 "hf mfu view -f hf-mfu-01020304-dump.bin"
5365 void *argtable
[] = {
5367 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
5368 arg_lit0("v", "verbose", "Verbose output"),
5369 arg_lit0("z", "dense", "dense dump output style"),
5372 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5374 char filename
[FILE_PATH_SIZE
];
5375 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
5376 bool verbose
= arg_get_lit(ctx
, 2);
5377 bool dense_output
= (g_session
.dense_output
|| arg_get_lit(ctx
, 3));
5381 uint8_t *dump
= NULL
;
5382 size_t bytes_read
= 0;
5383 int res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, (MFU_MAX_BYTES
+ MFU_DUMP_PREFIX_LENGTH
));
5384 if (res
!= PM3_SUCCESS
) {
5388 if (bytes_read
< MFU_DUMP_PREFIX_LENGTH
) {
5389 PrintAndLogEx(ERR
, "Error, dump file is too small");
5394 res
= convert_mfu_dump_format(&dump
, &bytes_read
, verbose
);
5395 if (res
!= PM3_SUCCESS
) {
5396 PrintAndLogEx(FAILED
, "Failed convert on load to new Ultralight/NTAG format");
5401 uint16_t block_cnt
= ((bytes_read
- MFU_DUMP_PREFIX_LENGTH
) / MFU_BLOCK_SIZE
);
5404 PrintAndLogEx(INFO
, "File: " _YELLOW_("%s"), filename
);
5405 PrintAndLogEx(INFO
, "File size %zu bytes, file blocks %d (0x%x)", bytes_read
, block_cnt
, block_cnt
);
5408 mfu_print_dump((mfu_dump_t
*)dump
, block_cnt
, 0, dense_output
);
5413 static int CmdHF14AMfuList(const char *Cmd
) {
5414 return CmdTraceListAlias(Cmd
, "hf 14a", "14a -c");
5417 static int CmdHF14AAmiibo(const char *Cmd
) {
5419 CLIParserContext
*ctx
;
5420 CLIParserInit(&ctx
, "hf mfu amiibo",
5421 "Tries to read all memory from amiibo tag and decrypt it",
5422 "hf mfu amiiboo --dec -f hf-mfu-04579DB27C4880-dump.bin --> decrypt file\n"
5423 "hf mfu amiiboo -v --dec --> decrypt tag"
5426 void *argtable
[] = {
5428 arg_lit0(NULL
, "dec", "Decrypt memory"),
5429 arg_lit0(NULL
, "enc", "Encrypt memory"),
5430 arg_str0("i", "in", "<fn>", "Specify a filename for input dump file"),
5431 arg_str0("o", "out", "<fn>", "Specify a filename for output dump file"),
5432 arg_lit0("v", "verbose", "Verbose output"),
5435 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5437 bool shall_decrypt
= arg_get_lit(ctx
, 1);
5438 bool shall_encrypt
= arg_get_lit(ctx
, 2);
5441 char infilename
[FILE_PATH_SIZE
];
5442 CLIParamStrToBuf(arg_get_str(ctx
, 3), (uint8_t *)infilename
, FILE_PATH_SIZE
, &infnlen
);
5445 char outfilename
[FILE_PATH_SIZE
];
5446 CLIParamStrToBuf(arg_get_str(ctx
, 4), (uint8_t *)outfilename
, FILE_PATH_SIZE
, &outfnlen
);
5448 bool verbose
= arg_get_lit(ctx
, 5);
5452 if ((shall_decrypt
+ shall_encrypt
) > 1) {
5453 PrintAndLogEx(WARNING
, "Only specify decrypt or encrypt");
5458 nfc3d_amiibo_keys_t amiibo_keys
;
5459 if (nfc3d_amiibo_load_keys(&amiibo_keys
) == false) {
5460 PrintAndLogEx(INFO
, "loading key file ( " _RED_("fail") " )");
5464 int res
= PM3_ESOFT
;
5466 uint8_t original
[NFC3D_AMIIBO_SIZE
] = {0};
5468 // load dump file if available
5470 uint8_t *dump
= NULL
;
5472 res
= loadFile_safe(infilename
, "", (void **)&dump
, &dumplen
);
5473 if (res
!= PM3_SUCCESS
) {
5478 if (dumplen
< MFU_DUMP_PREFIX_LENGTH
) {
5479 PrintAndLogEx(ERR
, "Error, dump file is too small");
5484 res
= convert_mfu_dump_format(&dump
, &dumplen
, verbose
);
5485 if (res
!= PM3_SUCCESS
) {
5486 PrintAndLogEx(FAILED
, "Failed convert on load to new Ultralight/NTAG format");
5491 const mfu_dump_t
*d
= (mfu_dump_t
*)dump
;
5492 memcpy(original
, d
->data
, sizeof(original
));
5496 uint8_t *dump
= NULL
;
5497 res
= mfu_dump_tag(MAX_NTAG_215
, (void **)&dump
, &dlen
);
5498 if (res
!= PM3_SUCCESS
) {
5499 PrintAndLogEx(FAILED
, "Failed to dump memory from tag");
5503 memcpy(original
, dump
, sizeof(original
));
5508 uint8_t decrypted
[NFC3D_AMIIBO_SIZE
] = {0};
5509 if (shall_decrypt
) {
5510 if (nfc3d_amiibo_unpack(&amiibo_keys
, original
, decrypted
) == false) {
5511 PrintAndLogEx(INFO
, "Tag signature ( " _RED_("fail") " )");
5516 for (uint8_t i
= 0; i
< (NFC3D_AMIIBO_SIZE
/ 16); i
++) {
5517 PrintAndLogEx(INFO
, "[%d] %s", i
, sprint_hex_ascii(decrypted
+ (i
* 16), 16));
5522 if (shall_encrypt
) {
5523 uint8_t encrypted
[NFC3D_AMIIBO_SIZE
] = {0};
5524 nfc3d_amiibo_pack(&amiibo_keys
, decrypted
, encrypted
);
5527 for (uint8_t i
= 0; i
< (NFC3D_AMIIBO_SIZE
/ 16); i
++) {
5528 PrintAndLogEx(INFO
, "[%d] %s", i
, sprint_hex_ascii(encrypted
+ (i
* 16), 16));
5534 // save dump. Last block contains PACK + RFU
5535 // uint16_t datalen = MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH;
5536 // res = pm3_save_dump(outfilename, (uint8_t *)dump, datalen, jsfMfuMemory);
5542 static int CmdHF14AMfuWipe(const char *Cmd
) {
5543 CLIParserContext
*ctx
;
5544 CLIParserInit(&ctx
, "hf mfu wipe",
5545 "Wipe card to zeros. It will ignore block0,1,2,3\n"
5546 "you will need to call it with password in order to wipe the config and sett default pwd/pack\n"
5547 "Abort by pressing a key\n"
5548 "New password.... FFFFFFFF\n"
5549 "New 3-DES key... 49454D4B41455242214E4143554F5946\n",
5551 "hf mfu wipe -k 49454D4B41455242214E4143554F5946\n"
5553 void *argtable
[] = {
5555 arg_str0("k", "key", "<hex>", "Key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
5556 arg_lit0("l", NULL
, "Swap entered key's endianness"),
5559 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5562 uint8_t authenticationkey
[16] = {0x00};
5563 uint8_t *auth_key_ptr
= authenticationkey
;
5564 CLIGetHexWithReturn(ctx
, 1, authenticationkey
, &ak_len
);
5565 bool swap_endian
= arg_get_lit(ctx
, 2);
5569 bool has_auth_key
= false;
5570 bool has_pwd
= false;
5572 has_auth_key
= true;
5573 } else if (ak_len
== 4) {
5575 } else if (ak_len
!= 0) {
5576 PrintAndLogEx(WARNING
, "ERROR: Key is incorrect length\n");
5580 uint8_t card_mem_size
= 0;
5585 auth_key_ptr
= SwapEndian64(authenticationkey
, ak_len
, 8);
5589 auth_key_ptr
= SwapEndian64(authenticationkey
, ak_len
, 4);
5593 uint64_t tagtype
= GetHF14AMfU_Type();
5594 if (tagtype
== MFU_TT_UL_ERROR
) {
5598 // number of pages to WRITE
5599 for (uint8_t idx
= 1; idx
< ARRAYLEN(UL_TYPES_ARRAY
); idx
++) {
5600 if ((tagtype
& UL_TYPES_ARRAY
[idx
]) == UL_TYPES_ARRAY
[idx
]) {
5601 //add one as maxblks starts at 0
5602 card_mem_size
= UL_MEMORY_ARRAY
[idx
] + 1;
5607 ul_print_type(tagtype
, 0);
5609 // GDM / GEN1A / GEN4 / NTAG21x read the key
5614 int res
= get_ulc_3des_key_magic(tagtype
, auth_key_ptr
);
5615 if (res
!= PM3_SUCCESS
) {
5618 PrintAndLogEx(SUCCESS
, "Using 3DES key... %s", sprint_hex_inrow(auth_key_ptr
, 16));
5619 has_auth_key
= true;
5624 PrintAndLogEx(INFO
, "Start wiping...");
5625 PrintAndLogEx(INFO
, "-----+-----------------------------");
5626 // time to wipe card
5627 // We skip the first four blocks.
5631 for (uint8_t i
= 4; i
< card_mem_size
; i
++) {
5633 if (kbd_enter_pressed()) {
5634 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
5638 uint8_t data
[MFU_BLOCK_SIZE
];
5639 memset(data
, 0x00, sizeof(data
));
5642 if ((tagtype
& MFU_TT_UL_C
) == MFU_TT_UL_C
) {
5647 memcpy(data
, "\x02\x00\x00\x10", 4);
5650 memcpy(data
, "\x00\x06\x01\x10", 4);
5653 memcpy(data
, "\x11\xFF\x00\x00", 4);
5656 memcpy(data
, "\x30\x00\x00\x00", 4);
5664 if ((tagtype
& MFU_TT_UL_AES
)) {
5668 // UL / NTAG with PWD/PACK
5669 if ((tagtype
& (MFU_TT_UL_EV1_48
| MFU_TT_UL_EV1_128
| MFU_TT_UL_EV1
| MFU_TT_UL_NANO_40
|
5670 MFU_TT_NTAG_210u
| MFU_TT_NTAG_213
| MFU_TT_NTAG_213_F
| MFU_TT_NTAG_213_C
|
5671 MFU_TT_NTAG_213_TT
| MFU_TT_NTAG_215
| MFU_TT_NTAG_216
| MFU_TT_NTAG_216_F
|
5672 MFU_TT_NTAG_I2C_1K
| MFU_TT_NTAG_I2C_2K
| MFU_TT_NTAG_I2C_1K_PLUS
| MFU_TT_NTAG_I2C_2K_PLUS
5677 if (i
== card_mem_size
- 4) {
5678 // strong modulation mode disabled
5679 // pages don't need authentication
5680 uint8_t cfg1
[MFU_BLOCK_SIZE
] = {0x00, 0x00, 0x00, 0xFF};
5681 memcpy(data
, cfg1
, sizeof(cfg1
));
5685 if (i
== card_mem_size
- 3) {
5686 // Unlimited password attempts
5687 // NFC counter disabled
5688 // NFC counter not protected
5689 // user configuration writeable
5690 // write access is protected with password
5691 // 05, Virtual Card Type Identifier is default
5692 uint8_t cfg2
[MFU_BLOCK_SIZE
] = {0x00, 0x05, 0x00, 0x00};
5693 memcpy(data
, cfg2
, sizeof(cfg2
));
5696 // Set PWD blocks 0xFF FF FF FF
5697 if (i
== card_mem_size
- 2) {
5698 memset(data
, 0xFF, sizeof(data
));
5701 // Since we changed PWD before, we need to use new PWD to set PACK
5702 // Pack will be all zeros,
5703 if (i
== card_mem_size
- 1) {
5704 memset(auth_key_ptr
, 0xFF, ak_len
);
5709 int res = PM3_SUCCESS;
5710 if (res == PM3_ESOFT) {
5711 res = mfu_write_block(data, MFU_BLOCK_SIZE, has_auth_key, has_pwd, auth_key_ptr, i);
5715 int res
= mfu_write_block(data
, MFU_BLOCK_SIZE
, has_auth_key
, has_pwd
, auth_key_ptr
, i
);
5717 PrintAndLogEx(INFO
, " %3d | %s" NOLF
, i
, sprint_hex(data
, MFU_BLOCK_SIZE
));
5720 PrintAndLogEx(NORMAL
, "( " _GREEN_("ok") " )");
5724 PrintAndLogEx(NORMAL
, "( " _RED_("fail") " )");
5729 PrintAndLogEx(NORMAL
, "");
5730 PrintAndLogEx(WARNING
, "command execution time out");
5736 PrintAndLogEx(INFO
, "-----+-----------------------------");
5740 // UL-C - set 3-DES key
5741 if ((tagtype
& MFU_TT_UL_C
) == MFU_TT_UL_C
) {
5744 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42,
5745 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46
5748 clearCommandBuffer();
5749 SendCommandMIX(CMD_HF_MIFAREUC_SETPWD
, 0, 0, 0, key
, sizeof(key
));
5750 PacketResponseNG resp
;
5751 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
5752 if ((resp
.oldarg
[0] & 0xff) == 1) {
5753 PrintAndLogEx(INFO
, "Ultralight-C new key... " _GREEN_("%s"), sprint_hex_inrow(key
, sizeof(key
)));
5755 PrintAndLogEx(WARNING
, "Failed writing at block %u", (uint8_t)(resp
.oldarg
[1] & 0xFF));
5759 PrintAndLogEx(WARNING
, "command execution time out");
5760 return PM3_ETIMEOUT
;
5765 if ((tagtype
& MFU_TT_UL_AES
)) {
5770 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mfu dump --ns") "` to verify");
5771 PrintAndLogEx(NORMAL
, "");
5772 PrintAndLogEx(INFO
, "Done!");
5778 static int CmdHF14AMfUIncr(const char *Cmd
) {
5779 CLIParserContext
*ctx
;
5780 CLIParserInit(&ctx
, "hf mfu incr",
5781 "Increment a MIFARE Ultralight Ev1 counter\n"
5782 "Will read but not increment counter if NTAG is detected",
5783 "hf mfu incr -c 0 -v 1337\n"
5784 "hf mfu incr -c 2 -v 0 -p FFFFFFFF");
5785 void *argtable
[] = {
5787 arg_int1("c", "cnt", "<dec>", "Counter index from 0"),
5788 arg_int1("v", "val", "<dec>", "Value to increment by (0-16777215)"),
5789 arg_str0("p", "pwd", "<hex>", "PWD to authenticate with"),
5792 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5794 uint8_t counter
= arg_get_int_def(ctx
, 1, 3);
5795 uint32_t value
= arg_get_u32_def(ctx
, 2, 16777216);
5798 uint8_t pwd
[4] = { 0x00 };
5799 CLIGetHexWithReturn(ctx
, 3, pwd
, &pwd_len
);
5800 bool has_key
= false;
5804 PrintAndLogEx(WARNING
, "incorrect PWD length");
5812 PrintAndLogEx(WARNING
, "Counter index must be in range 0-2");
5815 if (value
> 16777215) {
5816 PrintAndLogEx(WARNING
, "Value to increment must be in range 0-16777215");
5820 uint8_t increment_cmd
[6] = { MIFARE_ULEV1_INCR_CNT
, counter
, 0x00, 0x00, 0x00, 0x00 };
5822 for (uint8_t i
= 0; i
< 3; i
++) {
5823 increment_cmd
[i
+ 2] = (value
>> (8 * i
)) & 0xff;
5826 iso14a_card_select_t card
;
5827 if (ul_select(&card
) == false) {
5828 PrintAndLogEx(FAILED
, "failed to select card, exiting...");
5832 uint64_t tagtype
= GetHF14AMfU_Type();
5833 uint64_t tags_with_counter_ul
= MFU_TT_UL_EV1_48
| MFU_TT_UL_EV1_128
| MFU_TT_UL_EV1
;
5834 uint64_t tags_with_counter_ntag
= MFU_TT_NTAG_213
| MFU_TT_NTAG_213_F
| MFU_TT_NTAG_213_C
| MFU_TT_NTAG_213_TT
| MFU_TT_NTAG_215
| MFU_TT_NTAG_216
;
5835 if ((tagtype
& (tags_with_counter_ul
| tags_with_counter_ntag
)) == 0) {
5836 PrintAndLogEx(WARNING
, "tag type does not have counters");
5841 bool is_ntag
= (tagtype
& tags_with_counter_ntag
) != 0;
5842 if (is_ntag
&& (counter
!= 2)) {
5843 PrintAndLogEx(WARNING
, "NTAG only has one counter at index 2");
5848 uint8_t pack
[4] = { 0, 0, 0, 0 };
5850 if (ulev1_requestAuthentication(pwd
, pack
, sizeof(pack
)) == PM3_EWRONGANSWER
) {
5851 PrintAndLogEx(FAILED
, "authentication failed UL-EV1/NTAG");
5857 uint8_t current_counter
[3] = { 0, 0, 0 };
5858 int len
= ulev1_readCounter(counter
, current_counter
, sizeof(current_counter
));
5859 if (len
!= sizeof(current_counter
)) {
5860 PrintAndLogEx(FAILED
, "failed to read old counter");
5862 PrintAndLogEx(HINT
, "NTAG detected, try reading with PWD");
5868 uint32_t current_counter_num
= current_counter
[0] | (current_counter
[1] << 8) | (current_counter
[2] << 16);
5869 PrintAndLogEx(INFO
, "Current counter... " _GREEN_("%8d") " - " _GREEN_("%s"), current_counter_num
, sprint_hex(current_counter
, 3));
5871 if ((tagtype
& tags_with_counter_ntag
) != 0) {
5872 PrintAndLogEx(WARNING
, "NTAG detected, unable to manually increment counter");
5877 uint8_t resp
[1] = { 0x00 };
5878 if (ul_send_cmd_raw(increment_cmd
, sizeof(increment_cmd
), resp
, sizeof(resp
)) < 0) {
5879 PrintAndLogEx(FAILED
, "failed to increment counter");
5884 uint8_t new_counter
[3] = { 0, 0, 0 };
5885 int new_len
= ulev1_readCounter(counter
, new_counter
, sizeof(new_counter
));
5886 if (new_len
!= sizeof(current_counter
)) {
5887 PrintAndLogEx(FAILED
, "failed to read new counter");
5892 uint32_t new_counter_num
= new_counter
[0] | (new_counter
[1] << 8) | (new_counter
[2] << 16);
5893 PrintAndLogEx(INFO
, "New counter....... " _GREEN_("%8d") " - " _GREEN_("%s"), new_counter_num
, sprint_hex(new_counter
, 3));
5899 static command_t CommandTable
[] = {
5900 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
5901 {"list", CmdHF14AMfuList
, AlwaysAvailable
, "List MIFARE Ultralight / NTAG history"},
5902 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("recovery") " -------------------------"},
5903 {"keygen", CmdHF14AMfUKeyGen
, AlwaysAvailable
, "Generate DES/3DES/AES MIFARE diversified keys"},
5904 {"pwdgen", CmdHF14AMfUPwdGen
, AlwaysAvailable
, "Generate pwd from known algos"},
5905 {"otptear", CmdHF14AMfuOtpTearoff
, IfPm3Iso14443a
, "Tear-off test on OTP bits"},
5906 // {"tear_cnt", CmdHF14AMfuEv1CounterTearoff, IfPm3Iso14443a, "Tear-off test on Ev1/NTAG Counter bits"},
5907 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("operations") " -----------------------"},
5908 {"cauth", CmdHF14AMfUCAuth
, IfPm3Iso14443a
, "Ultralight-C - Authentication"},
5909 {"setpwd", CmdHF14AMfUCSetPwd
, IfPm3Iso14443a
, "Ultralight-C - Set 3DES key"},
5910 {"dump", CmdHF14AMfUDump
, IfPm3Iso14443a
, "Dump MIFARE Ultralight family tag to binary file"},
5911 {"incr", CmdHF14AMfUIncr
, IfPm3Iso14443a
, "Increments Ev1/NTAG counter"},
5912 {"info", CmdHF14AMfUInfo
, IfPm3Iso14443a
, "Tag information"},
5913 {"ndefread", CmdHF14MfuNDEFRead
, IfPm3Iso14443a
, "Prints NDEF records from card"},
5914 {"rdbl", CmdHF14AMfURdBl
, IfPm3Iso14443a
, "Read block"},
5915 {"restore", CmdHF14AMfURestore
, IfPm3Iso14443a
, "Restore a dump file onto a tag"},
5916 {"tamper", CmdHF14MfUTamper
, IfPm3Iso14443a
, "NTAG 213TT - Configure the tamper feature"},
5917 {"view", CmdHF14AMfuView
, AlwaysAvailable
, "Display content from tag dump file"},
5918 {"wipe", CmdHF14AMfuWipe
, IfPm3Iso14443a
, "Wipe card to zeros and default key"},
5919 {"wrbl", CmdHF14AMfUWrBl
, IfPm3Iso14443a
, "Write block"},
5920 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("simulation") " -----------------------"},
5921 {"eload", CmdHF14AMfUeLoad
, IfPm3Iso14443a
, "Upload file into emulator memory"},
5922 {"esave", CmdHF14AMfuESave
, IfPm3Iso14443a
, "Save emulator memory to file"},
5923 {"eview", CmdHF14AMfuEView
, IfPm3Iso14443a
, "View emulator memory"},
5924 {"sim", CmdHF14AMfUSim
, IfPm3Iso14443a
, "Simulate MIFARE Ultralight from emulator memory"},
5925 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("magic") " ----------------------------"},
5926 {"setuid", CmdHF14AMfUCSetUid
, IfPm3Iso14443a
, "Set UID - MAGIC tags only"},
5927 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("amiibo") " ----------------------------"},
5928 {"amiibo", CmdHF14AAmiibo
, IfPm3Iso14443a
, "Amiibo tag operations"},
5929 {NULL
, NULL
, NULL
, NULL
}
5932 static int CmdHelp(const char *Cmd
) {
5933 (void)Cmd
; // Cmd is not used so far
5934 CmdsHelp(CommandTable
);
5938 int CmdHFMFUltra(const char *Cmd
) {
5939 clearCommandBuffer();
5940 return CmdsParse(CommandTable
, Cmd
);