Merge pull request #2654 from Antiklesys/master
[RRG-proxmark3.git] / client / src / cmdhfntag424.c
blob9e4abeed2fb483874d701d777972a5ec3606d484
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 / NTAG424 DNA Commands
17 //-----------------------------------------------------------------------------
19 #include "cmdhfntag424.h"
20 #include <ctype.h>
21 #include "cmdparser.h"
22 #include "commonutil.h"
23 #include "comms.h"
24 #include "iso7816/apduinfo.h"
25 #include "protocols.h"
26 #include "cliparser.h"
27 #include "cmdmain.h"
28 #include "fileutils.h" // saveFile
29 #include "crypto/libpcrypto.h" // aes_decode
30 #include "cmac.h"
31 #include "cmdhf14a.h"
32 #include "ui.h"
33 #include "util.h"
34 #include "crc32.h"
35 #include "cmdhfmfdes.h"
37 #define NTAG424_MAX_BYTES 412
40 // NTAG424 commands currently implemented
41 // icenam: should be able to use 14a / msdes to annotate NTAG424 communications
42 #define NTAG424_CMD_GET_FILE_SETTINGS 0xF5
43 #define NTAG424_CMD_CHANGE_FILE_SETTINGS 0x5F
44 #define NTAG424_CMD_CHANGE_KEY 0xC4
45 #define NTAG424_CMD_READ_DATA 0xAD
46 #define NTAG424_CMD_WRITE_DATA 0x8D
47 #define NTAG424_CMD_AUTHENTICATE_EV2_FIRST 0x71
48 #define NTAG424_CMD_MORE_DATA 0xAF
49 #define NTAG424_CMD_GET_VERSION 0x60
50 #define NTAG424_CMD_GET_SIGNATURE 0x3C
53 // Original from https://github.com/rfidhacking/node-sdm/
55 typedef struct sdm_picc_s {
56 uint8_t tag;
57 uint8_t uid[7];
58 uint8_t cnt[3];
59 uint32_t cnt_int;
60 } sdm_picc_t;
62 // -------------- Encryption structs ---------------------------
63 typedef struct {
64 uint8_t ti[4];
65 uint8_t rnd_a[16];
66 uint8_t pd_cap2[6];
67 uint8_t pcd_cap2[6];
68 } ntag424_ev2_response_t;
70 typedef struct {
71 uint16_t command_counter;
72 uint8_t ti[4];
73 uint8_t encryption[16];
74 uint8_t mac[16];
75 } ntag424_session_keys_t;
77 typedef enum {
78 COMM_PLAIN,
79 COMM_MAC,
80 COMM_FULL
81 } ntag424_communication_mode_t;
83 const CLIParserOption ntag424_communication_mode_options[] = {
84 {COMM_PLAIN, "plain"},
85 {COMM_MAC, "mac"},
86 {COMM_FULL, "encrypt"},
87 {0, NULL},
90 // -------------- File settings structs -------------------------
91 // Enabling this bit in the settings will also reset the read counter to 0
92 #define FILE_SETTINGS_OPTIONS_SDM_AND_MIRRORING (1 << 6)
94 #define FILE_SETTINGS_SDM_OPTIONS_UID (1 << 7)
95 #define FILE_SETTINGS_SDM_OPTIONS_SDM_READ_COUNTER (1 << 6)
96 #define FILE_SETTINGS_SDM_OPTIONS_SDM_READ_COUNTER_LIMIT (1 << 5)
97 #define FILE_SETTINGS_SDM_OPTIONS_SDM_ENC_FILE_DATA (1 << 4)
98 #define FILE_SETTINGS_SDM_OPTIONS_ENCODING_MODE_ASCII (1 << 0)
100 typedef struct {
101 uint8_t sdm_options;
102 uint8_t sdm_access[2];
103 uint8_t sdm_data[8][3];
104 } ntag424_file_sdm_settings_t;
106 typedef struct {
107 uint8_t type;
108 uint8_t options;
109 uint8_t access[2];
110 uint8_t size[3];
111 ntag424_file_sdm_settings_t optional_sdm_settings;
112 } ntag424_file_settings_t;
114 #define SETTINGS_WITHOUT_SDM_DATA_SIZE (1+1+2+3+1+2)
116 // A different struct is used when actually writing the settings back,
117 // since we obviously can't change the size or type of a static file.
118 typedef struct {
119 uint8_t options;
120 uint8_t access[2];
121 ntag424_file_sdm_settings_t optional_sdm_settings;
122 } file_settings_write_t;
124 // -------------- Version information structs -------------------------
125 typedef struct {
126 uint8_t vendor_id;
127 uint8_t type;
128 uint8_t sub_type;
129 uint8_t major_version;
130 uint8_t minor_version;
131 uint8_t storage_size;
132 uint8_t protocol;
133 } PACKED ntag424_version_information_t;
135 typedef struct {
136 uint8_t uid[7];
137 uint8_t batch[4];
138 uint8_t fab_key_high : 4;
139 uint8_t batchno : 4;
140 uint8_t week_prod : 7;
141 uint8_t fab_key_low : 1;
142 uint8_t year_prod;
143 } PACKED ntag424_production_information_t;
145 typedef struct {
146 ntag424_version_information_t hardware;
147 ntag424_version_information_t software;
148 ntag424_production_information_t production;
149 } ntag424_full_version_information_t;
152 static void ntag424_print_version_information(ntag424_version_information_t *version) {
153 PrintAndLogEx(INFO, " vendor id: " _GREEN_("%02X"), version->vendor_id);
154 PrintAndLogEx(INFO, " type: " _GREEN_("%02X"), version->type);
155 PrintAndLogEx(INFO, " sub type: " _GREEN_("%02X"), version->sub_type);
156 PrintAndLogEx(INFO, " version: " _GREEN_("%d.%d"), version->major_version, version->minor_version);
157 PrintAndLogEx(INFO, "storage size: " _GREEN_("%02X"), version->storage_size);
158 PrintAndLogEx(INFO, " protocol: " _GREEN_("%02X"), version->protocol);
161 static void ntag424_print_production_information(ntag424_production_information_t *version) {
162 PrintAndLogEx(INFO, " uid: " _GREEN_("%s"), sprint_hex(version->uid, sizeof(version->uid)));
163 PrintAndLogEx(INFO, " batch: " _GREEN_("%s"), sprint_hex(version->batch, sizeof(version->batch)));
164 PrintAndLogEx(INFO, " batchno: " _GREEN_("%02X"), version->batchno);
165 PrintAndLogEx(INFO, " fab key: " _GREEN_("%02X"), (version->fab_key_high << 1) | version->fab_key_low);
166 PrintAndLogEx(INFO, " date: week " _GREEN_("%02X") " / " _GREEN_("20%02X"), version->week_prod, version->year_prod);
169 static void ntag424_print_full_version_information(ntag424_full_version_information_t *version) {
170 PrintAndLogEx(INFO, "--- " _CYAN_("Hardware version information:"));
171 ntag424_print_version_information(&version->hardware);
173 PrintAndLogEx(INFO, "--- " _CYAN_("Software version information:"));
174 ntag424_print_version_information(&version->software);
176 PrintAndLogEx(INFO, "--- " _CYAN_("Production information:"));
177 ntag424_print_production_information(&version->production);
180 // Currently unused functions, commented out due to -Wunused-function
181 /*static void ntag424_file_settings_set_access_rights(ntag424_file_settings_t *settings,
182 uint8_t read_write_key, uint8_t change_key,
183 uint8_t read_key, uint8_t write_key)
186 settings->access[0] = read_write_key << 4 | change_key;
187 settings->access[1] = read_key << 4 | write_key;
190 // Currently unused functions, commented out due to -Wunused-function
191 /*static void ntag424_file_settings_set_sdm_access_rights(ntag424_file_settings_t *settings,
192 uint8_t sdm_meta_read, uint8_t sdm_file_read, uint8_t sdm_ctr_ret)
194 settings->optional_sdm_settings.sdm_access[1] = sdm_meta_read << 4 | sdm_file_read;
195 settings->optional_sdm_settings.sdm_access[0] = 0xf << 4 | sdm_ctr_ret; // (0xf is due to reserved for future use)
199 static uint8_t ntag424_file_settings_get_sdm_meta_read(const ntag424_file_settings_t *settings) {
200 return settings->optional_sdm_settings.sdm_access[1] >> 4;
203 static uint8_t ntag424_file_settings_get_sdm_file_read(const ntag424_file_settings_t *settings) {
204 return settings->optional_sdm_settings.sdm_access[1] & 0xf;
207 // Currently unused functions, commented out due to -Wunused-function
208 /*static uint8_t ntag424_file_settings_get_sdm_ctr_ret(const ntag424_file_settings_t *settings) {
209 return settings->optional_sdm_settings.sdm_access[0] & 4;
212 // Calculate the actual size of a file settings struct. A variable number of data is attached
213 // at the end depending on settings.
214 static int ntag424_calc_file_settings_size(const ntag424_file_settings_t *settings) {
215 int size = 7;
217 if (settings->options & FILE_SETTINGS_OPTIONS_SDM_AND_MIRRORING) {
218 size += 3; // sdm_options and sdm_access must be present
220 if (settings->optional_sdm_settings.sdm_options & FILE_SETTINGS_SDM_OPTIONS_UID &&
221 ntag424_file_settings_get_sdm_meta_read(settings) == 0xe) {
222 size += 3; // UIDOffset
225 if (settings->optional_sdm_settings.sdm_options & FILE_SETTINGS_SDM_OPTIONS_SDM_READ_COUNTER &&
226 ntag424_file_settings_get_sdm_meta_read(settings) == 0xe) {
227 size += 3; // SDMReadCtrOffset
230 if (ntag424_file_settings_get_sdm_meta_read(settings) <= 0x04) {
231 size += 3; // PICCDataOffset
234 if (ntag424_file_settings_get_sdm_file_read(settings) != 0x0f) {
235 size += 3; // SDMMacInputOffset
238 if (ntag424_file_settings_get_sdm_file_read(settings) != 0x0f &&
239 settings->optional_sdm_settings.sdm_options & FILE_SETTINGS_SDM_OPTIONS_SDM_ENC_FILE_DATA) {
240 size += 3; // SDMEncOffset
241 size += 3; // SDMEncLength
244 if (ntag424_file_settings_get_sdm_file_read(settings) != 0x0f) {
245 // Warning, this value has different offsets depending on
246 // FILE_SETTINGS_SDM_OPTIONS_SDM_ENC_FILE_DATA
247 size += 3; // SDMMacOffset
250 if (settings->optional_sdm_settings.sdm_options & FILE_SETTINGS_SDM_OPTIONS_SDM_READ_COUNTER_LIMIT) {
251 size += 3; // SDMReadCtrLimit
255 return size;
258 static int ntag424_calc_file_write_settings_size(const ntag424_file_settings_t *settings) {
259 return ntag424_calc_file_settings_size(settings) - 4;
262 static void ntag424_calc_send_iv(ntag424_session_keys_t *session_keys, uint8_t *out_ivc) {
263 uint8_t iv_clear[] = { 0xa5, 0x5a,
264 session_keys->ti[0], session_keys->ti[1], session_keys->ti[2], session_keys->ti[3],
265 (uint8_t)(session_keys->command_counter), (uint8_t)(session_keys->command_counter >> 8),
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
269 uint8_t zero_iv[16] = {0};
270 aes_encode(zero_iv, session_keys->encryption, iv_clear, out_ivc, 16);
273 static void ntag424_calc_receive_iv(ntag424_session_keys_t *session_keys, uint8_t *out_ivc) {
274 uint8_t iv_clear[] = { 0x5a, 0xa5,
275 session_keys->ti[0], session_keys->ti[1], session_keys->ti[2], session_keys->ti[3],
276 (uint8_t)(session_keys->command_counter), (uint8_t)(session_keys->command_counter >> 8),
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
280 uint8_t zero_iv[16] = {0};
281 aes_encode(zero_iv, session_keys->encryption, iv_clear, out_ivc, 16);
284 static void ntag424_calc_mac(const ntag424_session_keys_t *session_keys, uint8_t command, const uint8_t *data, uint8_t datalen, uint8_t *out_mac) {
285 uint8_t mac_input_header[] = { command,
286 (uint8_t)session_keys->command_counter, (uint8_t)(session_keys->command_counter >> 8),
287 session_keys->ti[0], session_keys->ti[1], session_keys->ti[2], session_keys->ti[3]
290 int mac_input_len = sizeof(mac_input_header) + datalen;
292 uint8_t *mac_input = (uint8_t *)calloc(mac_input_len, sizeof(uint8_t));
293 memcpy(mac_input, mac_input_header, sizeof(mac_input_header));
294 memcpy(&mac_input[sizeof(mac_input_header)], data, datalen);
295 uint8_t mac[16] = {0};
296 mbedtls_aes_cmac_prf_128(session_keys->mac, 16, mac_input, sizeof(mac_input_header) + datalen, mac);
298 for (int i = 0; i < 8; i++) {
299 out_mac[i] = mac[i * 2 + 1];
302 free(mac_input);
305 static int ntag424_comm_mac_apdu(APDU_t *apdu, int command_header_length, int apdu_max_data_size, ntag424_session_keys_t *session_keys) {
307 int size = apdu->lc;
309 if (size + 8 > apdu_max_data_size) {
310 return PM3_EOVFLOW;
313 ntag424_calc_mac(session_keys, apdu->ins, apdu->data, size, &apdu->data[size]);
314 session_keys->command_counter++; // CmdCtr should be incremented each time a MAC is calculated
315 apdu->lc = size + 8;
317 return PM3_SUCCESS;
320 static int ntag424_comm_encrypt_apdu(APDU_t *apdu, int command_header_length, int apdu_max_data_size, ntag424_session_keys_t *session_keys) {
321 // ------- Calculate IV
322 uint8_t ivc[16];
323 ntag424_calc_send_iv(session_keys, ivc);
325 int size = apdu->lc;
327 size_t encrypt_data_size = size - command_header_length;
328 size_t padded_data_size = encrypt_data_size + 16 - (encrypt_data_size % 16); // pad up to 16 byte blocks
329 uint8_t temp_buffer[256] = {0};
331 if (!encrypt_data_size) {
332 return PM3_SUCCESS;
335 if (padded_data_size + command_header_length > apdu_max_data_size) {
336 return PM3_EOVFLOW;
339 // ------ Pad data
340 memcpy(temp_buffer, &apdu->data[command_header_length], encrypt_data_size); // We encrypt everything except the CmdHdr (first byte in data)
341 temp_buffer[encrypt_data_size] = 0x80;
343 // ------ Encrypt it
344 aes_encode(ivc, session_keys->encryption, temp_buffer, &apdu->data[command_header_length], padded_data_size);
346 apdu->lc = (uint8_t)(command_header_length + padded_data_size); // Set size to CmdHdr + padded data
348 return PM3_SUCCESS;
351 static int ntag424_exchange_apdu(APDU_t apdu, int command_header_length, uint8_t *response, int *response_length, ntag424_communication_mode_t comm_mode, ntag424_session_keys_t *session_keys, uint8_t sw1_expected, uint8_t sw2_expected) {
353 int res;
355 // New buffer since we might need to expand the data in the apdu
356 int buffer_length = 256;
357 uint8_t tmp_apdu_buffer[256] = {0};
359 if (comm_mode != COMM_PLAIN) {
360 if (session_keys == NULL) {
361 PrintAndLogEx(ERR, "Non-plain communications mode requested but no session keys supplied");
362 return PM3_EINVARG;
364 memcpy(tmp_apdu_buffer, apdu.data, apdu.lc);
365 apdu.data = tmp_apdu_buffer;
368 if (comm_mode == COMM_FULL) {
369 res = ntag424_comm_encrypt_apdu(&apdu, command_header_length, buffer_length, session_keys);
370 if (res != PM3_SUCCESS) {
371 return res;
375 if (comm_mode == COMM_MAC || comm_mode == COMM_FULL) {
376 res = ntag424_comm_mac_apdu(&apdu, command_header_length, buffer_length, session_keys);
377 if (res != PM3_SUCCESS) {
378 return res;
382 uint8_t cmd[256] = {0};
383 int apdu_length = 256;
385 if (APDUEncode(&apdu, cmd, &apdu_length) != 0) {
386 return PM3_EINVARG;
389 res = ExchangeAPDU14a(cmd, apdu_length + 1, false, true, response, *response_length, response_length);
390 if (res != PM3_SUCCESS) {
391 PrintAndLogEx(ERR, "Failed to exchange APDU: %d", res);
392 return res;
395 if (*response_length < 2) {
396 PrintAndLogEx(ERR, "No response");
397 return PM3_ESOFT;
400 uint8_t sw1 = response[*response_length - 2];
401 uint8_t sw2 = response[*response_length - 1];
403 if (sw1 != sw1_expected || sw2 != sw2_expected) {
404 PrintAndLogEx(ERR, "Error from card: %02X %02X (%s)", sw1, sw2, GetAPDUCodeDescription(sw1, sw2));
405 return PM3_ESOFT;
408 // Decrypt data if we are in full communications mode. If we want to verify MAC, this
409 // should also be done here
410 if (comm_mode == COMM_FULL) {
411 uint8_t iv[16] = {0};
412 ntag424_calc_receive_iv(session_keys, iv);
414 uint8_t tmp[256];
415 memcpy(tmp, response, *response_length);
416 aes_decode(iv, session_keys->encryption, response, tmp, *response_length - 10);
418 memcpy(response, tmp, *response_length);
421 return PM3_SUCCESS;
425 static int ntag424_get_file_settings(uint8_t fileno, ntag424_file_settings_t *settings_out) {
426 int response_length = sizeof(ntag424_file_settings_t) + 2;
427 uint8_t response[response_length];
429 APDU_t apdu = {
430 .cla = 0x90,
431 .ins = NTAG424_CMD_GET_FILE_SETTINGS,
432 .lc = 1,
433 .data = &fileno,
434 .extended_apdu = false
437 int res = ntag424_exchange_apdu(apdu, 1, response, &response_length, COMM_PLAIN, NULL, 0x91, 0x00);
438 if (res != PM3_SUCCESS) {
439 return res;
442 if (settings_out) {
443 memcpy(settings_out, response, response_length);
446 return PM3_SUCCESS;
449 static int ntag424_write_file_settings(uint8_t fileno, const ntag424_file_settings_t *settings, ntag424_session_keys_t *session_keys) {
451 // ------- Convert file settings to the format for writing
452 file_settings_write_t write_settings = {
453 .options = settings->options,
454 .access[0] = settings->access[0],
455 .access[1] = settings->access[1],
456 .optional_sdm_settings = settings->optional_sdm_settings,
459 size_t settings_size = ntag424_calc_file_write_settings_size(settings);
461 uint8_t cmd_buffer[256];
462 cmd_buffer[0] = fileno;
463 memcpy(&cmd_buffer[1], &write_settings, settings_size);
465 APDU_t apdu = {
466 .cla = 0x90,
467 .ins = NTAG424_CMD_CHANGE_FILE_SETTINGS,
468 .lc = 1 + settings_size,
469 .data = cmd_buffer
473 // ------- Actually send the APDU
474 int response_length = 8 + 2;
475 uint8_t response[response_length];
477 int res = ntag424_exchange_apdu(apdu, 1, response, &response_length, COMM_FULL, session_keys, 0x91, 0x00);
478 return res;
481 static void ntag424_print_file_settings(uint8_t fileno, const ntag424_file_settings_t *settings) {
483 int num_sdm_data = (ntag424_calc_file_settings_size(settings) - SETTINGS_WITHOUT_SDM_DATA_SIZE) / 3;
485 PrintAndLogEx(SUCCESS, "--- " _CYAN_("File %d settings:"), fileno);
487 PrintAndLogEx(SUCCESS, " type: " _GREEN_("%02X"), settings->type);
488 PrintAndLogEx(SUCCESS, " options: " _GREEN_("%02X"), settings->options);
489 PrintAndLogEx(SUCCESS, " access: " _GREEN_("%02X%02X (RW, C, R, W)"), settings->access[0], settings->access[1]);
490 PrintAndLogEx(SUCCESS, " size: " _GREEN_("%02X%02X%02X"), settings->size[2], settings->size[1], settings->size[0]);
492 if (settings->options & FILE_SETTINGS_OPTIONS_SDM_AND_MIRRORING) {
493 PrintAndLogEx(SUCCESS, "--- " _CYAN_("SDM settings: "));
494 PrintAndLogEx(SUCCESS, " options: " _GREEN_("%02X"), settings->optional_sdm_settings.sdm_options);
495 PrintAndLogEx(SUCCESS, " sdm access: " _GREEN_("%02X%02X"), settings->optional_sdm_settings.sdm_access[0], settings->optional_sdm_settings.sdm_access[1]);
497 if (num_sdm_data > 0) {
498 PrintAndLogEx(SUCCESS, "--- " _CYAN_("SDM data: "));
499 for (int i = 0; i < num_sdm_data; i++) {
500 PrintAndLogEx(SUCCESS, " %d: %02X%02X%02X", i,
501 settings->optional_sdm_settings.sdm_data[i][2],
502 settings->optional_sdm_settings.sdm_data[i][1],
503 settings->optional_sdm_settings.sdm_data[i][0]);
509 // NTAG424 only have one static application, so we select it here
510 static int ntag424_select_application(void) {
511 const size_t RESPONSE_LENGTH = 2;
512 uint8_t cmd[] = {0x00, 0xA4, 0x04, 0x0C, 0x07, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01, 0x00 };
513 uint8_t resp[RESPONSE_LENGTH];
514 int outlen = 0;
515 int res;
517 res = ExchangeAPDU14a(cmd, sizeof(cmd), false, true, resp, RESPONSE_LENGTH, &outlen);
518 if (res != PM3_SUCCESS) {
519 PrintAndLogEx(ERR, "Failed to send apdu");
520 return res;
523 if (outlen != RESPONSE_LENGTH || resp[RESPONSE_LENGTH - 2] != 0x90 || resp[RESPONSE_LENGTH - 1] != 0x00) {
524 PrintAndLogEx(ERR, "Failed to select application");
525 return PM3_ESOFT;
528 return PM3_SUCCESS;
531 static int ntag424_auth_first_step(uint8_t keyno, uint8_t *key, uint8_t *out) {
532 uint8_t key_number[2] = { keyno, 0x00 };
534 APDU_t apdu = {
535 .cla = 0x90,
536 .ins = NTAG424_CMD_AUTHENTICATE_EV2_FIRST,
537 .lc = 0x02,
538 .data = key_number
541 int response_length = 16 + 2;
542 uint8_t response[response_length];
544 int res = ntag424_exchange_apdu(apdu, 2, response, &response_length, COMM_PLAIN, NULL, 0x91, 0xAF);
545 if (res != PM3_SUCCESS) {
546 return res;
549 if (response_length != 16 + 2) {
550 PrintAndLogEx(ERR, "Failed to get RndB (invalid key number?)");
551 return PM3_ESOFT;
554 uint8_t iv[16] = {0};
555 aes_decode(iv, key, response, out, 16);
557 return PM3_SUCCESS;
560 static int ntag424_auth_second_step(uint8_t *challenge, uint8_t *response_out) {
561 APDU_t apdu = {
562 .cla = 0x90,
563 .ins = NTAG424_CMD_MORE_DATA,
564 .lc = 0x20,
565 .data = challenge,
567 int response_length = 256;
568 uint8_t response[response_length];
570 int res = ntag424_exchange_apdu(apdu, 0x20, response, &response_length, COMM_PLAIN, NULL, 0x91, 0x00);
571 if (res != PM3_SUCCESS) {
572 return res;
575 memcpy(response_out, response, response_length - 2);
577 return PM3_SUCCESS;
580 // Authenticate against a key number and optionally get session keys out
581 static int ntag424_authenticate_ev2_first(uint8_t keyno, uint8_t *key, ntag424_session_keys_t *session_keys_out) {
582 // -------- Get first challenge from card
583 uint8_t rnd_b_clear[16] = {0};
585 int res = ntag424_auth_first_step(keyno, key, rnd_b_clear);
586 if (res != PM3_SUCCESS) {
587 return res;
590 // -------- Concatenate RndA and RndB and encrypt it with the key
591 uint8_t concat_clear[32] = {0};
592 uint8_t concat_enc[32] = {0};
593 // This should of course be completely random, if we cared
594 // about security
595 uint8_t rnd_a_clear[16] = {
596 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
597 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf
600 uint8_t iv[16] = {0};
601 memcpy(&concat_clear[16], &rnd_b_clear[1], 15);
602 concat_clear[31] = rnd_b_clear[0];
603 memcpy(concat_clear, rnd_a_clear, 16);
605 aes_encode(iv, key, concat_clear, concat_enc, 32);
607 // -------- Do second step with our concatenated encrypted RndA || RndB
608 uint8_t resp[4 + 16 + 6 + 6];
609 res = ntag424_auth_second_step(concat_enc, resp);
610 if (res != PM3_SUCCESS) {
611 return res;
614 ntag424_ev2_response_t response;
615 aes_decode(iv, key, resp, (uint8_t *)&response, sizeof(ntag424_ev2_response_t));
617 // -------- Verify that the response we got contains the RndA that we supplied (rotated one byte)
618 if (memcmp(response.rnd_a, &rnd_a_clear[1], 15) != 0 ||
619 response.rnd_a[15] != rnd_a_clear[0]) {
620 PrintAndLogEx(ERR, "Incorrect response from card\n"
621 "expected: %s\n"
622 "got: %s"
623 , sprint_hex(rnd_a_clear, 16),
624 sprint_hex(response.rnd_a, 16));
625 return PM3_ESOFT;
628 // -------- Optionally calculate session keys
629 if (session_keys_out) {
630 memset(session_keys_out, 0, sizeof(ntag424_session_keys_t));
631 memcpy(session_keys_out->ti, response.ti, sizeof(response.ti));
633 // SV 1 = [0xA5][0x5A][0x00][0x01]
634 // [0x00][0x80][RndA[15:14] ||
635 // [ (RndA[13:8] ⊕ RndB[15:10]) ] ||
636 // [RndB[9:0] || RndA[7:0]
638 uint8_t sv1[] = { 0xa5, 0x5a, 0x00, 0x01, 0x00, 0x80, rnd_a_clear[0], rnd_a_clear[1],
639 rnd_a_clear[2] ^rnd_b_clear[0],
640 rnd_a_clear[3] ^rnd_b_clear[1],
641 rnd_a_clear[4] ^rnd_b_clear[2],
642 rnd_a_clear[5] ^rnd_b_clear[3],
643 rnd_a_clear[6] ^rnd_b_clear[4],
644 rnd_a_clear[7] ^rnd_b_clear[5],
645 rnd_b_clear[6], rnd_b_clear[7], rnd_b_clear[8], rnd_b_clear[9], rnd_b_clear[10],
646 rnd_b_clear[11], rnd_b_clear[12], rnd_b_clear[13], rnd_b_clear[14], rnd_b_clear[15],
647 rnd_a_clear[8], rnd_a_clear[9], rnd_a_clear[10],
648 rnd_a_clear[11], rnd_a_clear[12], rnd_a_clear[13], rnd_a_clear[14], rnd_a_clear[15]
651 // SV 2 = [0x5A][0xA5][0x00][0x01]
652 // [0x00][0x80][RndA[15:14] ||
653 // [ (RndA[13:8] ⊕ RndB[15:10]) ] ||
654 // [RndB[9:0] || RndA[7:0]
656 uint8_t sv2[] = { 0x5a, 0xa5, 0x00, 0x01, 0x00, 0x80, rnd_a_clear[0], rnd_a_clear[1],
657 rnd_a_clear[2] ^rnd_b_clear[0],
658 rnd_a_clear[3] ^rnd_b_clear[1],
659 rnd_a_clear[4] ^rnd_b_clear[2],
660 rnd_a_clear[5] ^rnd_b_clear[3],
661 rnd_a_clear[6] ^rnd_b_clear[4],
662 rnd_a_clear[7] ^rnd_b_clear[5],
663 rnd_b_clear[6], rnd_b_clear[7], rnd_b_clear[8], rnd_b_clear[9], rnd_b_clear[10],
664 rnd_b_clear[11], rnd_b_clear[12], rnd_b_clear[13], rnd_b_clear[14], rnd_b_clear[15],
665 rnd_a_clear[8], rnd_a_clear[9], rnd_a_clear[10],
666 rnd_a_clear[11], rnd_a_clear[12], rnd_a_clear[13], rnd_a_clear[14], rnd_a_clear[15]
669 mbedtls_aes_cmac_prf_128(key, 16, sv1, sizeof(sv1), session_keys_out->encryption);
670 mbedtls_aes_cmac_prf_128(key, 16, sv2, sizeof(sv2), session_keys_out->mac);
673 return PM3_SUCCESS;
676 #define MAX_WRITE_APDU (200)
678 // Write file to card. Only supports plain communications mode. Authentication must be done
679 // first unless file has free write access.
680 static int ntag424_write_data(uint8_t fileno, uint32_t offset, uint32_t num_bytes, uint8_t *in, ntag424_communication_mode_t comm_mode, ntag424_session_keys_t *session_keys) {
681 size_t remainder = 0;
683 // Split writes that are too large for one APDU
684 if (num_bytes > MAX_WRITE_APDU) {
685 remainder = num_bytes - MAX_WRITE_APDU;
686 num_bytes = MAX_WRITE_APDU;
689 uint8_t cmd_header[] = {
690 fileno,
691 (uint8_t)offset,
692 (uint8_t)(offset << 8),
693 (uint8_t)(offset << 16), // offset
694 (uint8_t)num_bytes,
695 (uint8_t)(num_bytes >> 8),
696 (uint8_t)(num_bytes >> 16) // size
699 uint8_t cmd[256] = {0};
701 memcpy(cmd, cmd_header, sizeof(cmd_header));
702 memcpy(&cmd[sizeof(cmd_header)], in, num_bytes);
704 APDU_t apdu = {
705 .cla = 0x90,
706 .ins = NTAG424_CMD_WRITE_DATA,
707 .lc = sizeof(cmd_header) + num_bytes,
708 .data = cmd,
711 int response_length = 8 + 2; // potential MAC and result
712 uint8_t response[response_length];
714 int res = ntag424_exchange_apdu(apdu, sizeof(cmd_header), response, &response_length, comm_mode, session_keys, 0x91, 0x00);
715 if (res != PM3_SUCCESS) {
716 return res;
719 if (remainder > 0) {
720 return ntag424_write_data(fileno, offset + num_bytes, remainder, &in[num_bytes], comm_mode, session_keys);
723 return PM3_SUCCESS;
726 // Read file from card. Only supports plain communications mode. Authentication must be done
727 // first unless file has free read access.
728 static int ntag424_read_data(uint8_t fileno, uint16_t offset, uint16_t num_bytes, uint8_t *out, ntag424_communication_mode_t comm_mode, ntag424_session_keys_t *session_keys) {
729 uint8_t cmd_header[] = {
730 fileno,
731 (uint8_t)offset, (uint8_t)(offset << 8), (uint8_t)(offset << 16), // offset
732 (uint8_t)num_bytes, (uint8_t)(num_bytes >> 8), 0x00
735 APDU_t apdu = {
736 .cla = 0x90,
737 .ins = NTAG424_CMD_READ_DATA,
738 .lc = sizeof(cmd_header),
739 .data = cmd_header,
742 int response_length = num_bytes + 4 + 2 + 20; // number of bytes to read + mac + result + potential padding
743 uint8_t response[response_length];
745 int res = ntag424_exchange_apdu(apdu, sizeof(cmd_header), response, &response_length, comm_mode, session_keys, 0x91, 0x00);
746 if (res != PM3_SUCCESS) {
747 return res;
750 memcpy(out, response, num_bytes);
751 return PM3_SUCCESS;
754 static int ntag424_get_version(ntag424_full_version_information_t *version) {
755 APDU_t apdu = {
756 .cla = 0x90,
757 .ins = NTAG424_CMD_GET_VERSION,
761 uint8_t response[256];
763 int response_length = sizeof(ntag424_version_information_t) + 2;
764 if (ntag424_exchange_apdu(apdu, 0, response, &response_length, COMM_PLAIN, NULL, 0x91, 0xAF) != PM3_SUCCESS) {
765 return PM3_ESOFT;
767 memcpy(&version->hardware, response, sizeof(ntag424_version_information_t));
769 APDU_t continue_apdu = {
770 .cla = 0x90,
771 .ins = NTAG424_CMD_MORE_DATA,
774 response_length = sizeof(ntag424_version_information_t) + 2;
775 if (ntag424_exchange_apdu(continue_apdu, 0, response, &response_length, COMM_PLAIN, NULL, 0x91, 0xAF) != PM3_SUCCESS) {
776 return PM3_ESOFT;
778 memcpy(&version->software, response, sizeof(ntag424_version_information_t));
780 response_length = sizeof(ntag424_production_information_t) + 2;
781 if (ntag424_exchange_apdu(continue_apdu, 0, response, &response_length, COMM_PLAIN, NULL, 0x91, 0x00) != PM3_SUCCESS) {
782 return PM3_ESOFT;
784 memcpy(&version->production, response, sizeof(ntag424_production_information_t));
786 return PM3_SUCCESS;
789 #define NXP_SIGNATURE_LENGTH 56
790 #define NXP_SIGNATURE_ID 0x00
792 static int ntag424_get_signature(uint8_t *signature_out) {
793 uint8_t signature_id = NXP_SIGNATURE_ID;
794 APDU_t apdu = {
795 .cla = 0x90,
796 .ins = NTAG424_CMD_GET_SIGNATURE,
797 .lc = 1,
798 .data = &signature_id,
801 int response_length = NXP_SIGNATURE_LENGTH + 2;
802 // This is a weird one. Datasheet claims this command should result in 91 00, but cards, and the AN12196
803 // document shows 91 90 on success.
804 if (ntag424_exchange_apdu(apdu, 1, signature_out, &response_length, COMM_PLAIN, NULL, 0x91, 0x90) != PM3_SUCCESS) {
805 return PM3_ESOFT;
808 return PM3_SUCCESS;
811 static int ntag424_change_key(uint8_t keyno, const uint8_t *new_key, const uint8_t *old_key, uint8_t version, ntag424_session_keys_t *session_keys) {
812 // -------- Calculate xor and crc
813 uint8_t key[16] = {0};
814 uint8_t crc[4] = {0};
815 if (keyno != 0) {
816 for (int i = 0; i < 16; i++) {
817 key[i] = old_key[i] ^ new_key[i];
819 crc32_ex(new_key, 16, crc);
820 } else {
821 memcpy(key, new_key, 16);
824 // ------- Assemble KeyData command
825 uint8_t key_cmd_data[32] = {0};
826 key_cmd_data[0] = keyno;
827 memcpy(&key_cmd_data[1], key, 16);
828 key_cmd_data[17] = version;
829 int key_data_len;
830 if (keyno != 0) {
831 memcpy(&key_cmd_data[18], crc, sizeof(crc));
832 key_data_len = sizeof(keyno) + sizeof(key) + sizeof(version) + sizeof(crc);
833 } else {
834 key_data_len = sizeof(keyno) + sizeof(key) + sizeof(version);
837 APDU_t apdu = {
838 .cla = 0x90,
839 .ins = NTAG424_CMD_CHANGE_KEY,
840 .lc = key_data_len,
841 .data = key_cmd_data
844 int response_length = 8 + 2;
845 uint8_t response[response_length];
847 int res = ntag424_exchange_apdu(apdu, 1, response, &response_length, COMM_FULL, session_keys, 0x91, 0x00);
848 return res;
851 static int CmdHelp(const char *Cmd);
853 static int CmdHF_ntag424_view(const char *Cmd) {
855 CLIParserContext *ctx;
856 CLIParserInit(&ctx, "hf ntag424 view",
857 "Print a NTAG 424 DNA dump file (bin/eml/json)",
858 "hf ntag424 view -f hf-ntag424-01020304-dump.bin"
860 void *argtable[] = {
861 arg_param_begin,
862 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
863 arg_lit0("v", "verbose", "Verbose output"),
864 arg_param_end
866 CLIExecWithReturn(ctx, Cmd, argtable, false);
867 int fnlen = 0;
868 char fn[FILE_PATH_SIZE];
869 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)fn, FILE_PATH_SIZE, &fnlen);
870 bool verbose = arg_get_lit(ctx, 2);
871 CLIParserFree(ctx);
873 // read dump file
874 uint8_t *dump = NULL;
875 size_t bytes_read = NTAG424_MAX_BYTES;
876 int res = pm3_load_dump(fn, (void **)&dump, &bytes_read, NTAG424_MAX_BYTES);
877 if (res != PM3_SUCCESS) {
878 return res;
881 if (verbose) {
882 PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), fn);
883 PrintAndLogEx(INFO, "File size %zu bytes", bytes_read);
886 // to be implemented...
887 PrintAndLogEx(INFO, "not implemented yet");
888 PrintAndLogEx(INFO, "Feel free to contribute!");
890 free(dump);
891 return PM3_SUCCESS;
894 static int CmdHF_ntag424_info(const char *Cmd) {
896 CLIParserContext *ctx;
897 CLIParserInit(&ctx, "hf ntag424 info",
898 "Get info about NXP NTAG424 DNA Family styled tag.",
899 "hf ntag424 info"
901 void *argtable[] = {
902 arg_param_begin,
903 arg_param_end
905 CLIExecWithReturn(ctx, Cmd, argtable, true);
906 CLIParserFree(ctx);
908 if (SelectCard14443A_4(false, true, NULL) != PM3_SUCCESS) {
909 PrintAndLogEx(ERR, "Failed to select card");
910 DropField();
911 return PM3_ERFTRANS;
914 if (ntag424_select_application() != PM3_SUCCESS) {
915 DropField();
916 return PM3_ESOFT;
919 ntag424_full_version_information_t version = {0};
920 if (ntag424_get_version(&version) != PM3_SUCCESS) {
921 DropField();
922 return PM3_ESOFT;
924 ntag424_print_full_version_information(&version);
926 uint8_t signature[NXP_SIGNATURE_LENGTH];
927 int res = ntag424_get_signature(signature);
928 DropField();
930 if (res == PM3_SUCCESS) {
931 PrintAndLogEx(INFO, "--- " _CYAN_("NXP originality signature:"));
932 desfire_print_signature(version.production.uid, 7, signature, NXP_SIGNATURE_LENGTH);
935 return res;
938 static int ntag424_cli_get_auth_information(CLIParserContext *ctx, int keyno_index, int key_index, int *keyno, uint8_t *key_out) {
940 if (keyno) {
941 *keyno = arg_get_int(ctx, keyno_index);
944 int keylen = 16;
945 uint8_t key[16] = {0};
947 if (CLIParamHexToBuf(arg_get_str(ctx, key_index), key, sizeof(key), &keylen) || (keylen != 16)) {
948 return PM3_ESOFT;
951 memcpy(key_out, key, 16);
952 return PM3_SUCCESS;
955 static int CmdHF_ntag424_auth(const char *Cmd) {
956 CLIParserContext *ctx;
957 CLIParserInit(&ctx, "hf ntag424 auth",
958 "Authenticate with selected key against NTAG424.",
959 "hf ntag424 auth --keyno 0 -k 00000000000000000000000000000000");
961 void *argtable[] = {
962 arg_param_begin,
963 arg_int1(NULL, "keyno", "<dec>", "Key number"),
964 arg_str1("k", "key", "<hex>", "Key for authenticate (HEX 16 bytes)"),
965 arg_param_end
967 CLIExecWithReturn(ctx, Cmd, argtable, false);
969 int keyno = 0;
970 uint8_t key[16] = {0};
971 if (ntag424_cli_get_auth_information(ctx, 1, 2, &keyno, key) != PM3_SUCCESS) {
972 CLIParserFree(ctx);
973 return PM3_ESOFT;
976 CLIParserFree(ctx);
978 if (SelectCard14443A_4(false, true, NULL) != PM3_SUCCESS) {
979 PrintAndLogEx(ERR, "Failed to select card");
980 DropField();
981 return PM3_ERFTRANS;
984 if (ntag424_select_application() != PM3_SUCCESS) {
985 DropField();
986 return PM3_ESOFT;
989 int res = ntag424_authenticate_ev2_first(keyno, key, NULL);
990 if (res != PM3_SUCCESS) {
991 PrintAndLogEx(ERR, "Auth key %d ( " _RED_("fail") " )", keyno);
992 } else {
993 PrintAndLogEx(SUCCESS, "Auth key %d ( " _GREEN_("ok") " )", keyno);
996 DropField();
997 return PM3_SUCCESS;
1000 // Read can only read files with plain communication mode!
1001 static int CmdHF_ntag424_read(const char *Cmd) {
1002 CLIParserContext *ctx;
1003 CLIParserInit(&ctx, "hf ntag424 read",
1004 "Read and print data from file on NTAG424 tag. Will authenticate if key information is provided.",
1005 "hf ntag424 read --fileno 1 --keyno 0 -k 00000000000000000000000000000000 -o 0 -l 32\n"
1006 "hf ntag424 read --fileno 2 --keyno 0 -k 00000000000000000000000000000000 -o 0 -l 256\n"
1007 "hf ntag424 read --fileno 3 --keyno 3 -k 00000000000000000000000000000000 -o 0 -l 128 -m encrypt");
1009 void *argtable[] = {
1010 arg_param_begin,
1011 arg_int1(NULL, "fileno", "<1|2|3>", "File number"),
1012 arg_int0(NULL, "keyno", "<dec>", "Key number"),
1013 arg_str0("k", "key", "<hex>", "Key for authentication (HEX 16 bytes)"),
1014 arg_int0("o", "offset", "<dec>", "Offset to read in file (def 0)"),
1015 arg_int1("l", "length", "<dec>", "Number of bytes to read"),
1016 arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communication mode"),
1017 arg_param_end
1019 CLIExecWithReturn(ctx, Cmd, argtable, false);
1021 int fileno = arg_get_int(ctx, 1);
1023 int keyno = 0;
1024 uint8_t key[16] = {0};
1025 bool auth = (ntag424_cli_get_auth_information(ctx, 2, 3, &keyno, key) == PM3_SUCCESS);
1027 int offset = arg_get_int_def(ctx, 4, 0);
1028 int read_length = arg_get_int(ctx, 5);
1030 ntag424_communication_mode_t comm_mode;
1031 int comm_out = 0;
1032 if (CLIGetOptionList(arg_get_str(ctx, 6), ntag424_communication_mode_options, &comm_out)) {
1033 CLIParserFree(ctx);
1034 return PM3_EINVARG;
1036 CLIParserFree(ctx);
1038 comm_mode = comm_out;
1040 if (comm_mode != COMM_PLAIN && auth == false) {
1041 PrintAndLogEx(ERR, "Only plain communication mode can be used without a key specified");
1042 return PM3_EINVARG;
1045 if (SelectCard14443A_4(false, true, NULL) != PM3_SUCCESS) {
1046 DropField();
1047 PrintAndLogEx(ERR, "Failed to select card");
1048 return PM3_ERFTRANS;
1051 if (ntag424_select_application() != PM3_SUCCESS) {
1052 DropField();
1053 return PM3_ESOFT;
1056 int res = PM3_SUCCESS;
1057 ntag424_session_keys_t session_keys;
1058 if (auth) {
1059 res = ntag424_authenticate_ev2_first(keyno, key, &session_keys);
1060 if (res != PM3_SUCCESS) {
1061 PrintAndLogEx(ERR, "Auth key %d ( " _RED_("fail") " )", keyno);
1062 DropField();
1063 return res;
1064 } else {
1065 PrintAndLogEx(SUCCESS, "Auth key %d ( " _GREEN_("ok") " )", keyno);
1069 uint8_t data[512] = {0};
1070 res = ntag424_read_data(fileno, offset, read_length, data, comm_mode, &session_keys);
1071 DropField();
1072 if (res == PM3_SUCCESS) {
1073 PrintAndLogEx(SUCCESS, " -------- Read file " _YELLOW_("%d") " contents ------------ ", fileno);
1074 print_hex_break(data, read_length, 16);
1076 return res;
1079 static int CmdHF_ntag424_write(const char *Cmd) {
1080 CLIParserContext *ctx;
1081 CLIParserInit(&ctx, "hf ntag424 write",
1082 "Write data to file on NTAG424 tag. Will authenticate if key information is provided.",
1083 "hf ntag424 write --fileno 2 --keyno 0 -k 00000000000000000000000000000000 -o 0 -d 1122334455667788\n"
1084 "hf ntag424 write --fileno 3 --keyno 3 -k 00000000000000000000000000000000 -o 0 -d 1122334455667788 -m encrypt");
1086 void *argtable[] = {
1087 arg_param_begin,
1088 arg_u64_1(NULL, "fileno", "<1|2|3>", "File number (def 2)"),
1089 arg_int0(NULL, "keyno", "<dec>", "Key number"),
1090 arg_str0("k", "key", "<hex>", "Key for authentication (HEX 16 bytes)"),
1091 arg_int0("o", "offset", "<dec>", "Offset to write in file (def 0)"),
1092 arg_str1("d", "data", "<hex>", "Data to write"),
1093 arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communication mode"),
1094 arg_param_end
1096 CLIExecWithReturn(ctx, Cmd, argtable, false);
1098 int fileno = arg_get_int(ctx, 1);
1100 int keyno = 0;
1101 uint8_t key[16] = {0};
1102 bool auth = (ntag424_cli_get_auth_information(ctx, 2, 3, &keyno, key) == PM3_SUCCESS);
1104 uint32_t offset = arg_get_u32_def(ctx, 4, 0);
1106 uint8_t data[512] = {0};
1107 int datalen = 512;
1108 CLIGetHexWithReturn(ctx, 5, data, &datalen);
1110 ntag424_communication_mode_t comm_mode;
1111 int comm_out = 0;
1112 if (CLIGetOptionList(arg_get_str(ctx, 6), ntag424_communication_mode_options, &comm_out)) {
1113 CLIParserFree(ctx);
1114 return PM3_EINVARG;
1116 CLIParserFree(ctx);
1118 comm_mode = comm_out;
1120 if (comm_mode != COMM_PLAIN && auth == false) {
1121 PrintAndLogEx(ERR, "Only plain communication mode can be used without a key specified");
1122 return PM3_EINVARG;
1125 if (SelectCard14443A_4(false, true, NULL) != PM3_SUCCESS) {
1126 DropField();
1127 PrintAndLogEx(ERR, "Failed to select card");
1128 return PM3_ERFTRANS;
1131 if (ntag424_select_application() != PM3_SUCCESS) {
1132 DropField();
1133 return PM3_ESOFT;
1136 int res = PM3_SUCCESS;
1137 ntag424_session_keys_t session_keys = {0};
1138 if (auth) {
1139 res = ntag424_authenticate_ev2_first(keyno, key, &session_keys);
1140 if (res != PM3_SUCCESS) {
1141 PrintAndLogEx(ERR, "Auth key %d ( " _RED_("fail") " )", keyno);
1142 DropField();
1143 return res;
1144 } else {
1145 PrintAndLogEx(SUCCESS, "Auth key %d ( " _GREEN_("ok") " )", keyno);
1149 res = ntag424_write_data(fileno, offset, (uint32_t)datalen, data, comm_mode, &session_keys);
1150 DropField();
1151 if (res == PM3_SUCCESS) {
1152 PrintAndLogEx(SUCCESS, "Wrote " _YELLOW_("%d") " bytes ( " _GREEN_("ok") " )", datalen);
1153 } else {
1154 PrintAndLogEx(ERR, "Wrote " _YELLOW_("%d") " bytes ( " _RED_("fail") " )", datalen);
1156 return res;
1159 static int CmdHF_ntag424_getfilesettings(const char *Cmd) {
1160 CLIParserContext *ctx;
1161 CLIParserInit(&ctx, "hf ntag424 getfs",
1162 "Read and print file settings for file",
1163 "hf ntag424 getfs --fileno 2");
1165 void *argtable[] = {
1166 arg_param_begin,
1167 arg_int1(NULL, "fileno", "<dec>", "File number"),
1168 arg_param_end
1170 CLIExecWithReturn(ctx, Cmd, argtable, false);
1171 int fileno = arg_get_int(ctx, 1);
1173 CLIParserFree(ctx);
1175 if (SelectCard14443A_4(false, true, NULL) != PM3_SUCCESS) {
1176 DropField();
1177 PrintAndLogEx(ERR, "Failed to select card");
1178 return PM3_ERFTRANS;
1181 if (ntag424_select_application() != PM3_SUCCESS) {
1182 DropField();
1183 return PM3_ESOFT;
1186 ntag424_file_settings_t settings = {0};
1187 int res = ntag424_get_file_settings(fileno, &settings);
1188 DropField();
1189 if (res == PM3_SUCCESS) {
1190 ntag424_print_file_settings(fileno, &settings);
1192 return res;
1195 static int CmdHF_ntag424_changefilesettings(const char *Cmd) {
1196 CLIParserContext *ctx;
1197 CLIParserInit(&ctx, "hf ntag424 changefs",
1198 "Updates file settings for file, must be authenticated.\n"
1199 "This is a short explanation of the settings. See AN12196 for more information:\n"
1200 "options: byte with bit flags\n"
1201 " Bit: Setting:\n"
1202 " 6 Enable SDM and mirroring\n\n"
1204 "access: two byte access rights.\n"
1205 "Each nibble is a key number, or E for free access.\n"
1206 "Order is key for readwrite, change, read and write\n\n"
1208 "sdmoptions: byte with bit flags\n"
1209 " Bit: Setting:\n"
1210 " 0 ASCII encoding\n"
1211 " 4 SDMEncFileData\n"
1212 " 5 SDMReadCtrLimit\n"
1213 " 6 SDMReadCtr\n"
1214 " 7 SDMOptionsUID\n\n"
1216 "sdmaccess: two byte access rights.\n"
1217 "Each nibble is a key, or E for plain mirror and F for no mirroring\n"
1218 "Order is Reserved, SDMCtrRet, SDMMetaRead and SDMFileRead\n\n"
1220 "sdm_data: Three bytes of data used to control SDM settings. Can be specified multiple times.\n"
1221 "Data means different things depending on settings.\n\n"
1223 "Note: Not all of these settings will be written. It depends on the option byte, and the keys set. See AN12196 for more information.\n"
1224 "You must also start with sdmdata1, then sdmdata2, up to the number of sdm_data you want to write",
1226 "hf ntag424 changefs --fileno 2 --keyno 0 -k 00000000000000000000000000000000 -o 40 -a 00E0 -s C1 -c F000 --data1 000020 --data2 000043 --data3 000043"
1229 void *argtable[] = {
1230 arg_param_begin,
1231 arg_int1(NULL, "fileno", "<dec>", "File number"),
1232 arg_int1(NULL, "keyno", "<dec>", "Key number"),
1233 arg_str1("k", "key", "<hex>", "Key for authentication (HEX 16 bytes)"),
1234 arg_str0("o", "options", "<hex>", "File options byte (HEX 1 byte)"),
1235 arg_str0("a", "access", "<hex>", "File access settings (HEX 2 bytes)"),
1236 arg_str0("s", "sdmoptions", "<hex>", "SDM options (HEX 1 byte)"),
1237 arg_str0("c", "sdmaccess", "<hex>", "SDM access settings (HEX 2 bytes)"),
1238 arg_str0(NULL, "data1", "<hex>", "SDM data (HEX 3 bytes)"),
1239 arg_str0(NULL, "data2", "<hex>", "SDM data (HEX 3 bytes)"),
1240 arg_str0(NULL, "data3", "<hex>", "SDM data (HEX 3 bytes)"),
1241 arg_str0(NULL, "data4", "<hex>", "SDM data (HEX 3 bytes)"),
1242 arg_str0(NULL, "data5", "<hex>", "SDM data (HEX 3 bytes)"),
1243 arg_str0(NULL, "data6", "<hex>", "SDM data (HEX 3 bytes)"),
1244 arg_str0(NULL, "data7", "<hex>", "SDM data (HEX 3 bytes)"),
1245 arg_str0(NULL, "data8", "<hex>", "SDM data (HEX 3 bytes)"),
1246 // Sorry, couldn't figure out how to work with arg_strn...
1247 arg_param_end
1249 CLIExecWithReturn(ctx, Cmd, argtable, false);
1250 int fileno = arg_get_int(ctx, 1);
1252 int keyno = 0;
1253 uint8_t key[16] = {0};
1255 uint8_t has_options = 0;
1256 uint8_t options[1];
1257 uint8_t has_access = 0;
1258 uint8_t access[2];
1259 uint8_t has_sdmoptions = 0;
1260 uint8_t sdmoptions[1];
1261 uint8_t has_sdmaccess = 0;
1262 uint8_t sdmaccess[2];
1263 uint8_t num_sdm_data = 0;
1264 uint8_t sdm_data[8][3];
1266 if (ntag424_cli_get_auth_information(ctx, 2, 3, &keyno, key) != PM3_SUCCESS) {
1267 PrintAndLogEx(ERR, "Could not get key settings");
1268 CLIParserFree(ctx);
1269 return PM3_EINVARG;
1272 int len = 1;
1273 if (arg_get_str(ctx, 4)->count == 1) {
1274 has_options = 1;
1275 CLIGetHexWithReturn(ctx, 4, options, &len);
1276 if (len != 1) {
1277 PrintAndLogEx(ERR, "Options must be 1 byte, got ( %d )", len);
1278 CLIParserFree(ctx);
1279 return PM3_EINVARG;
1282 len = 2;
1283 if (arg_get_str(ctx, 5)->count == 1) {
1284 has_access = 1;
1285 CLIGetHexWithReturn(ctx, 5, access, &len);
1286 if (len != 2) {
1287 PrintAndLogEx(ERR, "Access must be 2 bytes, got ( %d )", len);
1288 CLIParserFree(ctx);
1289 return PM3_EINVARG;
1292 len = 1;
1293 if (arg_get_str(ctx, 6)->count == 1) {
1294 has_sdmoptions = 1;
1295 CLIGetHexWithReturn(ctx, 6, sdmoptions, &len);
1296 if (len != 1) {
1297 PrintAndLogEx(ERR, "SDM Options must be 1 byte, got ( %d )", len);
1298 CLIParserFree(ctx);
1299 return PM3_EINVARG;
1302 len = 2;
1303 if (arg_get_str(ctx, 7)->count == 1) {
1304 has_sdmaccess = 1;
1305 CLIGetHexWithReturn(ctx, 7, sdmaccess, &len);
1306 if (len != 2) {
1307 PrintAndLogEx(ERR, "SDM Access must be 2 bytes, got ( %d )", len);
1308 CLIParserFree(ctx);
1309 return PM3_EINVARG;
1313 for (int i = 0; i < 8; i++) {
1314 if (arg_get_str(ctx, 8 + i)->count == 1) {
1315 len = 3;
1316 num_sdm_data++;
1317 CLIGetHexWithReturn(ctx, 8 + i, sdm_data[i], &len);
1318 if (len != 3) {
1319 PrintAndLogEx(ERR, "sdmdata must be 3 bytes, got ( %d )", len);
1320 CLIParserFree(ctx);
1321 return PM3_EINVARG;
1323 } else {
1324 break;
1328 CLIParserFree(ctx);
1330 if (SelectCard14443A_4(false, true, NULL) != PM3_SUCCESS) {
1331 DropField();
1332 PrintAndLogEx(ERR, "Failed to select card");
1333 return PM3_ERFTRANS;
1336 if (ntag424_select_application() != PM3_SUCCESS) {
1337 DropField();
1338 return PM3_ESOFT;
1341 ntag424_file_settings_t settings = {0};
1342 if (ntag424_get_file_settings(fileno, &settings) != PM3_SUCCESS) {
1343 DropField();
1344 return PM3_ESOFT;
1347 int res = PM3_SUCCESS;
1348 ntag424_session_keys_t session = {0};
1349 res = ntag424_authenticate_ev2_first(keyno, key, &session);
1350 if (res != PM3_SUCCESS) {
1351 PrintAndLogEx(ERR, "Auth key %d ( " _RED_("fail") " )", keyno);
1352 DropField();
1353 return res;
1354 } else {
1355 PrintAndLogEx(SUCCESS, "Auth key %d ( " _GREEN_("ok") " )", keyno);
1358 if (has_options) {
1359 settings.options = options[0];
1362 if (has_access) {
1363 memcpy(settings.access, access, 2);
1366 if (has_sdmoptions) {
1367 settings.optional_sdm_settings.sdm_options = sdmoptions[0];
1370 if (has_sdmaccess) {
1371 memcpy(settings.optional_sdm_settings.sdm_access, sdmaccess, 2);
1374 for (int i = 0; i < num_sdm_data; i++) {
1375 settings.optional_sdm_settings.sdm_data[i][2] = sdm_data[i][0];
1376 settings.optional_sdm_settings.sdm_data[i][1] = sdm_data[i][1];
1377 settings.optional_sdm_settings.sdm_data[i][0] = sdm_data[i][2];
1380 res = ntag424_write_file_settings(fileno, &settings, &session);
1381 DropField();
1382 if (res == PM3_SUCCESS) {
1383 PrintAndLogEx(SUCCESS, "Write settings ( " _GREEN_("ok") " )");
1384 ntag424_print_file_settings(fileno, &settings);
1385 } else {
1386 PrintAndLogEx(ERR, "Write settings (" _RED_("fail") " )");
1388 return res;
1391 static int CmdHF_ntag424_changekey(const char *Cmd) {
1393 CLIParserContext *ctx;
1394 CLIParserInit(&ctx, "hf ntag424 changekey",
1395 "Change a key.\n"
1396 "Authentication key must currently be different to the one we want to change.\n",
1397 "hf ntag424 changekey --keyno 1 --oldkey 00000000000000000000000000000000 --newkey 11111111111111111111111111111111 --key0 00000000000000000000000000000000 --kv 1\n"
1398 "hf ntag424 changekey --keyno 0 --newkey 11111111111111111111111111111111 --key0 00000000000000000000000000000000 --kv 1\n"
1400 void *argtable[] = {
1401 arg_param_begin,
1402 arg_int1(NULL, "keyno", "<dec>", "Key number to change"),
1403 arg_str0(NULL, "oldkey", "<hex>", "Old key (only needed when changing key 1-4, HEX 16 bytes)"),
1404 arg_str1(NULL, "newkey", "<hex>", "New key (HEX 16 bytes)"),
1405 arg_str1(NULL, "key0", "<hex>", "Authentication key (must be key 0, HEX 16 bytes)"),
1406 arg_int1(NULL, "kv", "<dec>", "New key version number"),
1407 arg_param_end
1409 CLIExecWithReturn(ctx, Cmd, argtable, false);
1411 uint8_t version = arg_get_int(ctx, 6);
1412 int keyno = arg_get_int(ctx, 1);
1414 uint8_t oldkey[16] = {0};
1415 if (keyno != 0) {
1416 if (ntag424_cli_get_auth_information(ctx, 0, 2, NULL, oldkey) != PM3_SUCCESS) {
1417 PrintAndLogEx(ERR, "Could not get keyno or old key");
1418 CLIParserFree(ctx);
1419 return PM3_EINVARG;
1423 uint8_t newkey[16] = {0};
1424 if (ntag424_cli_get_auth_information(ctx, 0, 3, NULL, newkey) != PM3_SUCCESS) {
1425 PrintAndLogEx(ERR, "Could not get new key");
1426 CLIParserFree(ctx);
1427 return PM3_EINVARG;
1430 uint8_t authkey[16] = {0};
1431 if (ntag424_cli_get_auth_information(ctx, 0, 4, NULL, authkey) != PM3_SUCCESS) {
1432 PrintAndLogEx(ERR, "Could not get authentication key");
1433 CLIParserFree(ctx);
1434 return PM3_EINVARG;
1436 CLIParserFree(ctx);
1438 if (SelectCard14443A_4(false, true, NULL) != PM3_SUCCESS) {
1439 DropField();
1440 PrintAndLogEx(ERR, "Failed to select card");
1441 return PM3_ERFTRANS;
1444 if (ntag424_select_application() != PM3_SUCCESS) {
1445 DropField();
1446 return PM3_ESOFT;
1449 int res = PM3_SUCCESS;
1450 ntag424_session_keys_t session = {0};
1451 res = ntag424_authenticate_ev2_first(0, authkey, &session);
1452 if (res != PM3_SUCCESS) {
1453 DropField();
1454 PrintAndLogEx(ERR, "Auth ( " _RED_("fail") " )");
1455 return PM3_ESOFT;
1456 } else {
1457 PrintAndLogEx(SUCCESS, "Auth ( " _GREEN_("ok") " )");
1460 res = ntag424_change_key(keyno, newkey, oldkey, version, &session);
1461 DropField();
1462 if (res == PM3_SUCCESS) {
1463 PrintAndLogEx(SUCCESS, "Change key %d ( " _GREEN_("ok") " )", keyno);
1464 } else {
1465 PrintAndLogEx(ERR, "Change key %d ( "_RED_("fail") " )", keyno);
1468 return res;
1471 static command_t CommandTable[] = {
1472 {"help", CmdHelp, AlwaysAvailable, "This help"},
1473 {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"},
1474 {"info", CmdHF_ntag424_info, IfPm3Iso14443a, "Tag information"},
1475 {"view", CmdHF_ntag424_view, AlwaysAvailable, "Display content from tag dump file"},
1476 {"auth", CmdHF_ntag424_auth, IfPm3Iso14443a, "Test authentication with key"},
1477 {"read", CmdHF_ntag424_read, IfPm3Iso14443a, "Read file"},
1478 {"write", CmdHF_ntag424_write, IfPm3Iso14443a, "Write file"},
1479 {"getfs", CmdHF_ntag424_getfilesettings, IfPm3Iso14443a, "Get file settings"},
1480 {"changefs", CmdHF_ntag424_changefilesettings, IfPm3Iso14443a, "Change file settings"},
1481 {"changekey", CmdHF_ntag424_changekey, IfPm3Iso14443a, "Change key"},
1482 {NULL, NULL, NULL, NULL}
1485 static int CmdHelp(const char *Cmd) {
1486 (void)Cmd; // Cmd is not used so far
1487 CmdsHelp(CommandTable);
1488 return PM3_SUCCESS;
1491 int CmdHF_ntag424(const char *Cmd) {
1492 clearCommandBuffer();
1493 return CmdsParse(CommandTable, Cmd);