From b2eca838c426b815e9a32cbfa80fa0284d62fde9 Mon Sep 17 00:00:00 2001 From: Martin Dagarin Date: Tue, 27 Jun 2017 10:50:50 +0200 Subject: [PATCH] Added support for NTAG 21x tags (#53) --- README.md | 1 + examples/CMakeLists.txt | 4 + examples/Makefile.am | 18 +- examples/ntag-detect.c | 68 +++ examples/ntag-removeauth.c | 146 +++++++ examples/ntag-setauth.c | 146 +++++++ examples/ntag-write.c | 119 ++++++ libfreefare/CMakeLists.txt | 1 + libfreefare/Makefile.am | 2 + libfreefare/freefare.c | 4 + libfreefare/freefare.h | 54 +++ libfreefare/freefare_internal.h | 23 ++ libfreefare/ntag21x.3 | 132 ++++++ libfreefare/ntag21x.c | 703 ++++++++++++++++++++++++++++++++ 14 files changed, 1420 insertions(+), 1 deletion(-) create mode 100644 examples/ntag-detect.c create mode 100644 examples/ntag-removeauth.c create mode 100644 examples/ntag-setauth.c create mode 100644 examples/ntag-write.c create mode 100644 libfreefare/ntag21x.3 create mode 100644 libfreefare/ntag21x.c diff --git a/README.md b/README.md index dce4145..23e2e42 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ If you are new to _libfreefare_ or the _nfc-tools_, you should collect useful in | MIFARE Plus X 4k | Not supported | | MIFARE Ultralight | Supported | | MIFARE Ultralight C | Supported | +| NTAG21x | Supported | ## Specifications | Specification | Status | diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a5dcd32..575bafe 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,6 +12,10 @@ set(EXAMPLES-SOURCES mifare-desfire-ev1-configure-default-key mifare-desfire-ev1-configure-random-uid mifare-ultralight-info + ntag-detect + ntag-removeauth + ntag-setauth + ntag-write ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../libfreefare) diff --git a/examples/Makefile.am b/examples/Makefile.am index eece1dd..cd1387d 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -15,7 +15,11 @@ bin_PROGRAMS = felica-lite-dump \ mifare-desfire-info \ mifare-desfire-read-ndef \ mifare-desfire-write-ndef \ - mifare-ultralight-info + mifare-ultralight-info \ + ntag-detect \ + ntag-removeauth \ + ntag-setauth \ + ntag-write felica_lite_dump_SOURCES = felica-lite-dump.c felica_lite_dump_LDADD = $(top_builddir)/libfreefare/libfreefare.la @@ -62,4 +66,16 @@ mifare_desfire_write_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la mifare_ultralight_info_SOURCES = mifare-ultralight-info.c mifare_ultralight_info_LDADD = $(top_builddir)/libfreefare/libfreefare.la +ntag_detect_SOURCES = ntag-detect.c +ntag_detect_LDADD = $(top_builddir)/libfreefare/libfreefare.la + +ntag_removeauth_SOURCES = ntag-removeauth.c +ntag_removeauth_LDADD = $(top_builddir)/libfreefare/libfreefare.la + +ntag_setauth_SOURCES = ntag-setauth.c +ntag_setauth_LDADD = $(top_builddir)/libfreefare/libfreefare.la + +ntag_write_SOURCES = ntag-write.c +ntag_write_LDADD = $(top_builddir)/libfreefare/libfreefare.la + CLEANFILES= *.gcno diff --git a/examples/ntag-detect.c b/examples/ntag-detect.c new file mode 100644 index 0000000..e8ffcc3 --- /dev/null +++ b/examples/ntag-detect.c @@ -0,0 +1,68 @@ +/*- + * Copyright (C) 2012, 2017 Romain Tartiere, Martin Dagarin (SloCompTech). + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ +#include +#include + +#include + +#include + +int +main(int argc, char *argv[]) +{ + int error = EXIT_SUCCESS; + nfc_device *device = NULL; + FreefareTag *tags = NULL; + + if (argc > 1) + errx(EXIT_FAILURE, "usage: %s", argv[0]); + + nfc_connstring devices[8]; + size_t device_count; + + nfc_context *context; + nfc_init(&context); + if (context == NULL) + errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); + + device_count = nfc_list_devices (context, devices, sizeof (devices) / sizeof (*devices)); + if (device_count <= 0) + errx(EXIT_FAILURE, "No NFC device found"); + + for (size_t d = 0; d < device_count; d++) { + if (!(device = nfc_open(context, devices[d]))) { + warnx("nfc_open() failed."); + error = EXIT_FAILURE; + continue; + } + + if (!(tags = freefare_get_tags(device))) { + nfc_close(device); + errx(EXIT_FAILURE, "Error listing tags."); + } + + for (int i = 0; (!error) && tags[i]; i++) { + char *tag_uid = freefare_get_tag_uid(tags[i]); + printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name(tags[i])); + free(tag_uid); + } + freefare_free_tags(tags); + nfc_close(device); + } + nfc_exit(context); + exit(error); +} diff --git a/examples/ntag-removeauth.c b/examples/ntag-removeauth.c new file mode 100644 index 0000000..38726cd --- /dev/null +++ b/examples/ntag-removeauth.c @@ -0,0 +1,146 @@ +/*- + * Copyright (C) 2012, 2017 Romain Tartiere, Martin Dagarin (SloCompTech). + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ +#include +#include + +#include + +#include + + +int +main(int argc, char *argv[]) +{ + int error = EXIT_SUCCESS; + nfc_device *device = NULL; + FreefareTag *tags = NULL; + + if (argc > 1) + errx(EXIT_FAILURE, "usage: %s", argv[0]); + + nfc_connstring devices[8]; + size_t device_count; + + nfc_context *context; + nfc_init(&context); + if (context == NULL) + errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); + + device_count = nfc_list_devices(context, devices, sizeof (devices) / sizeof (*devices)); + if (device_count <= 0) + errx(EXIT_FAILURE, "No NFC device found"); + + for (size_t d = 0; d < device_count; d++) { + if (!(device = nfc_open(context, devices[d]))) { + warnx("nfc_open() failed."); + error = EXIT_FAILURE; + continue; + } + + if (!(tags = freefare_get_tags(device))) { + nfc_close(device); + errx(EXIT_FAILURE, "Error listing tags."); + } + + for (int i = 0; (!error) && tags[i]; i++) { + switch (freefare_get_tag_type(tags[i])) { + case NTAG_21x: + break; + default: + continue; + } + + char *tag_uid = freefare_get_tag_uid(tags[i]); + printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name(tags[i])); + FreefareTag tag = tags[i]; + int res; + if (ntag21x_connect(tag) < 0) + errx(EXIT_FAILURE, "Error connecting to tag."); + + uint8_t pwd[4] = {0xff,0xff,0xff,0xff}; + uint8_t pack[2] = {0xaa,0xaa}; + uint8_t pack_old[2] = {0x00,0x00}; + + NTAG21xKey key; + NTAG21xKey key_old; + key = ntag21x_key_new(pwd,pack); // Creating key + key_old = ntag21x_key_new(pwd,pack_old); // Creating key + + uint8_t auth0 = 0x00; // Buffer for auth0 byte + + switch (true) { + case true: + /* + Get information about tag + MUST do, because here we are recognizing tag subtype (NTAG213,NTAG215,NTAG216), and gathering all parameters + */ + res = ntag21x_get_info(tag); + if(res < 0) { + printf("Error getting info from tag\n"); + break; + } + // Authenticate with tag + res = ntag21x_authenticate(tag,key); + if(res < 0) { + printf("Error getting info from tag\n"); + break; + } + // Get auth byte from tag + res = ntag21x_get_auth(tag,&auth0); + if(res < 0) { + printf("Error getting auth0 byte from tag\n"); + break; + } + printf("Old auth0: %#02x\n",auth0); + // Set old key + res = ntag21x_set_key(tag,key_old); + if(res < 0) { + printf("Error setting key tag\n"); + break; + } + // Disable password protection (when auth0 byte > last page) + res = ntag21x_set_auth(tag,0xff); + if(res<0) { + printf("Error setting auth0 byte \n"); + break; + } + // Disable read & write pwd protection -> (default: write only protection) + res = ntag21x_access_disable(tag,NTAG_PROT); + if(res < 0) { + printf("Error setting access byte \n"); + break; + } + // Get auth byte from tag + res = ntag21x_get_auth(tag,&auth0); + if(res < 0) { + printf("Error getting auth0 byte from tag\n"); + break; + } + printf("New auth0: %#02x\n",auth0); + } + + ntag21x_disconnect(tag); + ntag21x_key_free(key); // Delete key + ntag21x_key_free(key_old); // Delete key + free(tag_uid); + } + freefare_free_tags(tags); + nfc_close(device); + } + nfc_exit(context); + exit(error); +} diff --git a/examples/ntag-setauth.c b/examples/ntag-setauth.c new file mode 100644 index 0000000..57888f0 --- /dev/null +++ b/examples/ntag-setauth.c @@ -0,0 +1,146 @@ +/*- + * Copyright (C) 2012, 2017 Romain Tartiere, Martin Dagarin (SloCompTech). + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ +#include +#include + +#include + +#include + + +int +main(int argc, char *argv[]) +{ + int error = EXIT_SUCCESS; + nfc_device *device = NULL; + FreefareTag *tags = NULL; + + if (argc > 1) + errx(EXIT_FAILURE, "usage: %s", argv[0]); + + nfc_connstring devices[8]; + size_t device_count; + + nfc_context *context; + nfc_init (&context); + if (context == NULL) + errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); + + device_count = nfc_list_devices (context, devices, sizeof (devices) / sizeof (*devices)); + if (device_count <= 0) + errx(EXIT_FAILURE, "No NFC device found"); + + for (size_t d = 0; d < device_count; d++) { + if (!(device = nfc_open (context, devices[d]))) { + warnx("nfc_open() failed."); + error = EXIT_FAILURE; + continue; + } + + if (!(tags = freefare_get_tags (device))) { + nfc_close(device); + errx(EXIT_FAILURE, "Error listing tags."); + } + + for (int i = 0; (!error) && tags[i]; i++) { + switch (freefare_get_tag_type(tags[i])) { + case NTAG_21x: + break; + default: + continue; + } + + char *tag_uid = freefare_get_tag_uid(tags[i]); + printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name(tags[i])); + FreefareTag tag = tags[i]; + int res; + if (ntag21x_connect (tag) < 0) + errx(EXIT_FAILURE, "Error connecting to tag."); + + uint8_t pwd[4] = {0xff,0xff,0xff,0xff}; + uint8_t pack[2] = {0xaa,0xaa}; + + NTAG21xKey key; + key = ntag21x_key_new(pwd,pack); // Creating key + + uint8_t auth0 = 0x00; // Buffer for auth0 byte + uint8_t authlim = 0x00; + switch (true) { + case true: + /* + Get information about tag + MUST do, because here we are recognizing tag subtype (NTAG213,NTAG215,NTAG216), and gathering all parameters + */ + res = ntag21x_get_info(tag); + if(res < 0) { + printf("Error getting info from tag\n"); + break; + } + // Get auth byte from tag + res = ntag21x_get_auth(tag,&auth0); + if(res < 0) { + printf("Error getting auth0 byte from tag\n"); + break; + } + printf("Old auth0: %#02x\n",auth0); + res = ntag21x_get_authentication_limit(tag,&authlim); + if(res < 0) { + printf("Error getting auth0 byte from tag\n"); + break; + } + printf("Authlim: %#02x\n",authlim); + // Check if auth is required to set pwd and pack + if(auth0 < ntag21x_get_last_page(tag) - 2) { // Check if last 2 pages are protected + printf("Error: pwd and PACK sections are protected with unknown password\n"); + break; + } + // Set key + res = ntag21x_set_key(tag,key); + if(res < 0) { + printf("Error setting key tag\n"); + break; + } + // Protect last 6 pages !! It can be hacked if you don't protect last 4 pages where auth0 byte is located + res = ntag21x_set_auth(tag,ntag21x_get_last_page(tag)-5); + if(res < 0) { + printf("Error setting auth0 byte \n"); + break; + } + // Enable read & write pwd protection (default: write only protection) + res = ntag21x_access_enable(tag,NTAG_PROT); + if(res < 0) { + printf("Error setting access byte \n"); + break; + } + // Get auth byte from tag + res = ntag21x_get_auth(tag,&auth0); + if(res < 0) { + printf("Error getting auth0 byte from tag\n"); + break; + } + printf("New auth0: %#02x\n",auth0); + } + ntag21x_disconnect (tag); + ntag21x_key_free(key); // Delete key + free (tag_uid); + } + freefare_free_tags(tags); + nfc_close(device); + } + nfc_exit(context); + exit(error); +} diff --git a/examples/ntag-write.c b/examples/ntag-write.c new file mode 100644 index 0000000..a512cd4 --- /dev/null +++ b/examples/ntag-write.c @@ -0,0 +1,119 @@ +/*- + * Copyright (C) 2012, 2017 Romain Tartiere, Martin Dagarin (SloCompTech). + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ +#include +#include + +#include + +#include + + +int +main(int argc, char *argv[]) +{ + int error = EXIT_SUCCESS; + nfc_device *device = NULL; + FreefareTag *tags = NULL; + + if (argc > 1) + errx(EXIT_FAILURE, "usage: %s", argv[0]); + + nfc_connstring devices[8]; + size_t device_count; + + nfc_context *context; + nfc_init(&context); + if (context == NULL) + errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); + + device_count = nfc_list_devices(context, devices, sizeof (devices) / sizeof (*devices)); + if (device_count <= 0) + errx(EXIT_FAILURE, "No NFC device found"); + + for (size_t d = 0; d < device_count; d++) { + if (!(device = nfc_open(context, devices[d]))) { + warnx("nfc_open() failed."); + error = EXIT_FAILURE; + continue; + } + + if (!(tags = freefare_get_tags(device))) { + nfc_close(device); + errx(EXIT_FAILURE, "Error listing tags."); + } + + for (int i = 0; (!error) && tags[i]; i++) { + switch (freefare_get_tag_type(tags[i])) { + case NTAG_21x: + break; + default: + continue; + } + + char *tag_uid = freefare_get_tag_uid(tags[i]); + printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name (tags[i])); + FreefareTag tag = tags[i]; + int res; + if (ntag21x_connect(tag) < 0) + errx(EXIT_FAILURE, "Error connecting to tag."); + + uint8_t data [4] = {0xfa,0xca,0xac,0xad}; // Data to write on tag + uint8_t read[4]; // Buffer for reading data from tag + + bool flag_match = true; + switch (true) { + case true: + /* + Get information about tag + MUST do, because here we are recognizing tag subtype (NTAG213,NTAG215,NTAG216), and gathering all parameters + */ + res = ntag21x_get_info(tag); + if(res < 0) { + printf("Error getting info from tag\n"); + break; + } + + // writing to tag 4 bytes on page 0x27 (check specs for NTAG21x before changing page number !!!) + res = ntag21x_write(tag,0x27,data); + if(res < 0) { + printf("Error writing to tag\n"); + break; + } + res = ntag21x_fast_read4(tag,0x27,read); // Reading page from tag (4 bytes), you can also use ntag21x_read4 or ntag21x_read (16 bytes) or ntag21x_fast_read (start_page to end_page) + if(res < 0) { + printf("Error reading tag\n"); + break; + } + for(int i=0;i < 4;i++) // Checking if we can read what we have written earlyer + if(data[i] != read[i]) { + flag_match = false; + break; + } + if(!flag_match) + printf("Data don't match\n"); + else + printf("Data match\n"); + } + ntag21x_disconnect(tag); + free(tag_uid); + } + freefare_free_tags(tags); + nfc_close(device); + } + nfc_exit(context); + exit(error); +} diff --git a/libfreefare/CMakeLists.txt b/libfreefare/CMakeLists.txt index a818aa0..312b9dc 100644 --- a/libfreefare/CMakeLists.txt +++ b/libfreefare/CMakeLists.txt @@ -11,6 +11,7 @@ set(LIBRARY_SOURCES mifare_desfire_error mifare_desfire_key mifare_ultralight + ntag21x tlv ../contrib/libutil/hexdump ) diff --git a/libfreefare/Makefile.am b/libfreefare/Makefile.am index da2d652..cddb74b 100644 --- a/libfreefare/Makefile.am +++ b/libfreefare/Makefile.am @@ -14,6 +14,7 @@ libfreefare_la_SOURCES = felica.c \ mifare_desfire_key.c \ mad.c \ mifare_application.c \ + ntag21x.c \ tlv.c libfreefare_la_LIBADD = @@ -39,6 +40,7 @@ man_MANS = freefare.3 \ mifare_desfire_aid.3 \ mifare_desfire_key.3 \ mifare_ultralight.3 \ + ntag21x.3 \ tlv.3 linkedman = \ diff --git a/libfreefare/freefare.c b/libfreefare/freefare.c index 9a64fe6..b0c1921 100644 --- a/libfreefare/freefare.c +++ b/libfreefare/freefare.c @@ -48,6 +48,8 @@ freefare_tag_new (nfc_device *device, nfc_target target) tag = mifare_classic4k_tag_new (device, target); } else if (mifare_desfire_taste (device, target)) { tag = mifare_desfire_tag_new (device, target); + } else if (ntag21x_taste (device, target)) { + tag = ntag21x_tag_new (device, target); } else if (mifare_ultralightc_taste (device, target)) { tag = mifare_ultralightc_tag_new (device, target); } else if (mifare_ultralight_taste (device, target)) { @@ -171,6 +173,8 @@ freefare_get_tag_friendly_name (FreefareTag tag) return "Mifare UltraLightC"; case MIFARE_ULTRALIGHT: return "Mifare UltraLight"; + case NTAG_21x: + return "NTAG21x"; default: return "UNKNOWN"; } diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index a4f69da..875be91 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -40,6 +40,7 @@ enum freefare_tag_type { // MIFARE_PLUS_X4K, MIFARE_ULTRALIGHT, MIFARE_ULTRALIGHT_C, + NTAG_21x, }; struct freefare_tag; @@ -51,6 +52,9 @@ typedef struct freefare_tag *MifareTag __attribute__ ((deprecated)); struct mifare_desfire_key; typedef struct mifare_desfire_key *MifareDESFireKey; +struct ntag21x_key; +typedef struct ntag21x_key *NTAG21xKey; + typedef uint8_t MifareUltralightPageNumber; typedef unsigned char MifareUltralightPage[4]; @@ -104,6 +108,56 @@ bool is_mifare_ultralightc_on_reader (nfc_device *device, nfc_iso14443a_info n +bool ntag21x_taste (nfc_device *device, nfc_target target); + +/* NTAG21x access features */ +#define NTAG_PROT 0x80 +#define NTAG_CFGLCK 0x40 +#define NTAG_NFC_CNT_EN 0x20 +#define NTAG_NFC_CNT_PWD_PROT 0x10 +#define NTAG_AUTHLIM 0x07 + +enum ntag_tag_subtype { + NTAG_213, + NTAG_215, + NTAG_216 +}; + +FreefareTag ntag21x_tag_new (nfc_device *device, nfc_target target); +FreefareTag ntag21x_tag_reuse (FreefareTag tag); /* Copy data from Ultralight tag to new NTAG21x, don't forget to free your old tag */ +NTAG21xKey ntag21x_key_new (const uint8_t data[4],const uint8_t pack[2]); /* Create new key */ +void ntag21x_key_free (NTAG21xKey key); /* Clear key from memory */ +void ntag21x_tag_free (FreefareTag tag); +int ntag21x_connect (FreefareTag tag); +int ntag21x_disconnect (FreefareTag tag); +int ntag21x_get_info (FreefareTag tag); /* Get all information about tag (size,vendor ...) */ +enum ntag_tag_subtype ntag21x_get_subtype (FreefareTag tag); /* Get subtype of tag */ +uint8_t ntag21x_get_last_page (FreefareTag tag); /* Get last page address based on gathered info from function above */ +int ntag21x_read_signature (FreefareTag tag,uint8_t *data); /* Get tag signature */ +int ntag21x_set_pwd (FreefareTag tag, uint8_t data[4]); /* Set password */ +int ntag21x_set_pack (FreefareTag tag, uint8_t data[2]); /* Set pack */ +int ntag21x_set_key (FreefareTag tag,const NTAG21xKey key); /* Set key */ +int ntag21x_set_auth (FreefareTag tag,uint8_t byte); /* Set AUTH0 byte (from which page starts password protection) */ +int ntag21x_get_auth (FreefareTag tag,uint8_t *byte); /* Get AUTH0 byte */ +int ntag21x_access_enable (FreefareTag tag,uint8_t byte); /* Enable access feature in ACCESS byte */ +int ntag21x_access_disable (FreefareTag tag,uint8_t byte); /* Disable access feature in ACCESS byte */ +int ntag21x_get_access (FreefareTag tag,uint8_t *byte); /* Get ACCESS byte */ +int ntag21x_check_access (FreefareTag tag,uint8_t byte,bool *result); /* Check if access feature is enabled */ +int ntag21x_get_authentication_limit (FreefareTag tag,uint8_t *byte); /* Get authentication limit */ +int ntag21x_set_authentication_limit (FreefareTag tag,uint8_t byte); /* Set authentication limit (0x00 = disabled, [0x01,0x07] = valid range, > 0x07 invalid range) */ +int ntag21x_read (FreefareTag tag, uint8_t page,uint8_t *data); /* Read 16 bytes starting from page */ +int ntag21x_read4 (FreefareTag tag,uint8_t page,uint8_t *data); /* Read 4 bytes on page */ +int ntag21x_fast_read (FreefareTag tag, uint8_t start_page,uint8_t end_page, uint8_t *data); /* Read n*4 bytes from range [start_page,end_page] */ +int ntag21x_fast_read4 (FreefareTag tag,uint8_t page,uint8_t *data); /* Fast read certain page */ +int ntag21x_read_cnt (FreefareTag tag, uint8_t *data); /* Read 3-byte NFC counter if enabled else it returns error */ +int ntag21x_write (FreefareTag tag, uint8_t page, uint8_t data[4]); /* Write 4 bytes to page */ +int ntag21x_compatibility_write (FreefareTag tag, uint8_t page, uint8_t data[4]); /* Writes 4 bytes to page with mifare classic write */ +int ntag21x_authenticate (FreefareTag tag, const NTAG21xKey key); /* Authenticate with tag */ +bool is_ntag21x (FreefareTag tag); /* Check if tag type is NTAG21x */ +bool ntag21x_is_auth_supported (nfc_device *device, nfc_iso14443a_info nai); /* Check if tag supports 21x commands */ + + + bool mifare_mini_taste (nfc_device *device, nfc_target target); bool mifare_classic1k_taste (nfc_device *device, nfc_target target); bool mifare_classic4k_taste (nfc_device *device, nfc_target target); diff --git a/libfreefare/freefare_internal.h b/libfreefare/freefare_internal.h index 11e11cd..abc3b77 100644 --- a/libfreefare/freefare_internal.h +++ b/libfreefare/freefare_internal.h @@ -243,6 +243,28 @@ struct mifare_ultralight_tag { uint8_t cached_pages[MIFARE_ULTRALIGHT_MAX_PAGE_COUNT]; }; +/* + NTAG section +*/ + +struct ntag21x_tag { + struct freefare_tag __tag; + + int subtype; + uint8_t vendor_id; + uint8_t product_type; + uint8_t product_subtype; + uint8_t major_product_version; + uint8_t minor_product_version; + uint8_t storage_size; + uint8_t protocol_type; +}; + +struct ntag21x_key { + uint8_t data[4]; // 4B key + uint8_t pack[2]; // 2B Password Acknowlege +} ntag21x_key; + /* * FreefareTag assertion macros * @@ -262,6 +284,7 @@ struct mifare_ultralight_tag { #define MIFARE_CLASSIC(tag) ((struct mifare_classic_tag *) tag) #define MIFARE_DESFIRE(tag) ((struct mifare_desfire_tag *) tag) #define MIFARE_ULTRALIGHT(tag) ((struct mifare_ultralight_tag *) tag) +#define NTAG_21x(tag) ((struct ntag21x_tag *) tag) /* * Access bits manipulation macros diff --git a/libfreefare/ntag21x.3 b/libfreefare/ntag21x.3 new file mode 100644 index 0000000..25d355c --- /dev/null +++ b/libfreefare/ntag21x.3 @@ -0,0 +1,132 @@ +.\" Copyright (C) 2010, 2017 Romain Tartiere, Martin Dagarin (SloCompTech) +.\" +.\" This program is free software: you can redistribute it and/or modify it +.\" under the terms of the GNU Lesser General Public License as published by the +.\" Free Software Foundation, either version 3 of the License, or (at your +.\" option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, but WITHOUT +.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +.\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +.\" more details. +.\" +.\" You should have received a copy of the GNU Lesser General Public License +.\" along with this program. If not, see +.\" +.Dd February 26, 2017 +.Dt NTAG_21x 3 +.Os +.\" _ _ +.\" | \ | | __ _ _ __ ___ ___ +.\" | \| |/ _` | '_ ` _ \ / _ \ +.\" | |\ | (_| | | | | | | __/ +.\" |_| \_|\__,_|_| |_| |_|\___| +.\" +.Sh NAME +.Nm ntag21x_connect , +.Nm ntag21x_disconnect , +.Nm ntag21x_read , +.Nm ntag21x_read4 , +.Nm ntag21x_fast_read , +.Nm ntag21x_fast_read4 , +.Nm ntag21x_write , +.Nm ntag21x_compatibility_write , +.Nd NTAG 213/215/216 Manipulation Functions +.\" _ _ _ +.\" | | (_) |__ _ __ __ _ _ __ _ _ +.\" | | | | '_ \| '__/ _` | '__| | | | +.\" | |___| | |_) | | | (_| | | | |_| | +.\" |_____|_|_.__/|_| \__,_|_| \__, | +.\" |___/ +.Sh LIBRARY +Mifare card manipulation library (libfreefare, \-lfreefare) +.\" ____ _ +.\" / ___| _ _ _ __ ___ _ __ ___(_)___ +.\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| +.\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ +.\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ +.\" |___/ |_| +.Sh SYNOPSIS +.In freefare.h +.Ft int +.Fn ntag21x_connect "FreefareTag tag" +.Ft int +.Fn ntag21x_disconnect "FreefareTag tag" +.Ft int +.Fn ntag21x_read "FreefareTag tag" "uint8_t page" "uint8_t *data" +.Ft int +.Fn ntag21x_read4 "FreefareTag tag" "uint8_t page" "uint8_t *data" +.Ft int +.Fn ntag21x_fast_read "FreefareTag tag" "uint8_t start_page" "uint8_t end_page" "uint8_t *data" +.Ft int +.Fn ntag21x_fast_read4 "FreefareTag tag" "uint8_t page" "uint8_t *data" +.Ft int +.Fn ntag21x_write "FreefareTag tag" "uint8_t page" "uint8_t data[4]" +.Ft int +.Fn ntag21x_compatibility_write "FreefareTag tag" "uint8_t page" "uint8_t data[4]" +.\" ____ _ _ _ +.\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ +.\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ +.\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | +.\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| +.\" |_| +.Sh DESCRIPTION +The +.Fn ntag21x_* +functions allows management of NTAG213/215/216 tags. +.Pp +The +.Fn ntag21x_connect +function activates the specified +.Vt tag . +.Pp +A +.Vt page +of +.Vt data +can be read from a +.Vt tag +using +.Fn ntag21x_read , +.Fn ntag21x_read4, +.Fn ntag21x_fast_read, +.Fn ntag21x_fast_read4, +and written +using +.Fn ntag21_write , +.Fn ntag21x_compatibility_write . +.Pp +After usage, a +.Vt tag +is deactivated using +.Fn ntag21x_disconnect . +.\" ____ _ _ +.\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ +.\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| +.\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ +.\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ +.\" +.Sh RETURN VALUES +Unless stated otherwise, all functions return a value greater than or equal to +.Va 0 +on success or +.Va -1 +on failure. +.\" ____ _ +.\" / ___| ___ ___ __ _| |___ ___ +.\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ +.\" ___) | __/ __/ | (_| | \__ \ (_) | +.\" |____/ \___|\___| \__,_|_|___/\___/ +.\" +.Sh SEE ALSO +.Xr freefare 3 +.\" _ _ _ +.\" / \ _ _| |_| |__ ___ _ __ ___ +.\" / _ \| | | | __| '_ \ / _ \| '__/ __| +.\" / ___ \ |_| | |_| | | | (_) | | \__ \ +.\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ +.\" +.Sh AUTHORS +.An Romain Tartiere Aq romain@blogreen.org +.An Romuald Conty Aq romuald@libnfc.org +.An Martin Dagarin Aq SloCompTech@gmail.com diff --git a/libfreefare/ntag21x.c b/libfreefare/ntag21x.c new file mode 100644 index 0000000..0726dcf --- /dev/null +++ b/libfreefare/ntag21x.c @@ -0,0 +1,703 @@ +/*- + * Copyright (C) 2017, Martin Dagarin. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ + +/* + * This implementation was written based on information provided by the + * following documents: + * + * Contactless Single-trip Ticket IC + * MF0 IC U1 + * Functional Specification + * Revision 3.0 + * March 2003 + * + * NTAG213/215/216 + * NFC Forum Type 2 Tag compliant IC with 144/504/888 bytes user memory + * Revision 3.2 + * June 2015 + */ + +#include "config.h" + +#if defined(HAVE_SYS_TYPES_H) +# include +#endif + +#include +#include +#include + +#ifdef WITH_DEBUG +# include +#endif + +#include +#include "freefare_internal.h" + +#define NTAG_ASSERT_VALID_PAGE(tag, page, mode_write) \ + do { \ + if (mode_write) { \ + if (page<=0x02) \ + {return errno = EINVAL, -1;} \ + else if(NTAG_21x(tag)->subtype == NTAG_213&&page>0x2C) \ + {return errno = EINVAL, -1;} \ + else if(NTAG_21x(tag)->subtype == NTAG_215&&page>0x86) \ + {return errno = EINVAL, -1;} \ + else if(NTAG_21x(tag)->subtype == NTAG_216&&page>0xE6) \ + {return errno = EINVAL, -1;} \ + } else { \ + if(NTAG_21x(tag)->subtype == NTAG_213&&page>0x2C) \ + {return errno = EINVAL, -1;} \ + else if(NTAG_21x(tag)->subtype == NTAG_215&&page>0x86) \ + {return errno = EINVAL, -1;} \ + else if(NTAG_21x(tag)->subtype == NTAG_216&&page>0xE6) \ + {return errno = EINVAL, -1;} \ + } \ + } while (0) + +#define NTAG_TRANSCEIVE(tag, msg, res) \ + do { \ + errno = 0; \ + DEBUG_XFER (msg, __##msg##_n, "===> "); \ + int _res; \ + if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \ + return errno = EIO, -1; \ + } \ + __##res##_n = _res; \ + DEBUG_XFER (res, __##res##_n, "<=== "); \ + } while (0) + +#define NTAG_TRANSCEIVE_RAW(tag, msg, res) \ + do { \ + errno = 0; \ + if (nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, false) < 0) { \ + errno = EIO; \ + return -1; \ + } \ + DEBUG_XFER (msg, __##msg##_n, "===> "); \ + int _res; \ + if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \ + nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, true); \ + return errno = EIO, -1; \ + } \ + __##res##_n = _res; \ + DEBUG_XFER (res, __##res##_n, "<=== "); \ + if (nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, true) < 0) { \ + errno = EIO; \ + return -1; \ + } \ + } while (0) + + +bool +ntag21x_taste(nfc_device *device, nfc_target target) +{ + return target.nm.nmt == NMT_ISO14443A && target.nti.nai.btSak == 0x00 && ntag21x_is_auth_supported (device, target.nti.nai); +} + + +/* + * Memory management functions. + */ + +/* + * Allocates and initialize a NTAG tag. + */ +static FreefareTag +_ntag21x_tag_new(nfc_device *device, nfc_target target) +{ + FreefareTag tag; + + if ((tag = malloc (sizeof (struct ntag21x_tag)))) { + tag->type = NTAG_21x ; + tag->free_tag = ntag21x_tag_free; + tag->device = device; + tag->info = target; + tag->active = 0; + NTAG_21x(tag)->subtype = NTAG_213; // Set tag subtype + NTAG_21x(tag)->vendor_id = 0x04; + NTAG_21x(tag)->product_type = 0x04; + NTAG_21x(tag)->product_subtype = 0x02; + NTAG_21x(tag)->major_product_version = 0x01; + NTAG_21x(tag)->minor_product_version = 0x00; + NTAG_21x(tag)->storage_size = 0x0f; + NTAG_21x(tag)->protocol_type = 0x03; + } + + return tag; +} + +static FreefareTag +_ntag21x_tag_reuse(FreefareTag old_tag) +{ + FreefareTag tag; + + if ((tag = malloc (sizeof (struct ntag21x_tag)))) { + tag->type = NTAG_21x ; + tag->free_tag = ntag21x_tag_free; + tag->device = old_tag->device; + tag->info = old_tag->info; + tag->active = 0; + NTAG_21x(tag)->subtype = NTAG_213; // Set tag subtype + NTAG_21x(tag)->vendor_id = 0x04; + NTAG_21x(tag)->product_type = 0x04; + NTAG_21x(tag)->product_subtype = 0x02; + NTAG_21x(tag)->major_product_version = 0x01; + NTAG_21x(tag)->minor_product_version = 0x00; + NTAG_21x(tag)->storage_size = 0x0f; + NTAG_21x(tag)->protocol_type = 0x03; + } + + return tag; +} + +FreefareTag +ntag21x_tag_new(nfc_device *device, nfc_target target) +{ + return _ntag21x_tag_new (device, target); +} + +FreefareTag +ntag21x_tag_reuse(FreefareTag tag) +{ + return _ntag21x_tag_reuse (tag); +} + +/* + * Create new key for NTAG + */ +NTAG21xKey +ntag21x_key_new(const uint8_t data[4],const uint8_t pack[2]) +{ + NTAG21xKey key; + if ((key = malloc (sizeof (struct ntag21x_key)))) { + memcpy(key->data,data,4); + memcpy(key->pack,pack,2); + } + return key; +} + +/* + * Free NTAG key + */ +void +ntag21x_key_free(NTAG21xKey key) +{ + free(key); +} + +/* + * Free the provided tag. + */ +void +ntag21x_tag_free(FreefareTag tag) +{ + free (tag); +} + + + +/* + * MIFARE card communication preparation functions + * + * The following functions send NFC commands to the initiator to prepare + * communication with a MIFARE card, and perform required cleanups after using + * the target. + */ + + +/* + * Establish connection to the provided tag. + */ +int +ntag21x_connect(FreefareTag tag) +{ + ASSERT_INACTIVE (tag); + + nfc_target pnti; + nfc_modulation modulation = { + .nmt = NMT_ISO14443A, + .nbr = NBR_106 + }; + if (nfc_initiator_select_passive_target (tag->device, modulation, tag->info.nti.nai.abtUid, tag->info.nti.nai.szUidLen, &pnti) >= 0) { + tag->active = 1; + + } else { + errno = EIO; + return -1; + } + return 0; +} + +/* + * Terminate connection with the provided tag. + */ +int +ntag21x_disconnect(FreefareTag tag) +{ + ASSERT_ACTIVE (tag); + + if (nfc_initiator_deselect_target (tag->device) >= 0) { + tag->active = 0; + } else { + errno = EIO; + return -1; + } + return 0; +} + +/* + * Gather information about tag + */ +int +ntag21x_get_info(FreefareTag tag) +{ + ASSERT_ACTIVE (tag); + + // Init buffers + BUFFER_INIT (cmd, 1); + BUFFER_INIT (res,8); + + // Append get version command to buffer + BUFFER_APPEND (cmd, 0x60); + + NTAG_TRANSCEIVE_RAW (tag, cmd, res); // Send & receive to & from tag + + NTAG_21x(tag)->vendor_id = res[1]; + NTAG_21x(tag)->product_type = res[2]; + NTAG_21x(tag)->product_subtype = res[3]; + NTAG_21x(tag)->major_product_version = res[4]; + NTAG_21x(tag)->minor_product_version = res[5]; + NTAG_21x(tag)->storage_size = res[6]; + NTAG_21x(tag)->protocol_type = res[7]; + + // Set ntag subtype based on storage size + switch(NTAG_21x(tag)->storage_size) { + case 0x0f: + NTAG_21x(tag)->subtype = NTAG_213; + break; + case 0x11: + NTAG_21x(tag)->subtype = NTAG_215; + break; + case 0x13: + NTAG_21x(tag)->subtype = NTAG_216; + break; + default: + NTAG_21x(tag)->subtype = NTAG_213; + } + return 0; +} + +/* + * Get subtype of tag + */ +enum ntag_tag_subtype +ntag21x_get_subtype(FreefareTag tag) +{ + return NTAG_21x(tag)->subtype; +} + +/* + * Get last page + */ +uint8_t +ntag21x_get_last_page(FreefareTag tag) +{ + switch (NTAG_21x(tag)->subtype) { + case NTAG_213: + return 0x2C; + case NTAG_215: + return 0x86; + case NTAG_216: + return 0xE6; + default: + return 0x00; + } +} + +/* + * Read signature + */ +int +ntag21x_read_signature(FreefareTag tag,uint8_t *data) +{ + ASSERT_ACTIVE (tag); + + // Init buffers + BUFFER_INIT (cmd, 2); + BUFFER_INIT (res,32); + + // Append get version command to buffer + BUFFER_APPEND (cmd, 0x3C); + BUFFER_APPEND (cmd, 0x00); + + NTAG_TRANSCEIVE_RAW (tag, cmd, res); // Send & receive to & from tag + + memcpy(data,res,32); // Copy response to data output + return 0; +} + +/* + * Card manipulation functions + * + * The following functions perform direct communication with the connected + * NTAG21x tag. + */ + +/* + * Auth properties manipulation + */ +int +ntag21x_set_pwd(FreefareTag tag, uint8_t data[4]) // Set password +{ + uint8_t page = ntag21x_get_last_page(tag) - 1; // PWD page is located 1 before last page + int res = ntag21x_write(tag,page,data); + return res; +} + +int +ntag21x_set_pack(FreefareTag tag, uint8_t data[2]) // Set pack +{ + BUFFER_INIT(buff,4); + BUFFER_APPEND_BYTES(buff,data,2); + BUFFER_APPEND(buff,0x00); + BUFFER_APPEND(buff,0x00); + uint8_t page = ntag21x_get_last_page(tag); // PACK page is located on last page + int res = ntag21x_write(tag,page,buff); + return res; +} + +int +ntag21x_set_key(FreefareTag tag,const NTAG21xKey key) // Set key +{ + int res; + // Set password + res = ntag21x_set_pwd(tag,key->data); + if(res < 0) + return res; + + // Set pack + res = ntag21x_set_pack(tag,key->pack); + return res; +} + +int +ntag21x_set_auth(FreefareTag tag,uint8_t byte) // Set AUTH0 byte (from which page starts password protection) +{ + BUFFER_INIT(cdata,4); + int page = ntag21x_get_last_page(tag) - 3; // AUTH0 byte is on 4th page from back + int res; + res = ntag21x_read4(tag,page,cdata); // Read current configuration from tag + if(res < 0) + return res; + cdata[3] = byte; // Set AUTH0 byte in buffer + res = ntag21x_write(tag,page,cdata); // Write new configuration to tag + return res; +} + +int +ntag21x_get_auth(FreefareTag tag,uint8_t *byte) // Get AUTH0 byte +{ + BUFFER_INIT(cdata,4); + int page = ntag21x_get_last_page(tag) - 3; // AUTH0 byte is on 4th page from back + int res; + res = ntag21x_read4(tag,page,cdata); // Read current configuration from tag + if(res < 0) + return res; + *byte = cdata[3]; // Get AUTH0 byte in buffer + return res; +} + +int +ntag21x_access_enable(FreefareTag tag,uint8_t byte) // Enable access feature in ACCESS byte +{ + BUFFER_INIT(cdata,4); + int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back + int res; + res = ntag21x_read4(tag,page,cdata); // Read current configuration from tag + if(res < 0) + return res; + cdata[0] |= byte; // Set bit to 1 in ACCESS byte + res = ntag21x_write(tag,page,cdata); // Write new configuration to tag + return res; +} + +int +ntag21x_access_disable(FreefareTag tag,uint8_t byte) // Disable access feature in ACCESS byte +{ + BUFFER_INIT(cdata,4); + int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back + int res; + res = ntag21x_read4(tag,page,cdata); // Read current configuration from tag + if(res < 0) + return res; + cdata[0] &= ~byte; // Set bit to 0 in ACCESS byte + res = ntag21x_write(tag,page,cdata); // Write new configuration to tag + return res; +} + +int +ntag21x_get_access(FreefareTag tag,uint8_t *byte) // Get ACCESS byte +{ + BUFFER_INIT(cdata,4); + uint8_t page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back + int res; + res = ntag21x_read4(tag,page,cdata); // Read current configuration from tag + if(res < 0) + return res; + memcpy(byte,cdata,1); // Return 1 byte of page + return res; +} + +int +ntag21x_check_access(FreefareTag tag,uint8_t byte,bool *result) // Check if access feature is enabled +{ + BUFFER_INIT(buff,1); + int res; + res = ntag21x_get_access(tag,buff); + if(res<0) + return res; // Return error if can't get access byte + + *result = (buff[0]&byte)>0; // Set result, check if bit is 1 in access byte + + return res; +} + +int +ntag21x_get_authentication_limit(FreefareTag tag,uint8_t *byte) // Get authentication limit +{ + BUFFER_INIT(cdata,4); + uint8_t page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back + int res; + res = ntag21x_read4(tag,page,cdata); // Read current configuration from tag + if(res < 0) + return res; + cdata[0]&=0x07; // Extract last 3 bits from access byte + memcpy(byte,cdata,1); // Return 1 byte of page + return res; +} + +int +ntag21x_set_authentication_limit(FreefareTag tag,uint8_t byte) // Set authentication limit (0x00 = disabled, [0x01,0x07] = valid range, > 0x07 invalid range) +{ + if(byte > 7) // Check for invalid range of auth limit + return -1; + + BUFFER_INIT(cdata,4); + int page = ntag21x_get_last_page(tag) - 2; // ACCESS byte is on 3th page from back + int res; + res = ntag21x_read4(tag,page,cdata); // Read current configuration from tag + if(res < 0) + return res; + cdata[0] &= 0xf8; // Reset auth limit bits + cdata[0] |= byte; // Set aut limit + res = ntag21x_write(tag,page,cdata); // Write new configuration to tag + return res; +} + +/* + * Read 16 bytes from NTAG. + */ +int +ntag21x_read(FreefareTag tag, uint8_t page,uint8_t *data) +{ + ASSERT_ACTIVE (tag); + NTAG_ASSERT_VALID_PAGE (tag, page, false); + + // Init buffers + BUFFER_INIT (cmd, 2); + BUFFER_INIT (res,16); + + // Append read 16B command to buffer + BUFFER_APPEND (cmd, 0x30); + BUFFER_APPEND (cmd, page); + + NTAG_TRANSCEIVE (tag, cmd, res); // Send & receive to & from tag + memcpy (data, res, 16); // Copy first 4 bytes (selected page) to data output + return 0; +} + +/* + * Read 4 bytes from NTAG + */ +int +ntag21x_read4(FreefareTag tag,uint8_t page,uint8_t *data) +{ + BUFFER_INIT (res,16); + int re = ntag21x_read(tag,page,res); + memcpy(data,res,4); + return re; +} + +/* + * Read pages from [start,end] from NTAG + */ +int +ntag21x_fast_read(FreefareTag tag, uint8_t start_page,uint8_t end_page, uint8_t *data) +{ + ASSERT_ACTIVE (tag); + NTAG_ASSERT_VALID_PAGE (tag, start_page, false); + NTAG_ASSERT_VALID_PAGE (tag, end_page, false); + + // Init buffers + BUFFER_INIT (cmd, 3); + BUFFER_INIT (res,4*(end_page - start_page + 1)); + + // Append read 16B command to buffer + BUFFER_APPEND (cmd, 0x3A); + BUFFER_APPEND (cmd, start_page); + BUFFER_APPEND (cmd, end_page); + + NTAG_TRANSCEIVE_RAW (tag, cmd, res); // Send & receive to & from tag + + memcpy (data, res, 4*(end_page - start_page + 1)); // Copy first 4 bytes (selected page) to data output + return 0; +} + +int +ntag21x_fast_read4(FreefareTag tag,uint8_t page,uint8_t *data) +{ + BUFFER_INIT (res,4); + int re = ntag21x_fast_read(tag,page,page,res); + memcpy(data,res,4); + return re; +} + +/* + * Read one way counter 3 bytes + */ +int +ntag21x_read_cnt(FreefareTag tag, uint8_t *data) +{ + ASSERT_ACTIVE (tag); + + // Init buffers + BUFFER_INIT (cmd, 2); + BUFFER_INIT (res,3); + + // Append read cnt command to buffer + BUFFER_APPEND (cmd, 0x39); + BUFFER_APPEND (cmd, 0x02); + + NTAG_TRANSCEIVE_RAW (tag, cmd, res); // Send & receive to & from tag + + memcpy (data, res, 3); // Copy first 3 bytes (selected page) to data output + return 0; +} + +/* + * Read data to the provided MIFARE tag. + */ +int +ntag21x_write(FreefareTag tag, uint8_t page, uint8_t data[4]) +{ + ASSERT_ACTIVE (tag); + NTAG_ASSERT_VALID_PAGE (tag, page, true); + + // Init buffera + BUFFER_INIT (cmd, 6); + BUFFER_INIT (res, 1); + + // Append write 4B command to buffer + BUFFER_APPEND (cmd, 0xA2); + BUFFER_APPEND (cmd, page); + BUFFER_APPEND_BYTES (cmd, data, 4); // Copy data to last 4 bytes of buffer + + NTAG_TRANSCEIVE (tag, cmd, res); + + return 0; +} + +int +ntag21x_compatibility_write(FreefareTag tag, uint8_t page, uint8_t data[4]) +{ + ASSERT_ACTIVE (tag); + NTAG_ASSERT_VALID_PAGE (tag, page, true); + + // Init buffera + BUFFER_INIT (cmd, 18); + BUFFER_INIT (res, 1); + + // Append write 4B command to buffer + BUFFER_APPEND (cmd, 0xA0); + BUFFER_APPEND (cmd, page); + BUFFER_APPEND_BYTES (cmd, data, 4); // Copy data to last 4 bytes of buffer + for (int i=0;i<12;i++) { + BUFFER_APPEND(cmd,0x00); + } + + NTAG_TRANSCEIVE (tag, cmd, res); + return 0; +} + +/* + * Authenticate to the provided NTAG tag. + */ +int +ntag21x_authenticate(FreefareTag tag, const NTAG21xKey key) +{ + ASSERT_ACTIVE (tag); + BUFFER_INIT (cmd1, 5); + BUFFER_INIT (res, 2); + BUFFER_APPEND (cmd1, 0x1B); + BUFFER_APPEND_BYTES (cmd1, key->data,4); // Append key to command + NTAG_TRANSCEIVE_RAW(tag, cmd1, res); + + //Check if authenticated (PACK must be as expected) + bool flag_auth = true; + for(int i=0;i<2;i++) + if (res[i] != key->pack[i]) { + flag_auth = false; + break; + } + + if(!flag_auth) + return -1; + // XXX Should we store the state "authenticated" in the tag struct?? + return 0; +} + +bool +is_ntag21x(FreefareTag tag) +{ + return tag->type == NTAG_21x; +} + +/* + * Callback for freefare_tag_new to test presence of a ntag21x on the reader. + */ +bool +ntag21x_is_auth_supported(nfc_device *device, nfc_iso14443a_info nai) +{ + int ret; + uint8_t cmd_step1[1]; + uint8_t res_step1[8]; + cmd_step1[0] = 0x60; + cmd_step1[1] = 0x00; + + nfc_target pnti; + nfc_modulation modulation = { + .nmt = NMT_ISO14443A, + .nbr = NBR_106 + }; + nfc_initiator_select_passive_target(device, modulation, nai.abtUid, nai.szUidLen, &pnti); + nfc_device_set_property_bool(device, NP_EASY_FRAMING, false); + ret = nfc_initiator_transceive_bytes(device, cmd_step1, sizeof (cmd_step1), res_step1, sizeof(res_step1), 0); + nfc_device_set_property_bool(device, NP_EASY_FRAMING, true); + nfc_initiator_deselect_target(device); + return ret >= 0; +}