fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdhfst25ta.c
blobaa737304c13a66d81c8ee7e9b4b26068c0f19723
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2020 iceman1001
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // High frequency ISO14443A / ST25TA commands
9 //-----------------------------------------------------------------------------
11 #include "cmdhfst25ta.h"
12 #include "cmdhfst.h"
13 #include <ctype.h>
14 #include "fileutils.h"
15 #include "cmdparser.h" // command_t
16 #include "comms.h" // clearCommandBuffer
17 #include "cmdtrace.h"
18 #include "cliparser.h"
19 #include "crc16.h"
20 #include "cmdhf14a.h"
21 #include "protocols.h" // definitions of ISO14A/7816 protocol
22 #include "iso7816/apduinfo.h" // GetAPDUCodeDescription
23 #include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
24 #include "cmdnfc.h" // print_type4_cc_info
26 #define TIMEOUT 2000
28 static int CmdHelp(const char *Cmd);
30 static void print_st25ta_system_info(uint8_t *d, uint8_t n) {
31 if (n < 0x12) {
32 PrintAndLogEx(WARNING, "Not enough bytes read from system file");
33 return;
36 PrintAndLogEx(NORMAL, "");
37 PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " ------------");
39 uint16_t len = (d[0] << 8 | d[1]);
40 PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%04X") ")", len, len);
42 if (d[2] == 0x80) {
43 PrintAndLogEx(SUCCESS, " ST reserved ( 0x%02X )", d[2]);
44 } else {
45 PrintAndLogEx(SUCCESS, " GPO Config ( 0x%02X )", d[2]);
46 PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[2] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
47 uint8_t conf = (d[2] & 0x70) >> 4;
48 switch (conf) {
49 case 0:
50 PrintAndLogEx(SUCCESS, "");
51 break;
52 case 1:
53 PrintAndLogEx(SUCCESS, "Session opened");
54 break;
55 case 2:
56 PrintAndLogEx(SUCCESS, "WIP");
57 break;
58 case 3:
59 PrintAndLogEx(SUCCESS, "MIP");
60 break;
61 case 4:
62 PrintAndLogEx(SUCCESS, "Interrupt");
63 break;
64 case 5:
65 PrintAndLogEx(SUCCESS, "State Control");
66 break;
67 case 6:
68 PrintAndLogEx(SUCCESS, "RF Busy");
69 break;
70 case 7:
71 PrintAndLogEx(SUCCESS, "Field Detect");
72 break;
76 PrintAndLogEx(SUCCESS, " Event counter config ( 0x%02X )", d[3]);
77 PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[3] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
78 PrintAndLogEx(SUCCESS, " counter ( %s )", ((d[3] & 0x02) == 0x02) ? _RED_("enabled") : _GREEN_("disable"));
79 PrintAndLogEx(SUCCESS, " counter increment on ( %s )", ((d[3] & 0x01) == 0x01) ? _YELLOW_("write") : _YELLOW_("read"));
81 uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]);
82 PrintAndLogEx(SUCCESS, " 20bit counter ( 0x%05X )", counter & 0xFFFFF);
84 PrintAndLogEx(SUCCESS, " Product version ( 0x%02X )", d[7]);
86 PrintAndLogEx(SUCCESS, " UID " _GREEN_("%s"), sprint_hex_inrow(d + 8, 7));
87 PrintAndLogEx(SUCCESS, " MFG 0x%02X, " _YELLOW_("%s"), d[8], getTagInfo(d[8]));
88 PrintAndLogEx(SUCCESS, " Product Code 0x%02X, " _YELLOW_("%s"), d[9], get_st_chip_model(d[9]));
89 PrintAndLogEx(SUCCESS, " Device# " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5));
91 uint16_t mem = (d[0xF] << 8 | d[0x10]);
92 PrintAndLogEx(SUCCESS, " Memory Size - 1 %u bytes (" _GREEN_("0x%04X") ")", mem, mem);
94 PrintAndLogEx(SUCCESS, " IC Reference code %u ( 0x%02X )", d[0x12], d[0x12]);
96 PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------");
97 PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n));
98 PrintAndLogEx(NORMAL, "");
101 0012
102 80000000001302E2007D0E8DCC
106 static uint16_t get_sw(uint8_t *d, uint8_t n) {
107 if (n < 2)
108 return 0;
110 n -= 2;
111 return d[n] * 0x0100 + d[n + 1];
114 // ST25TA
115 static int infoHFST25TA(void) {
117 bool activate_field = true;
118 bool keep_field_on = true;
119 uint8_t response[PM3_CMD_DATA_SIZE];
120 int resplen = 0;
122 // --------------- Select NDEF Tag application ----------------
123 uint8_t aSELECT_AID[80];
124 int aSELECT_AID_n = 0;
125 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
126 int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
127 if (res != PM3_SUCCESS) {
128 DropField();
129 return res;
132 if (resplen < 2) {
133 DropField();
134 return PM3_ESOFT;
137 uint16_t sw = get_sw(response, resplen);
138 if (sw != 0x9000) {
139 PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
140 DropField();
141 return PM3_ESOFT;
144 activate_field = false;
145 keep_field_on = true;
146 // --------------- CC file reading ----------------
148 uint8_t aSELECT_FILE_CC[30];
149 int aSELECT_FILE_CC_n = 0;
150 param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n);
151 res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
152 if (res != PM3_SUCCESS) {
153 DropField();
154 return res;
157 sw = get_sw(response, resplen);
158 if (sw != 0x9000) {
159 PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
160 DropField();
161 return PM3_ESOFT;
164 uint8_t aREAD_CC[30];
165 int aREAD_CC_n = 0;
166 param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n);
167 res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
168 if (res != PM3_SUCCESS) {
169 DropField();
170 return res;
173 sw = get_sw(response, resplen);
174 if (sw != 0x9000) {
175 PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
176 DropField();
177 return PM3_ESOFT;
179 // store st cc data for later
180 uint8_t st_cc_data[resplen - 2];
181 memcpy(st_cc_data, response, sizeof(st_cc_data));
183 // --------------- System file reading ----------------
184 uint8_t aSELECT_FILE_SYS[30];
185 int aSELECT_FILE_SYS_n = 0;
186 param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n);
187 res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
188 if (res != PM3_SUCCESS) {
189 DropField();
190 return res;
193 sw = get_sw(response, resplen);
194 if (sw != 0x9000) {
195 PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
196 DropField();
197 return PM3_ESOFT;
200 keep_field_on = false;
202 uint8_t aREAD_SYS[30];
203 int aREAD_SYS_n = 0;
204 param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n);
205 res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
206 if (res != PM3_SUCCESS) {
207 DropField();
208 return res;
211 sw = get_sw(response, resplen);
212 if (sw != 0x9000) {
213 PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
214 DropField();
215 return PM3_ESOFT;
220 PrintAndLogEx(NORMAL, "");
221 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
222 PrintAndLogEx(NORMAL, "");
223 print_type4_cc_info(st_cc_data, sizeof(st_cc_data));
224 print_st25ta_system_info(response, resplen - 2);
225 return PM3_SUCCESS;
228 // menu command to get and print all info known about any known ST25TA tag
229 static int CmdHFST25TAInfo(const char *Cmd) {
230 CLIParserContext *ctx;
231 CLIParserInit(&ctx, "hf st25ta info",
232 "Get info about ST25TA tag",
233 "hf st25ta info"
236 void *argtable[] = {
237 arg_param_begin,
238 arg_param_end
240 CLIExecWithReturn(ctx, Cmd, argtable, true);
241 CLIParserFree(ctx);
242 return infoHFST25TA();
245 static int CmdHFST25TASim(const char *Cmd) {
246 int uidlen = 0;
247 uint8_t uid[7] = {0};
249 CLIParserContext *ctx;
250 CLIParserInit(&ctx, "hf st25ta sim",
251 "Emulating ST25TA512B tag with 7 byte UID",
252 "hf st25ta sim -u 02E2007D0FCA4C\n");
254 void *argtable[] = {
255 arg_param_begin,
256 arg_str1("u", "uid", "<hex>", "7 byte UID"),
257 arg_param_end
259 CLIExecWithReturn(ctx, Cmd, argtable, false);
260 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
261 CLIParserFree(ctx);
263 if (uidlen != 7) {
264 PrintAndLogEx(ERR, "UID must be 7 hex bytes");
265 return PM3_EINVARG;
268 char param[40];
269 snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen));
270 return CmdHF14ASim(param);
273 int CmdHFST25TANdefRead(const char *Cmd) {
274 int pwdlen = 0;
275 uint8_t pwd[16] = {0};
276 bool with_pwd = false;
278 CLIParserContext *ctx;
279 CLIParserInit(&ctx, "hf st25ta ndefread",
280 "Read NFC Data Exchange Format (NDEF) file on ST25TA",
281 "hf st25ta ndefread -p 82E80053D4CA5C0B656D852CC696C8A1\n");
283 void *argtable[] = {
284 arg_param_begin,
285 arg_str0("p", "pwd", "<hex>", "16 byte read password"),
286 arg_param_end
288 CLIExecWithReturn(ctx, Cmd, argtable, true);
289 CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen);
290 CLIParserFree(ctx);
292 if (pwdlen == 0) {
293 with_pwd = false;
294 } else {
295 if (pwdlen != 16) {
296 PrintAndLogEx(ERR, "Password must be 16 hex bytes");
297 return PM3_EINVARG;
299 with_pwd = true;
302 bool activate_field = true;
303 bool keep_field_on = true;
304 uint8_t response[PM3_CMD_DATA_SIZE];
305 int resplen = 0;
307 // --------------- Select NDEF Tag application ----------------
308 uint8_t aSELECT_AID[80];
309 int aSELECT_AID_n = 0;
310 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
311 int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
312 if (res != PM3_SUCCESS) {
313 DropField();
314 return res;
317 if (resplen < 2) {
318 DropField();
319 return PM3_ESOFT;
322 uint16_t sw = get_sw(response, resplen);
323 if (sw != 0x9000) {
324 PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
325 DropField();
326 return PM3_ESOFT;
329 activate_field = false;
330 keep_field_on = true;
332 // --------------- NDEF file reading ----------------
333 uint8_t aSELECT_FILE_NDEF[30];
334 int aSELECT_FILE_NDEF_n = 0;
335 param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
336 res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
337 if (res != PM3_SUCCESS) {
338 DropField();
339 return res;
342 sw = get_sw(response, resplen);
343 if (sw != 0x9000) {
344 PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
345 DropField();
346 return PM3_ESOFT;
349 if (with_pwd) {
350 // --------------- VERIFY ----------------
351 uint8_t aVERIFY[30];
352 int aVERIFY_n = 0;
353 param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
354 res = ExchangeAPDU14a(aVERIFY, aVERIFY_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
355 if (res != PM3_SUCCESS) {
356 DropField();
357 return res;
360 sw = get_sw(response, resplen);
361 if (sw == 0x6300) {
362 // need to provide 16byte password
363 param_gethex_to_eol("0020000110", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
364 memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
365 res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
366 if (res != PM3_SUCCESS) {
367 DropField();
368 return res;
371 sw = get_sw(response, resplen);
372 if (sw != 0x9000) {
373 PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
374 DropField();
375 return PM3_ESOFT;
380 keep_field_on = false;
381 uint8_t aREAD_NDEF[30];
382 int aREAD_NDEF_n = 0;
383 param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
384 res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
385 if (res != PM3_SUCCESS) {
386 DropField();
387 return res;
390 sw = get_sw(response, resplen);
391 if (sw != 0x9000) {
392 PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
393 DropField();
394 return PM3_ESOFT;
397 NDEFRecordsDecodeAndPrint(response + 2, resplen - 4);
398 return PM3_SUCCESS;
401 static int CmdHFST25TAProtect(const char *Cmd) {
403 int pwdlen = 0;
404 uint8_t pwd[16] = {0};
405 int statelen = 3;
406 uint8_t state[3] = {0x26, 0, 0x02};
408 bool disable_protection = false;
409 bool enable_protection = false;
410 bool read_protection = false;
411 bool write_protection = false;
413 CLIParserContext *ctx;
414 CLIParserInit(&ctx, "hf st25ta protect",
415 "Change read or write protection for NFC Data Exchange Format (NDEF) file on ST25TA",
416 "hf st25ta protect -p 82E80053D4CA5C0B656D852CC696C8A1 -r -e -> enable read protection\n"
417 "hf st25ta protect -p 82E80053D4CA5C0B656D852CC696C8A1 -w -d -> disable write protection\n");
419 void *argtable[] = {
420 arg_param_begin,
421 arg_lit0("e", "enable", "enable protection"),
422 arg_lit0("d", "disable", "disable protection (default)"),
423 arg_lit0("r", "read", "change read protection"),
424 arg_lit0("w", "write", "change write protection (default)"),
425 arg_str1("p", "password", "<hex>", "16 byte write password"),
426 arg_param_end
428 CLIExecWithReturn(ctx, Cmd, argtable, false);
430 enable_protection = arg_get_lit(ctx, 1);
431 disable_protection = arg_get_lit(ctx, 2);
432 read_protection = arg_get_lit(ctx, 3);
433 write_protection = arg_get_lit(ctx, 4);
434 CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen);
435 CLIParserFree(ctx);
437 //Validations
438 if (enable_protection && disable_protection) {
439 PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both");
440 return PM3_EINVARG;
442 if (enable_protection) {
443 state[0] = 0x28;
445 if (disable_protection) {
446 state[0] = 0x26;
449 if (read_protection && write_protection) {
450 PrintAndLogEx(ERR, "Must specify either read or write protection, not both");
451 return PM3_EINVARG;
453 if (read_protection) {
454 state[2] = 0x01;
456 if (write_protection) {
457 state[2] = 0x02;
460 if (pwdlen != 16) {
461 PrintAndLogEx(ERR, "Missing 16 byte password");
462 return PM3_EINVARG;
465 bool activate_field = true;
466 bool keep_field_on = true;
467 uint8_t response[PM3_CMD_DATA_SIZE];
468 int resplen = 0;
470 // --------------- Select NDEF Tag application ----------------
471 uint8_t aSELECT_AID[80];
472 int aSELECT_AID_n = 0;
473 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
474 int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
475 if (res != PM3_SUCCESS) {
476 DropField();
477 return res;
480 if (resplen < 2) {
481 DropField();
482 return PM3_ESOFT;
485 uint16_t sw = get_sw(response, resplen);
486 if (sw != 0x9000) {
487 PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
488 DropField();
489 return PM3_ESOFT;
492 activate_field = false;
493 keep_field_on = true;
495 // --------------- Select NDEF file ----------------
496 uint8_t aSELECT_FILE_NDEF[30];
497 int aSELECT_FILE_NDEF_n = 0;
498 param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
499 res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
500 if (res != PM3_SUCCESS) {
501 DropField();
502 return res;
505 sw = get_sw(response, resplen);
506 if (sw != 0x9000) {
507 PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
508 DropField();
509 return PM3_ESOFT;
512 // --------------- VERIFY ----------------
513 uint8_t aVERIFY[30];
514 int aVERIFY_n = 0;
515 // need to provide 16byte password
516 param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
517 memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
518 res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
519 if (res != PM3_SUCCESS) {
520 DropField();
521 return res;
524 sw = get_sw(response, resplen);
525 if (sw != 0x9000) {
526 PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
527 DropField();
528 return PM3_ESOFT;
531 // --------------- Change protection ----------------
532 keep_field_on = false;
533 uint8_t aPROTECT[30];
534 int aPROTECT_n = 0;
535 param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n);
536 memcpy(aPROTECT + aPROTECT_n, state, statelen);
537 res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen);
538 if (res != PM3_SUCCESS) {
539 DropField();
540 return res;
543 sw = get_sw(response, resplen);
544 if (sw != 0x9000) {
545 PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
546 DropField();
547 return PM3_ESOFT;
550 PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"),
551 ((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled"));
553 return PM3_SUCCESS;
556 static int CmdHFST25TAPwd(const char *Cmd) {
558 int pwdlen = 0;
559 uint8_t pwd[16] = {0};
560 int newpwdlen = 0;
561 uint8_t newpwd[16] = {0};
562 int changePwdlen = 4;
563 uint8_t changePwd[4] = {0x24, 0x00, 0x01, 0x10};
564 bool change_read_password = false;
565 bool change_write_password = false;
567 CLIParserContext *ctx;
568 CLIParserInit(&ctx, "hf st25ta pwd",
569 "Change read or write password for NFC Data Exchange Format (NDEF) file on ST25TA",
570 "hf st25ta pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -r -n 00000000000000000000000000000000 -> change read password\n"
571 "hf st25ta pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -w -n 00000000000000000000000000000000 -> change write password\n");
573 void *argtable[] = {
574 arg_param_begin,
575 arg_lit0("r", "read", "change the read password (default)"),
576 arg_lit0("w", "write", "change the write password"),
577 arg_str1("p", "password", "<hex>", "current 16 byte write password"),
578 arg_str1("n", "new", "<hex>", "new 16 byte password"),
579 arg_param_end
581 CLIExecWithReturn(ctx, Cmd, argtable, false);
583 change_read_password = arg_get_lit(ctx, 1);
584 change_write_password = arg_get_lit(ctx, 2);
585 CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen);
586 CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen);
587 CLIParserFree(ctx);
589 if (change_read_password && change_write_password) {
590 PrintAndLogEx(ERR, "Must specify either read or write, not both");
591 return PM3_EINVARG;
593 if (change_read_password) {
594 changePwd[2] = 0x01;
596 if (change_write_password) {
597 changePwd[2] = 0x02;
600 if (pwdlen != 16) {
601 PrintAndLogEx(ERR, "Original write password must be 16 hex bytes");
602 return PM3_EINVARG;
604 if (newpwdlen != 16) {
605 PrintAndLogEx(ERR, "New password must be 16 hex bytes");
606 return PM3_EINVARG;
609 bool activate_field = true;
610 bool keep_field_on = true;
611 uint8_t response[PM3_CMD_DATA_SIZE];
612 int resplen = 0;
614 // --------------- Select NDEF Tag application ----------------
615 uint8_t aSELECT_AID[80];
616 int aSELECT_AID_n = 0;
617 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
618 int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
619 if (res != PM3_SUCCESS) {
620 DropField();
621 return res;
624 if (resplen < 2) {
625 DropField();
626 return PM3_ESOFT;
629 uint16_t sw = get_sw(response, resplen);
630 if (sw != 0x9000) {
631 PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
632 DropField();
633 return PM3_ESOFT;
636 activate_field = false;
637 keep_field_on = true;
639 // --------------- Select NDEF file ----------------
640 uint8_t aSELECT_FILE_NDEF[30];
641 int aSELECT_FILE_NDEF_n = 0;
642 param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
643 res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
644 if (res != PM3_SUCCESS) {
645 DropField();
646 return res;
649 sw = get_sw(response, resplen);
650 if (sw != 0x9000) {
651 PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
652 DropField();
653 return PM3_ESOFT;
656 // --------------- VERIFY ----------------
657 uint8_t aVERIFY[30];
658 int aVERIFY_n = 0;
659 // need to provide 16byte password
660 param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
661 memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
662 res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
663 if (res != PM3_SUCCESS) {
664 DropField();
665 return res;
668 sw = get_sw(response, resplen);
669 if (sw != 0x9000) {
670 PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
671 DropField();
672 return PM3_ESOFT;
675 // --------------- Change password ----------------
677 keep_field_on = false;
678 uint8_t aCHG_PWD[30];
679 int aCHG_PWD_n = 0;
680 param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n);
681 memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen);
682 memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen);
683 res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
684 if (res != PM3_SUCCESS) {
685 DropField();
686 return res;
689 sw = get_sw(response, resplen);
690 if (sw != 0x9000) {
691 PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
692 DropField();
693 return PM3_ESOFT;
695 PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"));
696 return PM3_SUCCESS;
699 static int CmdHFST25TAList(const char *Cmd) {
700 return CmdTraceListAlias(Cmd, "hf st25ta", "7816");
703 static command_t CommandTable[] = {
704 {"help", CmdHelp, AlwaysAvailable, "This help"},
705 {"info", CmdHFST25TAInfo, IfPm3Iso14443a, "Tag information"},
706 {"list", CmdHFST25TAList, AlwaysAvailable, "List ISO 14443A/7816 history"},
707 {"ndefread", CmdHFST25TANdefRead, AlwaysAvailable, "read NDEF file on tag"},
708 {"protect", CmdHFST25TAProtect, IfPm3Iso14443a, "change protection on tag"},
709 {"pwd", CmdHFST25TAPwd, IfPm3Iso14443a, "change password on tag"},
710 {"sim", CmdHFST25TASim, IfPm3Iso14443a, "Fake ISO 14443A/ST tag"},
711 {NULL, NULL, NULL, NULL}
714 static int CmdHelp(const char *Cmd) {
715 (void)Cmd; // Cmd is not used so far
716 CmdsHelp(CommandTable);
717 return PM3_SUCCESS;
720 int CmdHFST25TA(const char *Cmd) {
721 clearCommandBuffer();
722 return CmdsParse(CommandTable, Cmd);