1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency ISO14443A / NTAG424 DNA Commands
17 //-----------------------------------------------------------------------------
19 #include "cmdhfntag424.h"
21 #include "cmdparser.h"
22 #include "commonutil.h"
24 #include "iso7816/apduinfo.h"
25 #include "protocols.h"
26 #include "cliparser.h"
28 #include "fileutils.h" // saveFile
29 #include "crypto/libpcrypto.h" // aes_decode
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
{
62 // -------------- Encryption structs ---------------------------
68 } ntag424_ev2_response_t
;
71 uint16_t command_counter
;
73 uint8_t encryption
[16];
75 } ntag424_session_keys_t
;
81 } ntag424_communication_mode_t
;
83 const CLIParserOption ntag424_communication_mode_options
[] = {
84 {COMM_PLAIN
, "plain"},
86 {COMM_FULL
, "encrypt"},
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)
102 uint8_t sdm_access
[2];
103 uint8_t sdm_data
[8][3];
104 } ntag424_file_sdm_settings_t
;
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.
121 ntag424_file_sdm_settings_t optional_sdm_settings
;
122 } file_settings_write_t
;
124 // -------------- Version information structs -------------------------
129 uint8_t major_version
;
130 uint8_t minor_version
;
131 uint8_t storage_size
;
133 } PACKED ntag424_version_information_t
;
138 uint8_t fab_key_high
: 4;
140 uint8_t week_prod
: 7;
141 uint8_t fab_key_low
: 1;
143 } PACKED ntag424_production_information_t
;
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
) {
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
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];
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
) {
309 if (size
+ 8 > apdu_max_data_size
) {
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
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
323 ntag424_calc_send_iv(session_keys
, ivc
);
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
) {
335 if (padded_data_size
+ command_header_length
> apdu_max_data_size
) {
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;
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
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
) {
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");
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
) {
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
) {
382 uint8_t cmd
[256] = {0};
383 int apdu_length
= 256;
385 if (APDUEncode(&apdu
, cmd
, &apdu_length
) != 0) {
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
);
395 if (*response_length
< 2) {
396 PrintAndLogEx(ERR
, "No response");
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
));
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
);
415 memcpy(tmp
, response
, *response_length
);
416 aes_decode(iv
, session_keys
->encryption
, response
, tmp
, *response_length
- 10);
418 memcpy(response
, tmp
, *response_length
);
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
];
431 .ins
= NTAG424_CMD_GET_FILE_SETTINGS
,
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
) {
443 memcpy(settings_out
, response
, response_length
);
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
);
467 .ins
= NTAG424_CMD_CHANGE_FILE_SETTINGS
,
468 .lc
= 1 + settings_size
,
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);
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
];
517 res
= ExchangeAPDU14a(cmd
, sizeof(cmd
), false, true, resp
, RESPONSE_LENGTH
, &outlen
);
518 if (res
!= PM3_SUCCESS
) {
519 PrintAndLogEx(ERR
, "Failed to send apdu");
523 if (outlen
!= RESPONSE_LENGTH
|| resp
[RESPONSE_LENGTH
- 2] != 0x90 || resp
[RESPONSE_LENGTH
- 1] != 0x00) {
524 PrintAndLogEx(ERR
, "Failed to select application");
531 static int ntag424_auth_first_step(uint8_t keyno
, uint8_t *key
, uint8_t *out
) {
532 uint8_t key_number
[2] = { keyno
, 0x00 };
536 .ins
= NTAG424_CMD_AUTHENTICATE_EV2_FIRST
,
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
) {
549 if (response_length
!= 16 + 2) {
550 PrintAndLogEx(ERR
, "Failed to get RndB (invalid key number?)");
554 uint8_t iv
[16] = {0};
555 aes_decode(iv
, key
, response
, out
, 16);
560 static int ntag424_auth_second_step(uint8_t *challenge
, uint8_t *response_out
) {
563 .ins
= NTAG424_CMD_MORE_DATA
,
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
) {
575 memcpy(response_out
, response
, response_length
- 2);
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
) {
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
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
) {
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"
623 , sprint_hex(rnd_a_clear
, 16),
624 sprint_hex(response
.rnd_a
, 16));
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
);
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
[] = {
692 (uint8_t)(offset
<< 8),
693 (uint8_t)(offset
<< 16), // offset
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
);
706 .ins
= NTAG424_CMD_WRITE_DATA
,
707 .lc
= sizeof(cmd_header
) + num_bytes
,
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
) {
720 return ntag424_write_data(fileno
, offset
+ num_bytes
, remainder
, &in
[num_bytes
], comm_mode
, session_keys
);
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
[] = {
731 (uint8_t)offset
, (uint8_t)(offset
<< 8), (uint8_t)(offset
<< 16), // offset
732 (uint8_t)num_bytes
, (uint8_t)(num_bytes
>> 8), 0x00
737 .ins
= NTAG424_CMD_READ_DATA
,
738 .lc
= sizeof(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
) {
750 memcpy(out
, response
, num_bytes
);
754 static int ntag424_get_version(ntag424_full_version_information_t
*version
) {
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
) {
767 memcpy(&version
->hardware
, response
, sizeof(ntag424_version_information_t
));
769 APDU_t continue_apdu
= {
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
) {
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
) {
784 memcpy(&version
->production
, response
, sizeof(ntag424_production_information_t
));
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
;
796 .ins
= NTAG424_CMD_GET_SIGNATURE
,
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
) {
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};
816 for (int i
= 0; i
< 16; i
++) {
817 key
[i
] = old_key
[i
] ^ new_key
[i
];
819 crc32_ex(new_key
, 16, crc
);
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
;
831 memcpy(&key_cmd_data
[18], crc
, sizeof(crc
));
832 key_data_len
= sizeof(keyno
) + sizeof(key
) + sizeof(version
) + sizeof(crc
);
834 key_data_len
= sizeof(keyno
) + sizeof(key
) + sizeof(version
);
839 .ins
= NTAG424_CMD_CHANGE_KEY
,
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);
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"
862 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
863 arg_lit0("v", "verbose", "Verbose output"),
866 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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);
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
) {
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!");
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.",
905 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
908 if (SelectCard14443A_4(false, true, NULL
) != PM3_SUCCESS
) {
909 PrintAndLogEx(ERR
, "Failed to select card");
914 if (ntag424_select_application() != PM3_SUCCESS
) {
919 ntag424_full_version_information_t version
= {0};
920 if (ntag424_get_version(&version
) != PM3_SUCCESS
) {
924 ntag424_print_full_version_information(&version
);
926 uint8_t signature
[NXP_SIGNATURE_LENGTH
];
927 int res
= ntag424_get_signature(signature
);
930 if (res
== PM3_SUCCESS
) {
931 PrintAndLogEx(INFO
, "--- " _CYAN_("NXP originality signature:"));
932 desfire_print_signature(version
.production
.uid
, 7, signature
, NXP_SIGNATURE_LENGTH
);
938 static int ntag424_cli_get_auth_information(CLIParserContext
*ctx
, int keyno_index
, int key_index
, int *keyno
, uint8_t *key_out
) {
941 *keyno
= arg_get_int(ctx
, keyno_index
);
945 uint8_t key
[16] = {0};
947 if (CLIParamHexToBuf(arg_get_str(ctx
, key_index
), key
, sizeof(key
), &keylen
) || (keylen
!= 16)) {
951 memcpy(key_out
, key
, 16);
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");
963 arg_int1(NULL
, "keyno", "<dec>", "Key number"),
964 arg_str1("k", "key", "<hex>", "Key for authenticate (HEX 16 bytes)"),
967 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
970 uint8_t key
[16] = {0};
971 if (ntag424_cli_get_auth_information(ctx
, 1, 2, &keyno
, key
) != PM3_SUCCESS
) {
978 if (SelectCard14443A_4(false, true, NULL
) != PM3_SUCCESS
) {
979 PrintAndLogEx(ERR
, "Failed to select card");
984 if (ntag424_select_application() != PM3_SUCCESS
) {
989 int res
= ntag424_authenticate_ev2_first(keyno
, key
, NULL
);
990 if (res
!= PM3_SUCCESS
) {
991 PrintAndLogEx(ERR
, "Auth key %d ( " _RED_("fail") " )", keyno
);
993 PrintAndLogEx(SUCCESS
, "Auth key %d ( " _GREEN_("ok") " )", keyno
);
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
[] = {
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"),
1019 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1021 int fileno
= arg_get_int(ctx
, 1);
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
;
1032 if (CLIGetOptionList(arg_get_str(ctx
, 6), ntag424_communication_mode_options
, &comm_out
)) {
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");
1045 if (SelectCard14443A_4(false, true, NULL
) != PM3_SUCCESS
) {
1047 PrintAndLogEx(ERR
, "Failed to select card");
1048 return PM3_ERFTRANS
;
1051 if (ntag424_select_application() != PM3_SUCCESS
) {
1056 int res
= PM3_SUCCESS
;
1057 ntag424_session_keys_t session_keys
;
1059 res
= ntag424_authenticate_ev2_first(keyno
, key
, &session_keys
);
1060 if (res
!= PM3_SUCCESS
) {
1061 PrintAndLogEx(ERR
, "Auth key %d ( " _RED_("fail") " )", keyno
);
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
);
1072 if (res
== PM3_SUCCESS
) {
1073 PrintAndLogEx(SUCCESS
, " -------- Read file " _YELLOW_("%d") " contents ------------ ", fileno
);
1074 print_hex_break(data
, read_length
, 16);
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
[] = {
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"),
1096 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1098 int fileno
= arg_get_int(ctx
, 1);
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};
1108 CLIGetHexWithReturn(ctx
, 5, data
, &datalen
);
1110 ntag424_communication_mode_t comm_mode
;
1112 if (CLIGetOptionList(arg_get_str(ctx
, 6), ntag424_communication_mode_options
, &comm_out
)) {
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");
1125 if (SelectCard14443A_4(false, true, NULL
) != PM3_SUCCESS
) {
1127 PrintAndLogEx(ERR
, "Failed to select card");
1128 return PM3_ERFTRANS
;
1131 if (ntag424_select_application() != PM3_SUCCESS
) {
1136 int res
= PM3_SUCCESS
;
1137 ntag424_session_keys_t session_keys
= {0};
1139 res
= ntag424_authenticate_ev2_first(keyno
, key
, &session_keys
);
1140 if (res
!= PM3_SUCCESS
) {
1141 PrintAndLogEx(ERR
, "Auth key %d ( " _RED_("fail") " )", keyno
);
1145 PrintAndLogEx(SUCCESS
, "Auth key %d ( " _GREEN_("ok") " )", keyno
);
1149 res
= ntag424_write_data(fileno
, offset
, (uint32_t)datalen
, data
, comm_mode
, &session_keys
);
1151 if (res
== PM3_SUCCESS
) {
1152 PrintAndLogEx(SUCCESS
, "Wrote " _YELLOW_("%d") " bytes ( " _GREEN_("ok") " )", datalen
);
1154 PrintAndLogEx(ERR
, "Wrote " _YELLOW_("%d") " bytes ( " _RED_("fail") " )", datalen
);
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
[] = {
1167 arg_int1(NULL
, "fileno", "<dec>", "File number"),
1170 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1171 int fileno
= arg_get_int(ctx
, 1);
1175 if (SelectCard14443A_4(false, true, NULL
) != PM3_SUCCESS
) {
1177 PrintAndLogEx(ERR
, "Failed to select card");
1178 return PM3_ERFTRANS
;
1181 if (ntag424_select_application() != PM3_SUCCESS
) {
1186 ntag424_file_settings_t settings
= {0};
1187 int res
= ntag424_get_file_settings(fileno
, &settings
);
1189 if (res
== PM3_SUCCESS
) {
1190 ntag424_print_file_settings(fileno
, &settings
);
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"
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"
1210 " 0 ASCII encoding\n"
1211 " 4 SDMEncFileData\n"
1212 " 5 SDMReadCtrLimit\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
[] = {
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...
1249 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1250 int fileno
= arg_get_int(ctx
, 1);
1253 uint8_t key
[16] = {0};
1255 uint8_t has_options
= 0;
1257 uint8_t has_access
= 0;
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");
1273 if (arg_get_str(ctx
, 4)->count
== 1) {
1275 CLIGetHexWithReturn(ctx
, 4, options
, &len
);
1277 PrintAndLogEx(ERR
, "Options must be 1 byte, got ( %d )", len
);
1283 if (arg_get_str(ctx
, 5)->count
== 1) {
1285 CLIGetHexWithReturn(ctx
, 5, access
, &len
);
1287 PrintAndLogEx(ERR
, "Access must be 2 bytes, got ( %d )", len
);
1293 if (arg_get_str(ctx
, 6)->count
== 1) {
1295 CLIGetHexWithReturn(ctx
, 6, sdmoptions
, &len
);
1297 PrintAndLogEx(ERR
, "SDM Options must be 1 byte, got ( %d )", len
);
1303 if (arg_get_str(ctx
, 7)->count
== 1) {
1305 CLIGetHexWithReturn(ctx
, 7, sdmaccess
, &len
);
1307 PrintAndLogEx(ERR
, "SDM Access must be 2 bytes, got ( %d )", len
);
1313 for (int i
= 0; i
< 8; i
++) {
1314 if (arg_get_str(ctx
, 8 + i
)->count
== 1) {
1317 CLIGetHexWithReturn(ctx
, 8 + i
, sdm_data
[i
], &len
);
1319 PrintAndLogEx(ERR
, "sdmdata must be 3 bytes, got ( %d )", len
);
1330 if (SelectCard14443A_4(false, true, NULL
) != PM3_SUCCESS
) {
1332 PrintAndLogEx(ERR
, "Failed to select card");
1333 return PM3_ERFTRANS
;
1336 if (ntag424_select_application() != PM3_SUCCESS
) {
1341 ntag424_file_settings_t settings
= {0};
1342 if (ntag424_get_file_settings(fileno
, &settings
) != PM3_SUCCESS
) {
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
);
1355 PrintAndLogEx(SUCCESS
, "Auth key %d ( " _GREEN_("ok") " )", keyno
);
1359 settings
.options
= options
[0];
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
);
1382 if (res
== PM3_SUCCESS
) {
1383 PrintAndLogEx(SUCCESS
, "Write settings ( " _GREEN_("ok") " )");
1384 ntag424_print_file_settings(fileno
, &settings
);
1386 PrintAndLogEx(ERR
, "Write settings (" _RED_("fail") " )");
1391 static int CmdHF_ntag424_changekey(const char *Cmd
) {
1393 CLIParserContext
*ctx
;
1394 CLIParserInit(&ctx
, "hf ntag424 changekey",
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
[] = {
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"),
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};
1416 if (ntag424_cli_get_auth_information(ctx
, 0, 2, NULL
, oldkey
) != PM3_SUCCESS
) {
1417 PrintAndLogEx(ERR
, "Could not get keyno or old key");
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");
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");
1438 if (SelectCard14443A_4(false, true, NULL
) != PM3_SUCCESS
) {
1440 PrintAndLogEx(ERR
, "Failed to select card");
1441 return PM3_ERFTRANS
;
1444 if (ntag424_select_application() != PM3_SUCCESS
) {
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
) {
1454 PrintAndLogEx(ERR
, "Auth ( " _RED_("fail") " )");
1457 PrintAndLogEx(SUCCESS
, "Auth ( " _GREEN_("ok") " )");
1460 res
= ntag424_change_key(keyno
, newkey
, oldkey
, version
, &session
);
1462 if (res
== PM3_SUCCESS
) {
1463 PrintAndLogEx(SUCCESS
, "Change key %d ( " _GREEN_("ok") " )", keyno
);
1465 PrintAndLogEx(ERR
, "Change key %d ( "_RED_("fail") " )", keyno
);
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
);
1491 int CmdHF_ntag424(const char *Cmd
) {
1492 clearCommandBuffer();
1493 return CmdsParse(CommandTable
, Cmd
);