fix one too small
[RRG-proxmark3.git] / client / src / cmdhfst25ta.c
blob4298bde7d2418d9e4a28deafc09c79a6425251bb
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
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.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency ISO14443A / ST25TA commands
17 //-----------------------------------------------------------------------------
19 #include "cmdhfst25ta.h"
20 #include "cmdhfst.h"
21 #include <ctype.h>
22 #include "fileutils.h"
23 #include "cmdparser.h" // command_t
24 #include "comms.h" // clearCommandBuffer
25 #include "cmdtrace.h"
26 #include "cliparser.h"
27 #include "crc16.h"
28 #include "cmdhf14a.h"
29 #include "protocols.h" // definitions of ISO14A/7816 protocol
30 #include "iso7816/apduinfo.h" // GetAPDUCodeDescription
31 #include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
32 #include "cmdnfc.h" // print_type4_cc_info
33 #include "commonutil.h" // get_sw
34 #include "protocols.h" // ISO7816 APDU return codes
35 #include "crypto/libpcrypto.h" // ecdsa
37 #define TIMEOUT 2000
39 static int CmdHelp(const char *Cmd);
41 static bool st25ta_select(iso14a_card_select_t *card) {
43 clearCommandBuffer();
44 SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0);
45 PacketResponseNG resp;
46 if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
47 PrintAndLogEx(DEBUG, "iso14443a card select timeout");
48 DropField();
49 return false;
50 } else {
52 uint16_t len = (resp.oldarg[1] & 0xFFFF);
53 if (len == 0) {
54 PrintAndLogEx(DEBUG, "iso14443a card select failed");
55 DropField();
56 return false;
59 if (card) {
60 memcpy(card, resp.data.asBytes, sizeof(iso14a_card_select_t));
63 return true;
66 static void print_st25ta_system_info(uint8_t *d, uint8_t n) {
67 if (n < 0x12) {
68 PrintAndLogEx(WARNING, "Not enough bytes read from system file");
69 return;
72 PrintAndLogEx(NORMAL, "");
73 PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " -----------------------------");
75 PrintAndLogEx(SUCCESS, "Manufacture..... " _YELLOW_("%s"), getTagInfo(d[8]));
76 PrintAndLogEx(SUCCESS, "Product Code.... " _YELLOW_("%s"), get_st_chip_model(d[9]));
77 PrintAndLogEx(SUCCESS, "Device Serial... " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5));
79 if (d[2] != 0x80) {
81 PrintAndLogEx(SUCCESS, "GPO Config... 0x%02X", d[2]);
82 PrintAndLogEx(SUCCESS, " lock bit.... %s", ((d[2] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
84 uint8_t conf = (d[2] & 0x70) >> 4;
85 switch (conf) {
86 case 0:
87 break;
88 case 1:
89 PrintAndLogEx(SUCCESS, " Session opened");
90 break;
91 case 2:
92 PrintAndLogEx(SUCCESS, " WIP");
93 break;
94 case 3:
95 PrintAndLogEx(SUCCESS, " MIP");
96 break;
97 case 4:
98 PrintAndLogEx(SUCCESS, " Interrupt");
99 break;
100 case 5:
101 PrintAndLogEx(SUCCESS, " State Control");
102 break;
103 case 6:
104 PrintAndLogEx(SUCCESS, " RF Busy");
105 break;
106 case 7:
107 PrintAndLogEx(SUCCESS, " Field Detect");
108 break;
112 PrintAndLogEx(NORMAL, "");
113 PrintAndLogEx(SUCCESS, "Event counter config.... 0x%02X", d[3]);
114 PrintAndLogEx(SUCCESS, " config lock bit........ %s", ((d[3] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
115 PrintAndLogEx(SUCCESS, " counter................ %s", ((d[3] & 0x02) == 0x02) ? _RED_("enabled") : _GREEN_("disable"));
116 PrintAndLogEx(SUCCESS, " counter increment on... %s", ((d[3] & 0x01) == 0x01) ? _YELLOW_("write") : _YELLOW_("read"));
117 PrintAndLogEx(NORMAL, "");
119 uint16_t len = (d[0] << 8 | d[1]);
121 PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------------------------");
122 PrintAndLogEx(SUCCESS, " %s", sprint_hex_inrow(d, n));
123 PrintAndLogEx(SUCCESS, " %02X%02X................................ - Len ( %u bytes )", d[0], d[1], len);
125 if (d[2] == 0x80) {
126 PrintAndLogEx(SUCCESS, " ....%02X.............................. - ST reserved", d[2]);
127 } else {
128 PrintAndLogEx(SUCCESS, " ....%02X.............................. - GPO config", d[2]);
131 PrintAndLogEx(SUCCESS, " ......%02X............................ - Event counter config", d[3]);
133 uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]);
134 PrintAndLogEx(SUCCESS, " ........%02X%02X%02X...................... - 20 bit counter ( %u )", d[4], d[5], d[6], (counter & 0xFFFFF));
135 PrintAndLogEx(SUCCESS, " ..............%02X.................... - Product version", d[7]);
136 PrintAndLogEx(SUCCESS, " ................%s...... - UID", sprint_hex_inrow(d + 8, 7));
138 uint16_t mem = (d[0xF] << 8 | d[0x10]);
139 PrintAndLogEx(SUCCESS, " ..............................%02X%02X.. - Mem size - 1 ( %u bytes )", d[0xf], d[0x10], mem);
141 PrintAndLogEx(SUCCESS, " ..................................%02X - IC ref code", d[0x11]);
142 PrintAndLogEx(NORMAL, "");
145 0012
146 80000000001302E2007D0E8DCC
150 static int print_st25ta_signature(uint8_t *uid, uint8_t *signature) {
152 #define PUBLIC_ECDA_KEYLEN 33
153 // known public keys for the originality check (source: https://github.com/alexbatalov/node-nxp-originality-verifier)
154 // ref: AN11350 NTAG 21x Originality Signature Validation
155 // ref: AN11341 MIFARE Ultralight EV1 Originality Signature Validation
156 const ecdsa_publickey_t nxp_mfu_public_keys[] = {
157 {"NXP MIFARE Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
158 {"MIFARE Classic / QL88", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
159 {"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
160 {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
161 {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
162 {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
163 {"MIKRON Public key", "04F971EDA742A4A80D32DCF6A814A707CC3DC396D35902F72929FDCD698B3468F2"},
164 {"VivoKey Spark1 Public key", "04D64BB732C0D214E7EC580736ACF847284B502C25C0F7F2FA86AACE1DADA4387A"},
165 {"TruST25 (ST) key 01?", "041D92163650161A2548D33881C235D0FB2315C2C31A442F23C87ACF14497C0CBA"},
166 {"TruST25 (ST) key 04?", "04101E188A8B4CDDBC62D5BC3E0E6850F0C2730E744B79765A0E079907FBDB01BC"},
169 PrintAndLogEx(NORMAL, "");
170 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
172 for (uint8_t i = 0; i < ARRAYLEN(nxp_mfu_public_keys); i++) {
174 int dl = 0;
175 uint8_t key[PUBLIC_ECDA_KEYLEN] = {0};
176 param_gethex_to_eol(nxp_mfu_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl);
178 int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 7, signature, 32, true);
180 if (res == 0) {
181 PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_mfu_public_keys[i].desc);
182 PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value);
183 PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
184 PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
185 PrintAndLogEx(SUCCESS, " Signature verification ( " _GREEN_("successful") " )");
186 return PM3_SUCCESS;
189 return PM3_ESOFT;
192 static int st25ta_get_signature(uint8_t *signature) {
194 hf 14a raw -sck 0200A4040007D276000085010100
195 hf 14a raw -ck 0300A4000C020001
196 hf 14a raw -c 02a2b000e020
198 typedef struct {
199 const char *apdu;
200 uint8_t apdulen;
201 } transport_st25a_apdu_t;
203 transport_st25a_apdu_t cmds[] = {
204 { "\x00\xA4\x04\x00\x07\xD2\x76\x00\x00\x85\x01\x01\x00", 13 },
205 { "\x00\xA4\x00\x0C\x02\x00\x01", 7 },
206 { "\xa2\xb0\x00\xe0\x20", 5 },
209 uint8_t resp[40] = {0};
210 int resplen = 0;
211 bool activate_field = true;
213 for (uint8_t i = 0; i < ARRAYLEN(cmds); i++) {
214 int res = ExchangeAPDU14a((uint8_t *)cmds[i].apdu, cmds[i].apdulen, activate_field, true, resp, sizeof(resp), &resplen);
215 if (res != PM3_SUCCESS) {
216 DropField();
217 return res;
219 activate_field = false;
222 if (signature) {
223 memcpy(signature, resp, 32);
226 DropField();
227 return PM3_SUCCESS;
230 // ST25TA
231 static int infoHFST25TA(void) {
233 bool activate_field = true;
234 bool keep_field_on = true;
235 uint8_t response[PM3_CMD_DATA_SIZE];
236 int resplen = 0;
238 // --------------- Select NDEF Tag application ----------------
239 uint8_t aSELECT_AID[80];
240 int aSELECT_AID_n = 0;
241 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
242 int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
243 if (res != PM3_SUCCESS) {
244 DropField();
245 return res;
248 if (resplen < 2) {
249 DropField();
250 return PM3_ESOFT;
253 uint16_t sw = get_sw(response, resplen);
254 if (sw != ISO7816_OK) {
255 PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
256 DropField();
257 return PM3_ESOFT;
260 activate_field = false;
261 keep_field_on = true;
262 // --------------- CC file reading ----------------
264 uint8_t aSELECT_FILE_CC[30];
265 int aSELECT_FILE_CC_n = 0;
266 param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n);
267 res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
268 if (res != PM3_SUCCESS) {
269 DropField();
270 return res;
273 sw = get_sw(response, resplen);
274 if (sw != ISO7816_OK) {
275 PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
276 DropField();
277 return PM3_ESOFT;
280 uint8_t aREAD_CC[30];
281 int aREAD_CC_n = 0;
282 param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n);
283 res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
284 if (res != PM3_SUCCESS) {
285 DropField();
286 return res;
289 sw = get_sw(response, resplen);
290 if (sw != ISO7816_OK) {
291 PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
292 DropField();
293 return PM3_ESOFT;
295 // store st cc data for later
296 uint8_t st_cc_data[resplen - 2];
297 memcpy(st_cc_data, response, sizeof(st_cc_data));
299 // --------------- System file reading ----------------
300 uint8_t aSELECT_FILE_SYS[30];
301 int aSELECT_FILE_SYS_n = 0;
302 param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n);
303 res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
304 if (res != PM3_SUCCESS) {
305 DropField();
306 return res;
309 sw = get_sw(response, resplen);
310 if (sw != ISO7816_OK) {
311 PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
312 DropField();
313 return PM3_ESOFT;
316 keep_field_on = false;
318 uint8_t aREAD_SYS[30];
319 int aREAD_SYS_n = 0;
320 param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n);
321 res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
322 if (res != PM3_SUCCESS) {
323 DropField();
324 return res;
327 sw = get_sw(response, resplen);
328 if (sw != ISO7816_OK) {
329 PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
330 DropField();
331 return PM3_ESOFT;
334 PrintAndLogEx(NORMAL, "");
335 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
336 PrintAndLogEx(NORMAL, "");
337 iso14a_card_select_t card;
338 if (st25ta_select(&card)) {
339 uint8_t sig[32] = {0};
340 if (st25ta_get_signature(sig) == PM3_SUCCESS) {
341 print_st25ta_signature(card.uid, sig);
345 print_type4_cc_info(st_cc_data, sizeof(st_cc_data));
346 print_st25ta_system_info(response, resplen - 2);
348 return PM3_SUCCESS;
351 // menu command to get and print all info known about any known ST25TA tag
352 static int CmdHFST25TAInfo(const char *Cmd) {
353 CLIParserContext *ctx;
354 CLIParserInit(&ctx, "hf st25ta info",
355 "Get info about ST25TA tag",
356 "hf st25ta info"
359 void *argtable[] = {
360 arg_param_begin,
361 arg_param_end
363 CLIExecWithReturn(ctx, Cmd, argtable, true);
364 CLIParserFree(ctx);
365 return infoHFST25TA();
368 static int CmdHFST25TASim(const char *Cmd) {
369 int uidlen = 0;
370 uint8_t uid[7] = {0};
372 CLIParserContext *ctx;
373 CLIParserInit(&ctx, "hf st25ta sim",
374 "Emulating ST25TA512B tag with 7 byte UID",
375 "hf st25ta sim -u 02E2007D0FCA4C\n");
377 void *argtable[] = {
378 arg_param_begin,
379 arg_str1("u", "uid", "<hex>", "7 byte UID"),
380 arg_param_end
382 CLIExecWithReturn(ctx, Cmd, argtable, false);
383 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
384 CLIParserFree(ctx);
386 if (uidlen != 7) {
387 PrintAndLogEx(ERR, "UID must be 7 hex bytes");
388 return PM3_EINVARG;
391 char param[40];
392 snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen));
393 return CmdHF14ASim(param);
396 int CmdHFST25TANdefRead(const char *Cmd) {
397 int pwdlen = 0;
398 uint8_t pwd[16] = {0};
399 bool with_pwd = false;
401 CLIParserContext *ctx;
402 CLIParserInit(&ctx, "hf st25ta ndefread",
403 "Read NFC Data Exchange Format (NDEF) file on ST25TA",
404 "hf st25ta ndefread -p 82E80053D4CA5C0B656D852CC696C8A1\n"
405 "hf st25ta ndefread -f myfilename -> save raw NDEF to file"
408 void *argtable[] = {
409 arg_param_begin,
410 arg_str0("p", "pwd", "<hex>", "16 byte read password"),
411 arg_str0("f", "file", "<fn>", "save raw NDEF to file"),
412 arg_lit0("v", "verbose", "verbose output"),
413 arg_param_end
415 CLIExecWithReturn(ctx, Cmd, argtable, true);
416 CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen);
417 int fnlen = 0;
418 char filename[FILE_PATH_SIZE] = {0};
419 CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
420 bool verbose = arg_get_lit(ctx, 3);
421 CLIParserFree(ctx);
423 if (pwdlen == 0) {
424 with_pwd = false;
425 } else {
426 if (pwdlen != 16) {
427 PrintAndLogEx(ERR, "Password must be 16 hex bytes");
428 return PM3_EINVARG;
430 with_pwd = true;
433 bool activate_field = true;
434 bool keep_field_on = true;
435 uint8_t response[PM3_CMD_DATA_SIZE];
436 int resplen = 0;
438 // --------------- Select NDEF Tag application ----------------
439 uint8_t aSELECT_AID[80];
440 int aSELECT_AID_n = 0;
441 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
442 int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
443 if (res != PM3_SUCCESS) {
444 DropField();
445 return res;
448 if (resplen < 2) {
449 DropField();
450 return PM3_ESOFT;
453 uint16_t sw = get_sw(response, resplen);
454 if (sw != ISO7816_OK) {
455 PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
456 DropField();
457 return PM3_ESOFT;
460 activate_field = false;
461 keep_field_on = true;
463 // --------------- NDEF file reading ----------------
464 uint8_t aSELECT_FILE_NDEF[30];
465 int aSELECT_FILE_NDEF_n = 0;
466 param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
467 res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
468 if (res != PM3_SUCCESS) {
469 DropField();
470 return res;
473 sw = get_sw(response, resplen);
474 if (sw != ISO7816_OK) {
475 PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
476 DropField();
477 return PM3_ESOFT;
480 if (with_pwd) {
481 // --------------- VERIFY ----------------
482 uint8_t aVERIFY[30];
483 int aVERIFY_n = 0;
484 param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
485 res = ExchangeAPDU14a(aVERIFY, aVERIFY_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
486 if (res != PM3_SUCCESS) {
487 DropField();
488 return res;
491 sw = get_sw(response, resplen);
492 if (sw == 0x6300) {
493 // need to provide 16byte password
494 param_gethex_to_eol("0020000110", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
495 memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
496 res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
497 if (res != PM3_SUCCESS) {
498 DropField();
499 return res;
502 sw = get_sw(response, resplen);
503 if (sw != ISO7816_OK) {
504 PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
505 DropField();
506 return PM3_ESOFT;
511 keep_field_on = false;
512 uint8_t aREAD_NDEF[30];
513 int aREAD_NDEF_n = 0;
514 param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
515 res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
516 if (res != PM3_SUCCESS) {
517 DropField();
518 return res;
521 sw = get_sw(response, resplen);
522 if (sw != ISO7816_OK) {
523 PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
524 DropField();
525 return PM3_ESOFT;
528 NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose);
530 // get total NDEF length before save. If fails, we save it all
531 size_t n = 0;
532 if (NDEFGetTotalLength(response, resplen, &n) != PM3_SUCCESS)
533 n = resplen;
535 pm3_save_dump(filename, response + 2, n, jsfNDEF);
537 return PM3_SUCCESS;
540 static int CmdHFST25TAProtect(const char *Cmd) {
542 int pwdlen = 0;
543 uint8_t pwd[16] = {0};
544 int statelen = 3;
545 uint8_t state[3] = {0x26, 0, 0x02};
547 bool disable_protection = false;
548 bool enable_protection = false;
549 bool read_protection = false;
550 bool write_protection = false;
552 CLIParserContext *ctx;
553 CLIParserInit(&ctx, "hf st25ta protect",
554 "Change read or write protection for NFC Data Exchange Format (NDEF) file on ST25TA",
555 "hf st25ta protect -p 82E80053D4CA5C0B656D852CC696C8A1 -r -e -> enable read protection\n"
556 "hf st25ta protect -p 82E80053D4CA5C0B656D852CC696C8A1 -w -d -> disable write protection\n");
558 void *argtable[] = {
559 arg_param_begin,
560 arg_lit0("e", "enable", "enable protection"),
561 arg_lit0("d", "disable", "disable protection (default)"),
562 arg_lit0("r", "read", "change read protection"),
563 arg_lit0("w", "write", "change write protection (default)"),
564 arg_str1("p", "password", "<hex>", "16 byte write password"),
565 arg_param_end
567 CLIExecWithReturn(ctx, Cmd, argtable, false);
569 enable_protection = arg_get_lit(ctx, 1);
570 disable_protection = arg_get_lit(ctx, 2);
571 read_protection = arg_get_lit(ctx, 3);
572 write_protection = arg_get_lit(ctx, 4);
573 CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen);
574 CLIParserFree(ctx);
576 //Validations
577 if (enable_protection && disable_protection) {
578 PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both");
579 return PM3_EINVARG;
581 if (enable_protection) {
582 state[0] = 0x28;
584 if (disable_protection) {
585 state[0] = 0x26;
588 if (read_protection && write_protection) {
589 PrintAndLogEx(ERR, "Must specify either read or write protection, not both");
590 return PM3_EINVARG;
592 if (read_protection) {
593 state[2] = 0x01;
595 if (write_protection) {
596 state[2] = 0x02;
599 if (pwdlen != 16) {
600 PrintAndLogEx(ERR, "Missing 16 byte password");
601 return PM3_EINVARG;
604 bool activate_field = true;
605 bool keep_field_on = true;
606 uint8_t response[PM3_CMD_DATA_SIZE];
607 int resplen = 0;
609 // --------------- Select NDEF Tag application ----------------
610 uint8_t aSELECT_AID[80];
611 int aSELECT_AID_n = 0;
612 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
613 int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
614 if (res != PM3_SUCCESS) {
615 DropField();
616 return res;
619 if (resplen < 2) {
620 DropField();
621 return PM3_ESOFT;
624 uint16_t sw = get_sw(response, resplen);
625 if (sw != ISO7816_OK) {
626 PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
627 DropField();
628 return PM3_ESOFT;
631 activate_field = false;
632 keep_field_on = true;
634 // --------------- Select NDEF file ----------------
635 uint8_t aSELECT_FILE_NDEF[30];
636 int aSELECT_FILE_NDEF_n = 0;
637 param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
638 res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
639 if (res != PM3_SUCCESS) {
640 DropField();
641 return res;
644 sw = get_sw(response, resplen);
645 if (sw != ISO7816_OK) {
646 PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
647 DropField();
648 return PM3_ESOFT;
651 // --------------- VERIFY ----------------
652 uint8_t aVERIFY[30];
653 int aVERIFY_n = 0;
654 // need to provide 16byte password
655 param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
656 memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
657 res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
658 if (res != PM3_SUCCESS) {
659 DropField();
660 return res;
663 sw = get_sw(response, resplen);
664 if (sw != ISO7816_OK) {
665 PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
666 DropField();
667 return PM3_ESOFT;
670 // --------------- Change protection ----------------
671 keep_field_on = false;
672 uint8_t aPROTECT[30];
673 int aPROTECT_n = 0;
674 param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n);
675 memcpy(aPROTECT + aPROTECT_n, state, statelen);
676 res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen);
677 if (res != PM3_SUCCESS) {
678 DropField();
679 return res;
682 sw = get_sw(response, resplen);
683 if (sw != ISO7816_OK) {
684 PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
685 DropField();
686 return PM3_ESOFT;
689 PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"),
690 ((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled"));
692 return PM3_SUCCESS;
695 static int CmdHFST25TAPwd(const char *Cmd) {
697 int pwdlen = 0;
698 uint8_t pwd[16] = {0};
699 int newpwdlen = 0;
700 uint8_t newpwd[16] = {0};
701 int changePwdlen = 4;
702 uint8_t changePwd[4] = {0x24, 0x00, 0x01, 0x10};
703 bool change_read_password = false;
704 bool change_write_password = false;
706 CLIParserContext *ctx;
707 CLIParserInit(&ctx, "hf st25ta pwd",
708 "Change read or write password for NFC Data Exchange Format (NDEF) file on ST25TA",
709 "hf st25ta pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -r -n 00000000000000000000000000000000 -> change read password\n"
710 "hf st25ta pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -w -n 00000000000000000000000000000000 -> change write password\n");
712 void *argtable[] = {
713 arg_param_begin,
714 arg_lit0("r", "read", "change the read password (default)"),
715 arg_lit0("w", "write", "change the write password"),
716 arg_str1("p", "password", "<hex>", "current 16 byte write password"),
717 arg_str1("n", "new", "<hex>", "new 16 byte password"),
718 arg_param_end
720 CLIExecWithReturn(ctx, Cmd, argtable, false);
722 change_read_password = arg_get_lit(ctx, 1);
723 change_write_password = arg_get_lit(ctx, 2);
724 CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen);
725 CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen);
726 CLIParserFree(ctx);
728 if (change_read_password && change_write_password) {
729 PrintAndLogEx(ERR, "Must specify either read or write, not both");
730 return PM3_EINVARG;
732 if (change_read_password) {
733 changePwd[2] = 0x01;
735 if (change_write_password) {
736 changePwd[2] = 0x02;
739 if (pwdlen != 16) {
740 PrintAndLogEx(ERR, "Original write password must be 16 hex bytes");
741 return PM3_EINVARG;
743 if (newpwdlen != 16) {
744 PrintAndLogEx(ERR, "New password must be 16 hex bytes");
745 return PM3_EINVARG;
748 bool activate_field = true;
749 bool keep_field_on = true;
750 uint8_t response[PM3_CMD_DATA_SIZE];
751 int resplen = 0;
753 // --------------- Select NDEF Tag application ----------------
754 uint8_t aSELECT_AID[80];
755 int aSELECT_AID_n = 0;
756 param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
757 int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
758 if (res != PM3_SUCCESS) {
759 DropField();
760 return res;
763 if (resplen < 2) {
764 DropField();
765 return PM3_ESOFT;
768 uint16_t sw = get_sw(response, resplen);
769 if (sw != ISO7816_OK) {
770 PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
771 DropField();
772 return PM3_ESOFT;
775 activate_field = false;
776 keep_field_on = true;
778 // --------------- Select NDEF file ----------------
779 uint8_t aSELECT_FILE_NDEF[30];
780 int aSELECT_FILE_NDEF_n = 0;
781 param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
782 res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
783 if (res != PM3_SUCCESS) {
784 DropField();
785 return res;
788 sw = get_sw(response, resplen);
789 if (sw != ISO7816_OK) {
790 PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
791 DropField();
792 return PM3_ESOFT;
795 // --------------- VERIFY ----------------
796 uint8_t aVERIFY[30];
797 int aVERIFY_n = 0;
798 // need to provide 16byte password
799 param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
800 memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
801 res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
802 if (res != PM3_SUCCESS) {
803 DropField();
804 return res;
807 sw = get_sw(response, resplen);
808 if (sw != ISO7816_OK) {
809 PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
810 DropField();
811 return PM3_ESOFT;
814 // --------------- Change password ----------------
816 keep_field_on = false;
817 uint8_t aCHG_PWD[30];
818 int aCHG_PWD_n = 0;
819 param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n);
820 memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen);
821 memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen);
822 res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
823 if (res != PM3_SUCCESS) {
824 DropField();
825 return res;
828 sw = get_sw(response, resplen);
829 if (sw != ISO7816_OK) {
830 PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
831 DropField();
832 return PM3_ESOFT;
834 PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"));
835 return PM3_SUCCESS;
838 static int CmdHFST25TAList(const char *Cmd) {
839 return CmdTraceListAlias(Cmd, "hf st25ta", "7816");
842 static command_t CommandTable[] = {
843 {"help", CmdHelp, AlwaysAvailable, "This help"},
844 {"info", CmdHFST25TAInfo, IfPm3Iso14443a, "Tag information"},
845 {"list", CmdHFST25TAList, AlwaysAvailable, "List ISO 14443A/7816 history"},
846 {"ndefread", CmdHFST25TANdefRead, AlwaysAvailable, "read NDEF file on tag"},
847 {"protect", CmdHFST25TAProtect, IfPm3Iso14443a, "change protection on tag"},
848 {"pwd", CmdHFST25TAPwd, IfPm3Iso14443a, "change password on tag"},
849 {"sim", CmdHFST25TASim, IfPm3Iso14443a, "Fake ISO 14443A/ST tag"},
850 {NULL, NULL, NULL, NULL}
853 static int CmdHelp(const char *Cmd) {
854 (void)Cmd; // Cmd is not used so far
855 CmdsHelp(CommandTable);
856 return PM3_SUCCESS;
859 int CmdHFST25TA(const char *Cmd) {
860 clearCommandBuffer();
861 return CmdsParse(CommandTable, Cmd);