Added support for NTAG 21x tags (#53)
This commit is contained in:
parent
2be45f60e2
commit
b2eca838c4
14 changed files with 1420 additions and 1 deletions
|
@ -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 Plus X 4k | Not supported |
|
||||||
| MIFARE Ultralight | Supported |
|
| MIFARE Ultralight | Supported |
|
||||||
| MIFARE Ultralight C | Supported |
|
| MIFARE Ultralight C | Supported |
|
||||||
|
| NTAG21x | Supported |
|
||||||
|
|
||||||
## Specifications
|
## Specifications
|
||||||
| Specification | Status |
|
| Specification | Status |
|
||||||
|
|
|
@ -12,6 +12,10 @@ set(EXAMPLES-SOURCES
|
||||||
mifare-desfire-ev1-configure-default-key
|
mifare-desfire-ev1-configure-default-key
|
||||||
mifare-desfire-ev1-configure-random-uid
|
mifare-desfire-ev1-configure-random-uid
|
||||||
mifare-ultralight-info
|
mifare-ultralight-info
|
||||||
|
ntag-detect
|
||||||
|
ntag-removeauth
|
||||||
|
ntag-setauth
|
||||||
|
ntag-write
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../libfreefare)
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../libfreefare)
|
||||||
|
|
|
@ -15,7 +15,11 @@ bin_PROGRAMS = felica-lite-dump \
|
||||||
mifare-desfire-info \
|
mifare-desfire-info \
|
||||||
mifare-desfire-read-ndef \
|
mifare-desfire-read-ndef \
|
||||||
mifare-desfire-write-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_SOURCES = felica-lite-dump.c
|
||||||
felica_lite_dump_LDADD = $(top_builddir)/libfreefare/libfreefare.la
|
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_SOURCES = mifare-ultralight-info.c
|
||||||
mifare_ultralight_info_LDADD = $(top_builddir)/libfreefare/libfreefare.la
|
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
|
CLEANFILES= *.gcno
|
||||||
|
|
68
examples/ntag-detect.c
Normal file
68
examples/ntag-detect.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <nfc/nfc.h>
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
146
examples/ntag-removeauth.c
Normal file
146
examples/ntag-removeauth.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <nfc/nfc.h>
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
146
examples/ntag-setauth.c
Normal file
146
examples/ntag-setauth.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <nfc/nfc.h>
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
119
examples/ntag-write.c
Normal file
119
examples/ntag-write.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <nfc/nfc.h>
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ set(LIBRARY_SOURCES
|
||||||
mifare_desfire_error
|
mifare_desfire_error
|
||||||
mifare_desfire_key
|
mifare_desfire_key
|
||||||
mifare_ultralight
|
mifare_ultralight
|
||||||
|
ntag21x
|
||||||
tlv
|
tlv
|
||||||
../contrib/libutil/hexdump
|
../contrib/libutil/hexdump
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,6 +14,7 @@ libfreefare_la_SOURCES = felica.c \
|
||||||
mifare_desfire_key.c \
|
mifare_desfire_key.c \
|
||||||
mad.c \
|
mad.c \
|
||||||
mifare_application.c \
|
mifare_application.c \
|
||||||
|
ntag21x.c \
|
||||||
tlv.c
|
tlv.c
|
||||||
libfreefare_la_LIBADD =
|
libfreefare_la_LIBADD =
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ man_MANS = freefare.3 \
|
||||||
mifare_desfire_aid.3 \
|
mifare_desfire_aid.3 \
|
||||||
mifare_desfire_key.3 \
|
mifare_desfire_key.3 \
|
||||||
mifare_ultralight.3 \
|
mifare_ultralight.3 \
|
||||||
|
ntag21x.3 \
|
||||||
tlv.3
|
tlv.3
|
||||||
|
|
||||||
linkedman = \
|
linkedman = \
|
||||||
|
|
|
@ -48,6 +48,8 @@ freefare_tag_new (nfc_device *device, nfc_target target)
|
||||||
tag = mifare_classic4k_tag_new (device, target);
|
tag = mifare_classic4k_tag_new (device, target);
|
||||||
} else if (mifare_desfire_taste (device, target)) {
|
} else if (mifare_desfire_taste (device, target)) {
|
||||||
tag = mifare_desfire_tag_new (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)) {
|
} else if (mifare_ultralightc_taste (device, target)) {
|
||||||
tag = mifare_ultralightc_tag_new (device, target);
|
tag = mifare_ultralightc_tag_new (device, target);
|
||||||
} else if (mifare_ultralight_taste (device, target)) {
|
} else if (mifare_ultralight_taste (device, target)) {
|
||||||
|
@ -171,6 +173,8 @@ freefare_get_tag_friendly_name (FreefareTag tag)
|
||||||
return "Mifare UltraLightC";
|
return "Mifare UltraLightC";
|
||||||
case MIFARE_ULTRALIGHT:
|
case MIFARE_ULTRALIGHT:
|
||||||
return "Mifare UltraLight";
|
return "Mifare UltraLight";
|
||||||
|
case NTAG_21x:
|
||||||
|
return "NTAG21x";
|
||||||
default:
|
default:
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ enum freefare_tag_type {
|
||||||
// MIFARE_PLUS_X4K,
|
// MIFARE_PLUS_X4K,
|
||||||
MIFARE_ULTRALIGHT,
|
MIFARE_ULTRALIGHT,
|
||||||
MIFARE_ULTRALIGHT_C,
|
MIFARE_ULTRALIGHT_C,
|
||||||
|
NTAG_21x,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct freefare_tag;
|
struct freefare_tag;
|
||||||
|
@ -51,6 +52,9 @@ typedef struct freefare_tag *MifareTag __attribute__ ((deprecated));
|
||||||
struct mifare_desfire_key;
|
struct mifare_desfire_key;
|
||||||
typedef struct mifare_desfire_key *MifareDESFireKey;
|
typedef struct mifare_desfire_key *MifareDESFireKey;
|
||||||
|
|
||||||
|
struct ntag21x_key;
|
||||||
|
typedef struct ntag21x_key *NTAG21xKey;
|
||||||
|
|
||||||
typedef uint8_t MifareUltralightPageNumber;
|
typedef uint8_t MifareUltralightPageNumber;
|
||||||
typedef unsigned char MifareUltralightPage[4];
|
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_mini_taste (nfc_device *device, nfc_target target);
|
||||||
bool mifare_classic1k_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);
|
bool mifare_classic4k_taste (nfc_device *device, nfc_target target);
|
||||||
|
|
|
@ -243,6 +243,28 @@ struct mifare_ultralight_tag {
|
||||||
uint8_t cached_pages[MIFARE_ULTRALIGHT_MAX_PAGE_COUNT];
|
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
|
* FreefareTag assertion macros
|
||||||
*
|
*
|
||||||
|
@ -262,6 +284,7 @@ struct mifare_ultralight_tag {
|
||||||
#define MIFARE_CLASSIC(tag) ((struct mifare_classic_tag *) tag)
|
#define MIFARE_CLASSIC(tag) ((struct mifare_classic_tag *) tag)
|
||||||
#define MIFARE_DESFIRE(tag) ((struct mifare_desfire_tag *) tag)
|
#define MIFARE_DESFIRE(tag) ((struct mifare_desfire_tag *) tag)
|
||||||
#define MIFARE_ULTRALIGHT(tag) ((struct mifare_ultralight_tag *) tag)
|
#define MIFARE_ULTRALIGHT(tag) ((struct mifare_ultralight_tag *) tag)
|
||||||
|
#define NTAG_21x(tag) ((struct ntag21x_tag *) tag)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Access bits manipulation macros
|
* Access bits manipulation macros
|
||||||
|
|
132
libfreefare/ntag21x.3
Normal file
132
libfreefare/ntag21x.3
Normal file
|
@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
.\"
|
||||||
|
.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
|
703
libfreefare/ntag21x.c
Normal file
703
libfreefare/ntag21x.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef WITH_DEBUG
|
||||||
|
# include <libutil.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in a new issue