move some examples to utils/ since they are not examples anymore :) (Fixes Issue 164)
This commit is contained in:
parent
311d12feef
commit
8c7b61eaba
34 changed files with 126 additions and 83 deletions
|
|
@ -1,23 +1,15 @@
|
|||
SET(EXAMPLES-SOURCES nfc-anticol nfc-dep-initiator nfc-dep-target nfc-emulate-forum-tag4 nfc-emulate-tag nfc-emulate-uid nfc-list nfc-poll nfc-relay nfc-relay-picc nfc-mfclassic nfc-mfultralight)
|
||||
#TODO pn53x-diagnose pn53x-sam pn53x-tamashell
|
||||
SET(EXAMPLES-SOURCES nfc-anticol nfc-dep-initiator nfc-dep-target nfc-emulate-tag nfc-emulate-uid nfc-poll nfc-relay pn53x-diagnose pn53x-sam pn53x-tamashell)
|
||||
|
||||
# XXX: Examples should not use private API!
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libnfc)
|
||||
|
||||
INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS} ${PCSC_INCLUDE_DIRS})
|
||||
LINK_DIRECTORIES(${LIBUSB_LIBRARY_DIRS} ${PCSC_LIBRARY_DIRS})
|
||||
|
||||
ADD_LIBRARY(nfc-utils nfc-utils)
|
||||
|
||||
# Examples
|
||||
FOREACH(source ${EXAMPLES-SOURCES})
|
||||
IF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic"))
|
||||
ADD_EXECUTABLE(${source} ${source}.c mifare)
|
||||
ELSE()
|
||||
ADD_EXECUTABLE(${source} ${source}.c)
|
||||
ENDIF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic"))
|
||||
ADD_EXECUTABLE(${source} ${source}.c)
|
||||
TARGET_LINK_LIBRARIES(${source} nfc)
|
||||
TARGET_LINK_LIBRARIES(${source} nfc-utils)
|
||||
TARGET_LINK_LIBRARIES(${source} nfcutils)
|
||||
INSTALL(TARGETS ${source} RUNTIME DESTINATION bin COMPONENT examples)
|
||||
ENDFOREACH(source)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,17 +4,10 @@ bin_PROGRAMS = \
|
|||
nfc-anticol \
|
||||
nfc-dep-initiator \
|
||||
nfc-dep-target \
|
||||
nfc-emulate-forum-tag2 \
|
||||
nfc-emulate-forum-tag4 \
|
||||
nfc-emulate-tag \
|
||||
nfc-emulate-uid \
|
||||
nfc-list \
|
||||
nfc-mfclassic \
|
||||
nfc-mfsetuid \
|
||||
nfc-mfultralight \
|
||||
nfc-poll \
|
||||
nfc-relay \
|
||||
nfc-relay-picc \
|
||||
pn53x-diagnose \
|
||||
pn53x-sam
|
||||
|
||||
|
|
@ -28,93 +21,55 @@ INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
|
|||
|
||||
AM_CFLAGS = -I$(top_srcdir)/libnfc
|
||||
|
||||
noinst_HEADERS = mifare.h nfc-utils.h
|
||||
noinst_LTLIBRARIES = libnfcutils.la
|
||||
|
||||
libnfcutils_la_SOURCES = nfc-utils.c
|
||||
|
||||
nfc_poll_SOURCES = nfc-poll.c
|
||||
nfc_poll_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
nfc_anticol_SOURCES = nfc-anticol.c
|
||||
nfc_anticol_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
|
||||
nfc_list_SOURCES = nfc-list.c
|
||||
nfc_list_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
|
||||
nfc_mfultralight_SOURCES = nfc-mfultralight.c mifare.c mifare.h
|
||||
nfc_mfultralight_LDADD = $(top_builddir)/libnfc/libnfc.la
|
||||
|
||||
nfc_mfclassic_SOURCES = nfc-mfclassic.c mifare.c mifare.h
|
||||
nfc_mfclassic_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
|
||||
nfc_mfsetuid_SOURCES = nfc-mfsetuid.c
|
||||
nfc_mfsetuid_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
nfc_relay_SOURCES = nfc-relay.c
|
||||
nfc_relay_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
|
||||
nfc_relay_picc_SOURCES = nfc-relay-picc.c
|
||||
nfc_relay_picc_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
|
||||
nfc_emulate_forum_tag2_SOURCES = nfc-emulate-forum-tag2.c
|
||||
nfc_emulate_forum_tag2_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
|
||||
nfc_emulate_forum_tag4_SOURCES = nfc-emulate-forum-tag4.c
|
||||
nfc_emulate_forum_tag4_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
nfc_emulate_tag_SOURCES = nfc-emulate-tag.c
|
||||
nfc_emulate_tag_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
nfc_emulate_uid_SOURCES = nfc-emulate-uid.c
|
||||
nfc_emulate_uid_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
nfc_dep_target_SOURCES = nfc-dep-target.c
|
||||
nfc_dep_target_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
nfc_dep_initiator_SOURCES = nfc-dep-initiator.c
|
||||
nfc_dep_initiator_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
pn53x_diagnose_SOURCES = pn53x-diagnose.c
|
||||
pn53x_diagnose_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
pn53x_sam_SOURCES = pn53x-sam.c
|
||||
pn53x_sam_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
|
||||
pn53x_tamashell_SOURCES = pn53x-tamashell.c
|
||||
pn53x_tamashell_LDADD = $(top_builddir)/libnfc/libnfc.la \
|
||||
libnfcutils.la
|
||||
$(top_builddir)/utils/libnfcutils.la
|
||||
pn53x_tamashell_LDFLAGS = @READLINE_LIBS@
|
||||
|
||||
dist_man_MANS = \
|
||||
nfc-anticol.1 \
|
||||
nfc-dep-initiator.1 \
|
||||
nfc-dep-target.1 \
|
||||
nfc-emulate-forum-tag4.1 \
|
||||
nfc-emulate-tag.1 \
|
||||
nfc-emulate-uid.1 \
|
||||
nfc-list.1 \
|
||||
nfc-mfclassic.1 \
|
||||
nfc-mfsetuid.1 \
|
||||
nfc-mfultralight.1 \
|
||||
nfc-poll.1 \
|
||||
nfc-relay.1 \
|
||||
nfc-relay-picc.1 \
|
||||
pn53x-diagnose.1 \
|
||||
pn53x-sam.1 \
|
||||
pn53x-tamashell.1
|
||||
|
|
|
|||
|
|
@ -1,130 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mifare.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
/**
|
||||
* @brief Execute a MIFARE Classic Command
|
||||
* @return Returns true if action was successfully performed; otherwise returns false.
|
||||
* @param pmp Some commands need additional information. This information should be supplied in the mifare_param union.
|
||||
*
|
||||
* The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number.
|
||||
* @note There are three different types of information (Authenticate, Data and Value).
|
||||
*
|
||||
* First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID.
|
||||
* They are both used to initialize the internal cipher-state of the PN53X chip (http://libnfc.org/hardware/pn53x-chip).
|
||||
* After a successful authentication it will be possible to execute other commands (e.g. Read/Write).
|
||||
* The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process.
|
||||
*/
|
||||
bool
|
||||
nfc_initiator_mifare_cmd (nfc_device_t * pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param * pmp)
|
||||
{
|
||||
byte_t abtRx[265];
|
||||
size_t szRx = sizeof(abtRx);
|
||||
size_t szParamLen;
|
||||
byte_t abtCmd[265];
|
||||
bool bEasyFraming;
|
||||
|
||||
abtCmd[0] = mc; // The MIFARE Classic command
|
||||
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
||||
|
||||
switch (mc) {
|
||||
// Read and store command have no parameter
|
||||
case MC_READ:
|
||||
case MC_STORE:
|
||||
szParamLen = 0;
|
||||
break;
|
||||
|
||||
// Authenticate command
|
||||
case MC_AUTH_A:
|
||||
case MC_AUTH_B:
|
||||
szParamLen = sizeof (mifare_param_auth);
|
||||
break;
|
||||
|
||||
// Data command
|
||||
case MC_WRITE:
|
||||
szParamLen = sizeof (mifare_param_data);
|
||||
break;
|
||||
|
||||
// Value command
|
||||
case MC_DECREMENT:
|
||||
case MC_INCREMENT:
|
||||
case MC_TRANSFER:
|
||||
szParamLen = sizeof (mifare_param_value);
|
||||
break;
|
||||
|
||||
// Please fix your code, you never should reach this statement
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
// When available, copy the parameter bytes
|
||||
if (szParamLen)
|
||||
memcpy (abtCmd + 2, (byte_t *) pmp, szParamLen);
|
||||
|
||||
bEasyFraming = pnd->bEasyFraming;
|
||||
if (!nfc_configure (pnd, NDO_EASY_FRAMING, true)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
return false;
|
||||
}
|
||||
// Fire the mifare command
|
||||
if (!nfc_initiator_transceive_bytes (pnd, abtCmd, 2 + szParamLen, abtRx, &szRx, NULL)) {
|
||||
if (pnd->iLastError == EINVRXFRAM) {
|
||||
// "Invalid received frame" AKA EINVRXFRAM, usual means we are
|
||||
// authenticated on a sector but the requested MIFARE cmd (read, write)
|
||||
// is not permitted by current acces bytes;
|
||||
// So there is nothing to do here.
|
||||
} else {
|
||||
nfc_perror (pnd, "nfc_initiator_transceive_bytes");
|
||||
}
|
||||
nfc_configure (pnd, NDO_EASY_FRAMING, bEasyFraming);
|
||||
return false;
|
||||
}
|
||||
if (!nfc_configure (pnd, NDO_EASY_FRAMING, bEasyFraming)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
return false;
|
||||
}
|
||||
|
||||
// When we have executed a read command, copy the received bytes into the param
|
||||
if (mc == MC_READ) {
|
||||
if (szRx == 16) {
|
||||
memcpy (pmp->mpd.abtData, abtRx, 16);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Command succesfully executed
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mifaretag.h
|
||||
* @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_MIFARE_H_
|
||||
# define _LIBNFC_MIFARE_H_
|
||||
|
||||
# include <nfc/nfc-types.h>
|
||||
|
||||
// Compiler directive, set struct alignment to 1 byte_t for compatibility
|
||||
# pragma pack(1)
|
||||
|
||||
typedef enum {
|
||||
MC_AUTH_A = 0x60,
|
||||
MC_AUTH_B = 0x61,
|
||||
MC_READ = 0x30,
|
||||
MC_WRITE = 0xA0,
|
||||
MC_TRANSFER = 0xB0,
|
||||
MC_DECREMENT = 0xC0,
|
||||
MC_INCREMENT = 0xC1,
|
||||
MC_STORE = 0xC2
|
||||
} mifare_cmd;
|
||||
|
||||
// MIFARE command params
|
||||
typedef struct {
|
||||
byte_t abtKey[6];
|
||||
byte_t abtUid[4];
|
||||
} mifare_param_auth;
|
||||
|
||||
typedef struct {
|
||||
byte_t abtData[16];
|
||||
} mifare_param_data;
|
||||
|
||||
typedef struct {
|
||||
byte_t abtValue[4];
|
||||
} mifare_param_value;
|
||||
|
||||
typedef union {
|
||||
mifare_param_auth mpa;
|
||||
mifare_param_data mpd;
|
||||
mifare_param_value mpv;
|
||||
} mifare_param;
|
||||
|
||||
// Reset struct alignment to default
|
||||
# pragma pack()
|
||||
|
||||
bool nfc_initiator_mifare_cmd (nfc_device_t * pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param * pmp);
|
||||
|
||||
// Compiler directive, set struct alignment to 1 byte_t for compatibility
|
||||
# pragma pack(1)
|
||||
|
||||
// MIFARE Classic
|
||||
typedef struct {
|
||||
byte_t abtUID[4];
|
||||
byte_t btBCC;
|
||||
byte_t btUnknown;
|
||||
byte_t abtATQA[2];
|
||||
byte_t abtUnknown[8];
|
||||
} mifare_classic_block_manufacturer;
|
||||
|
||||
typedef struct {
|
||||
byte_t abtData[16];
|
||||
} mifare_classic_block_data;
|
||||
|
||||
typedef struct {
|
||||
byte_t abtKeyA[6];
|
||||
byte_t abtAccessBits[4];
|
||||
byte_t abtKeyB[6];
|
||||
} mifare_classic_block_trailer;
|
||||
|
||||
typedef union {
|
||||
mifare_classic_block_manufacturer mbm;
|
||||
mifare_classic_block_data mbd;
|
||||
mifare_classic_block_trailer mbt;
|
||||
} mifare_classic_block;
|
||||
|
||||
typedef struct {
|
||||
mifare_classic_block amb[256];
|
||||
} mifare_classic_tag;
|
||||
|
||||
// MIFARE Ultralight
|
||||
typedef struct {
|
||||
byte_t sn0[3];
|
||||
byte_t btBCC0;
|
||||
byte_t sn1[4];
|
||||
byte_t btBCC1;
|
||||
byte_t internal;
|
||||
byte_t lock[2];
|
||||
byte_t otp[4];
|
||||
} mifareul_block_manufacturer;
|
||||
|
||||
typedef struct {
|
||||
byte_t abtData[16];
|
||||
} mifareul_block_data;
|
||||
|
||||
typedef union {
|
||||
mifareul_block_manufacturer mbm;
|
||||
mifareul_block_data mbd;
|
||||
} mifareul_block;
|
||||
|
||||
typedef struct {
|
||||
mifareul_block amb[4];
|
||||
} mifareul_tag;
|
||||
|
||||
// Reset struct alignment to default
|
||||
# pragma pack()
|
||||
|
||||
#endif // _LIBNFC_MIFARE_H_
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
|
||||
#define SAK_FLAG_ATS_SUPPORTED 0x20
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
|
||||
|
|
|
|||
|
|
@ -1,208 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2011, Romuald Conty
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-emulate-forum-tag2.c
|
||||
* @brief Emulates a NFC Forum Tag Type 2 with a NDEF message
|
||||
* This example allow to emulate an NFC Forum Tag Type 2 that contains a read-only NDEF message.
|
||||
*
|
||||
* It have been developed using PN533 USB hardware as target and Google Nexus S phone as initiator.
|
||||
*
|
||||
* This is know to NOT work with Nokia 6212 Classic and could not work with
|
||||
* several NFC Forum compiliant devices due to these reasons:
|
||||
* - The emulated target only have a 4 bytes UID where 7 bytes UID (as a real
|
||||
* Mifare Ultralight tag) are usually attempted;
|
||||
* - The chip is emulating a ISO/IEC 14443-3 tag, without any hardware helper.
|
||||
* If the initiator have too short timeouts for software-based emulation
|
||||
* (which is usually the case), this example will failed, this is not a bug
|
||||
* and we can't do anything using this kind of hardware (PN531/PN533).
|
||||
*/
|
||||
|
||||
/*
|
||||
* This implementation was written based on information provided by the
|
||||
* following documents:
|
||||
*
|
||||
* NFC Forum Type 2 Tag Operation
|
||||
* Technical Specification
|
||||
* NFCForum-TS-Type-2-Tag_1.0 - 2007-07-09
|
||||
*
|
||||
* ISO/IEC 14443-3
|
||||
* First edition - 2001-02-01
|
||||
* Identification cards — Contactless integrated circuit(s) cards — Proximity cards
|
||||
* Part 3: Initialization and anticollision
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
#include <nfc/nfc-emulation.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
static nfc_device_t *pnd;
|
||||
|
||||
void
|
||||
stop_emulation (int sig)
|
||||
{
|
||||
(void)sig;
|
||||
if (pnd) {
|
||||
nfc_abort_command(pnd);
|
||||
} else {
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t __nfcforum_tag2_memory_area[] = {
|
||||
0x00, 0x00, 0x00, 0x00, // Block 0
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, // Block 2 (Static lock bytes: CC area and data area are read-only locked)
|
||||
0xE1, 0x10, 0x06, 0x0F, // Block 3 (CC - NFC-Forum Tag Type 2 version 1.0, Data area (from block 4 to the end) is 48 bytes, Read-only mode)
|
||||
|
||||
0x03, 33, 0xd1, 0x02, // Block 4 (NDEF)
|
||||
0x1c, 0x53, 0x70, 0x91,
|
||||
0x01, 0x09, 0x54, 0x02,
|
||||
0x65, 0x6e, 0x4c, 0x69,
|
||||
|
||||
0x62, 0x6e, 0x66, 0x63,
|
||||
0x51, 0x01, 0x0b, 0x55,
|
||||
0x03, 0x6c, 0x69, 0x62,
|
||||
0x6e, 0x66, 0x63, 0x2e,
|
||||
|
||||
0x6f, 0x72, 0x67, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
#define READ 0x30
|
||||
#define WRITE 0xA2
|
||||
#define SECTOR_SELECT 0xC2
|
||||
|
||||
#define HALT 0x50
|
||||
int
|
||||
nfcforum_tag2_io (struct nfc_emulator *emulator, const byte_t *data_in, const size_t data_in_len, byte_t *data_out, const size_t data_out_len)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
uint8_t *nfcforum_tag2_memory_area = (uint8_t *)(emulator->user_data);
|
||||
|
||||
printf (" In: ");
|
||||
print_hex (data_in, data_in_len);
|
||||
|
||||
switch (data_in[0]) {
|
||||
case READ:
|
||||
if (data_out_len >= 16) {
|
||||
memcpy(data_out, nfcforum_tag2_memory_area + (data_in[1] * 4), 16);
|
||||
res = 16;
|
||||
} else {
|
||||
res = -ENOSPC;
|
||||
}
|
||||
break;
|
||||
case HALT:
|
||||
printf ("HALT sent\n");
|
||||
res = -ECONNABORTED;
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown command: 0x%02x\n", data_in[0]);
|
||||
res = -ENOTSUP;
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
ERR ("%s (%d)", strerror (-res), -res);
|
||||
} else {
|
||||
printf (" Out: ");
|
||||
print_hex (data_out, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
nfc_target_t nt = {
|
||||
.nm = {
|
||||
.nmt = NMT_ISO14443A,
|
||||
.nbr = NBR_UNDEFINED, // Will be updated by nfc_target_init()
|
||||
},
|
||||
.nti = {
|
||||
.nai = {
|
||||
.abtAtqa = { 0x00, 0x04 },
|
||||
.abtUid = { 0x08, 0x00, 0xb0, 0x0b },
|
||||
.szUidLen = 4,
|
||||
.btSak = 0x00,
|
||||
.szAtsLen = 0,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
struct nfc_emulation_state_machine state_machine = {
|
||||
.io = nfcforum_tag2_io
|
||||
};
|
||||
|
||||
struct nfc_emulator emulator = {
|
||||
.target= &nt,
|
||||
.state_machine = &state_machine,
|
||||
.user_data = __nfcforum_tag2_memory_area,
|
||||
};
|
||||
|
||||
signal (SIGINT, stop_emulation);
|
||||
pnd = nfc_connect (NULL);
|
||||
|
||||
if (pnd == NULL) {
|
||||
ERR("Unable to connect to NFC device");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf ("Connected to NFC device: %s\n", pnd->acName);
|
||||
printf ("Emulating NDEF tag now, please touch it with a second NFC device\n");
|
||||
|
||||
if (nfc_emulate_target (pnd, &emulator) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
nfc_disconnect(pnd);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
error:
|
||||
if (pnd) {
|
||||
nfc_perror (pnd, argv[0]);
|
||||
nfc_disconnect (pnd);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
.Dd March 12, 2011
|
||||
.Dt NFC-EMULATE-FORUM-TAG4 1 URM
|
||||
.Sh NAME
|
||||
.Nm nfc-emulate-forum-tag4
|
||||
.Nd NFC Forum tag type 4 emulation command line demonstration tool
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op infile Op outfile
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a demonstration tool that emulates a NFC Forum tag type 4 with NDEF content.
|
||||
.Pp
|
||||
.Ar infile
|
||||
is the file which contains NDEF message you want to share with the NFC-Forum
|
||||
compiliant initiator device (e.g. Nokia 6212 Classic)
|
||||
.Pp
|
||||
If you want to save a shared content by the initiator device, we have to give
|
||||
.Ar outfile
|
||||
argument to point where the NDEF message will be saved.
|
||||
.Pp
|
||||
This example uses the hardware capability of PN532 to handle ISO/IEC 14443-4
|
||||
low-level frames like RATS/ATS, WTX, etc.
|
||||
.Pp
|
||||
All devices compiliant with NFC-Forum Tag Type 4 (Version 1.0) can be used with
|
||||
this example in read-write mode.
|
||||
.Pp
|
||||
If no argument is given, a default NDEF file is available.
|
||||
.Sh IMPLEMENTATION NOTES
|
||||
You can specify the same
|
||||
.Ar infile
|
||||
and
|
||||
.Ar outfile
|
||||
.Sh IMPORTANT
|
||||
Only PN532 equipped devices can use this example. (e.g. PN532 breakout board)
|
||||
.Pp
|
||||
ACR122 devices (like touchatag, etc.) can be used by this example, but if
|
||||
something goes wrong, you will have to unplug/replug your device.
|
||||
This is not a
|
||||
.Em libnfc's
|
||||
bug, this problem is due to ACR122's internal MCU in front of NFC chip (PN532).
|
||||
.Sh BUGS
|
||||
Please report any bugs on the
|
||||
.Em libnfc
|
||||
forum at
|
||||
.Em http://www.libnfc.org/community/ "."
|
||||
.Sh LICENCE
|
||||
.Em libnfc
|
||||
and
|
||||
.Em libnfc-examples
|
||||
are covered by the GNU Lesser General Public License (LGPL), version 3.
|
||||
.Sh AUTHORS
|
||||
.An Roel Verdult Aq roel@libnfc.org
|
||||
.An Romain Tartière Aq romain@libnfc.org
|
||||
.An Romuald Conty Aq romuald@libnfc.org
|
||||
.Pp
|
||||
This manual page was written by Romuald Conty.
|
||||
It is licensed under the terms of the GNU GPL (version 2 or later).
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2010, Roel Verdult, Romuald Conty
|
||||
* Copyright (C) 2011, Romain Tartière, Romuald Conty
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-emulate-forum-tag4.c
|
||||
* @brief Emulates a NFC Forum Tag Type 4 with a NDEF message
|
||||
*/
|
||||
|
||||
/*
|
||||
* This implementation was written based on information provided by the
|
||||
* following documents:
|
||||
*
|
||||
* NFC Forum Type 4 Tag Operation
|
||||
* Technical Specification
|
||||
* NFCForum-TS-Type-4-Tag_1.0 - 2007-03-13
|
||||
*/
|
||||
|
||||
// Notes & differences with nfc-emulate-tag:
|
||||
// - This example only works with PN532 because it relies on
|
||||
// its internal handling of ISO14443-4 specificities.
|
||||
// - Thanks to this internal handling & injection of WTX frames,
|
||||
// this example works on readers very strict on timing
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
#include <nfc/nfc-emulation.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
static nfc_device_t *pnd;
|
||||
static bool quiet_output = false;
|
||||
|
||||
#define SYMBOL_PARAM_fISO14443_4_PICC 0x20
|
||||
|
||||
typedef enum { NONE, CC_FILE, NDEF_FILE } file;
|
||||
|
||||
struct nfcforum_tag4_ndef_data {
|
||||
uint8_t *ndef_file;
|
||||
size_t ndef_file_len;
|
||||
};
|
||||
|
||||
struct nfcforum_tag4_state_machine_data {
|
||||
file current_file;
|
||||
};
|
||||
|
||||
uint8_t nfcforum_capability_container[] = {
|
||||
0x00, 0x0F, /* CCLEN 15 bytes */
|
||||
0x10, /* Mapping version 1.0 */
|
||||
0x00, 0x54, /* MLe Maximum R-ADPU data size */
|
||||
// Notes:
|
||||
// - I (Romuald) don't know why Nokia 6212 Classic refuses the NDEF message if MLe is more than 0xFD (any suggests are welcome);
|
||||
// - ARYGON devices doesn't support extended frame sending, consequently these devices can't sent more than 0xFE bytes as APDU, so 0xFB APDU data bytes.
|
||||
// - I (Romuald) don't know why ARYGON device doesn't ACK when MLe > 0x54 (ARYGON frame lenght = 0xC2 (192 bytes))
|
||||
0x00, 0xFF, /* MLc Maximum C-ADPU data size */
|
||||
0x04, /* T field of the NDEF File-Control TLV */
|
||||
0x06, /* L field of the NDEF File-Control TLV */
|
||||
/* V field of the NDEF File-Control TLV */
|
||||
0xE1, 0x04, /* File identifier */
|
||||
0xFF, 0xFE, /* Maximum NDEF Size */
|
||||
0x00, /* NDEF file read access condition */
|
||||
0x00, /* NDEF file write access condition */
|
||||
};
|
||||
|
||||
/* C-ADPU offsets */
|
||||
#define CLA 0
|
||||
#define INS 1
|
||||
#define P1 2
|
||||
#define P2 3
|
||||
#define LC 4
|
||||
#define DATA 5
|
||||
|
||||
#define ISO144434A_RATS 0xE0
|
||||
|
||||
int
|
||||
nfcforum_tag4_io (struct nfc_emulator *emulator, const byte_t *data_in, const size_t data_in_len, byte_t *data_out, const size_t data_out_len)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
struct nfcforum_tag4_ndef_data *ndef_data = (struct nfcforum_tag4_ndef_data *)(emulator->user_data);
|
||||
struct nfcforum_tag4_state_machine_data *state_machine_data = (struct nfcforum_tag4_state_machine_data *)(emulator->state_machine->data);
|
||||
|
||||
if (data_in_len == 0) {
|
||||
// No input data, nothing to do
|
||||
return res;
|
||||
}
|
||||
|
||||
// Show transmitted command
|
||||
if (!quiet_output) {
|
||||
printf (" In: ");
|
||||
print_hex (data_in, data_in_len);
|
||||
}
|
||||
|
||||
if(data_in_len >= 4) {
|
||||
if (data_in[CLA] != 0x00)
|
||||
return -ENOTSUP;
|
||||
|
||||
#define ISO7816_SELECT 0xA4
|
||||
#define ISO7816_READ_BINARY 0xB0
|
||||
#define ISO7816_UPDATE_BINARY 0xD6
|
||||
|
||||
switch(data_in[INS]) {
|
||||
case ISO7816_SELECT:
|
||||
|
||||
switch (data_in[P1]) {
|
||||
case 0x00: /* Select by ID */
|
||||
if ((data_in[P2] | 0x0C) != 0x0C)
|
||||
return -ENOTSUP;
|
||||
|
||||
const uint8_t ndef_capability_container[] = { 0xE1, 0x03 };
|
||||
const uint8_t ndef_file[] = { 0xE1, 0x04 };
|
||||
if ((data_in[LC] == sizeof (ndef_capability_container)) && (0 == memcmp (ndef_capability_container, data_in + DATA, data_in[LC]))) {
|
||||
memcpy (data_out, "\x90\x00", res = 2);
|
||||
state_machine_data->current_file = CC_FILE;
|
||||
} else if ((data_in[LC] == sizeof (ndef_file)) && (0 == memcmp (ndef_file, data_in + DATA, data_in[LC]))) {
|
||||
memcpy (data_out, "\x90\x00", res = 2);
|
||||
state_machine_data->current_file = NDEF_FILE;
|
||||
} else {
|
||||
memcpy (data_out, "\x6a\x00", res = 2);
|
||||
state_machine_data->current_file = NONE;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x04: /* Select by name */
|
||||
if (data_in[P2] != 0x00)
|
||||
return -ENOTSUP;
|
||||
|
||||
const uint8_t ndef_tag_application_name[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 };
|
||||
if ((data_in[LC] == sizeof (ndef_tag_application_name)) && (0 == memcmp (ndef_tag_application_name, data_in + DATA, data_in[LC])))
|
||||
memcpy (data_out, "\x90\x00", res = 2);
|
||||
else
|
||||
memcpy (data_out, "\x6a\x82", res = 2);
|
||||
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
break;
|
||||
case ISO7816_READ_BINARY:
|
||||
if ((size_t)(data_in[LC] + 2) > data_out_len) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
switch (state_machine_data->current_file) {
|
||||
case NONE:
|
||||
memcpy (data_out, "\x6a\x82", res = 2);
|
||||
break;
|
||||
case CC_FILE:
|
||||
memcpy (data_out, nfcforum_capability_container + (data_in[P1] << 8) + data_in[P2], data_in[LC]);
|
||||
memcpy (data_out + data_in[LC], "\x90\x00", 2);
|
||||
res = data_in[LC] + 2;
|
||||
break;
|
||||
case NDEF_FILE:
|
||||
memcpy (data_out, ndef_data->ndef_file + (data_in[P1] << 8) + data_in[P2], data_in[LC]);
|
||||
memcpy (data_out + data_in[LC], "\x90\x00", 2);
|
||||
res = data_in[LC] + 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ISO7816_UPDATE_BINARY:
|
||||
memcpy (ndef_data->ndef_file + (data_in[P1] << 8) + data_in[P2], data_in + DATA, data_in[LC]);
|
||||
if ((data_in[P1] << 8) + data_in[P2] == 0) {
|
||||
ndef_data->ndef_file_len = (ndef_data->ndef_file[0] << 8) + ndef_data->ndef_file[1] + 2;
|
||||
}
|
||||
memcpy (data_out, "\x90\x00", res = 2);
|
||||
break;
|
||||
default: // Unknown
|
||||
if (!quiet_output) {
|
||||
printf("Unknown frame, emulated target abort.\n");
|
||||
}
|
||||
res = -ENOTSUP;
|
||||
}
|
||||
} else {
|
||||
res = -ENOTSUP;
|
||||
}
|
||||
|
||||
// Show transmitted command
|
||||
if (!quiet_output) {
|
||||
if (res < 0) {
|
||||
ERR ("%s (%d)", strerror (-res), -res);
|
||||
} else {
|
||||
printf (" Out: ");
|
||||
print_hex (data_out, res);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void stop_emulation (int sig)
|
||||
{
|
||||
(void) sig;
|
||||
if (pnd)
|
||||
nfc_abort_command (pnd);
|
||||
else
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
size_t
|
||||
ndef_message_load (char *filename, struct nfcforum_tag4_ndef_data *tag_data)
|
||||
{
|
||||
struct stat sb;
|
||||
if (stat (filename, &sb) < 0)
|
||||
return 0;
|
||||
|
||||
/* Check file size */
|
||||
if (sb.st_size > 0xFFFF) {
|
||||
errx (EXIT_FAILURE, "file size too large '%s'", filename);
|
||||
}
|
||||
|
||||
tag_data->ndef_file_len = sb.st_size + 2;
|
||||
|
||||
tag_data->ndef_file[0] = (uint8_t)(sb.st_size >> 8);
|
||||
tag_data->ndef_file[1] = (uint8_t)(sb.st_size);
|
||||
|
||||
FILE *F;
|
||||
if (!(F = fopen (filename, "r")))
|
||||
err (EXIT_FAILURE, "fopen (%s, \"r\")", filename);
|
||||
|
||||
if (1 != fread (tag_data->ndef_file + 2, sb.st_size, 1, F))
|
||||
err (EXIT_FAILURE, "Can't read from %s", filename);
|
||||
|
||||
fclose (F);
|
||||
return sb.st_size;
|
||||
}
|
||||
|
||||
size_t
|
||||
ndef_message_save (char *filename, struct nfcforum_tag4_ndef_data *tag_data)
|
||||
{
|
||||
FILE *F;
|
||||
if (!(F= fopen (filename, "w")))
|
||||
err (EXIT_FAILURE, "fopen (%s, w)", filename);
|
||||
|
||||
if (1 != fwrite (tag_data->ndef_file + 2, tag_data->ndef_file_len - 2, 1, F)) {
|
||||
err (EXIT_FAILURE, "fwrite (%d)", (int) tag_data->ndef_file_len -2);
|
||||
}
|
||||
|
||||
fclose (F);
|
||||
|
||||
return tag_data->ndef_file_len - 2;
|
||||
}
|
||||
|
||||
void
|
||||
usage (char *progname)
|
||||
{
|
||||
fprintf (stderr, "usage: %s [infile [outfile]]\n", progname);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
nfc_target_t nt = {
|
||||
.nm = {
|
||||
.nmt = NMT_ISO14443A,
|
||||
.nbr = NBR_UNDEFINED, // Will be updated by nfc_target_init()
|
||||
},
|
||||
.nti = {
|
||||
.nai = {
|
||||
.abtAtqa = { 0x00, 0x04 },
|
||||
.abtUid = { 0x08, 0x00, 0xb0, 0x0b },
|
||||
.szUidLen = 4,
|
||||
.btSak = 0x20,
|
||||
.abtAts = { 0x75, 0x33, 0x92, 0x03 }, /* Not used by PN532 */
|
||||
.szAtsLen = 4,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
uint8_t ndef_file[0xfffe] = {
|
||||
0x00, 33,
|
||||
0xd1, 0x02, 0x1c, 0x53, 0x70, 0x91, 0x01, 0x09, 0x54, 0x02,
|
||||
0x65, 0x6e, 0x4c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x51, 0x01,
|
||||
0x0b, 0x55, 0x03, 0x6c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x2e,
|
||||
0x6f, 0x72, 0x67
|
||||
};
|
||||
|
||||
struct nfcforum_tag4_ndef_data nfcforum_tag4_data = {
|
||||
.ndef_file = ndef_file,
|
||||
.ndef_file_len = ndef_file[1] + 2,
|
||||
};
|
||||
|
||||
struct nfcforum_tag4_state_machine_data state_machine_data = {
|
||||
.current_file = NONE,
|
||||
};
|
||||
|
||||
struct nfc_emulation_state_machine state_machine = {
|
||||
.io = nfcforum_tag4_io,
|
||||
.data = &state_machine_data,
|
||||
};
|
||||
|
||||
struct nfc_emulator emulator = {
|
||||
.target = &nt,
|
||||
.state_machine = &state_machine,
|
||||
.user_data = &nfcforum_tag4_data,
|
||||
};
|
||||
|
||||
if (argc > 3) {
|
||||
usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// If some file is provided load it
|
||||
if (argc >= 2) {
|
||||
if (!ndef_message_load (argv[1], &nfcforum_tag4_data)) {
|
||||
err (EXIT_FAILURE, "Can't load NDEF file '%s'", argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to open the NFC reader
|
||||
pnd = nfc_connect (NULL);
|
||||
|
||||
if (pnd == NULL) {
|
||||
ERR("Unable to connect to NFC device");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
signal (SIGINT, stop_emulation);
|
||||
|
||||
printf ("Connected to NFC device: %s\n", pnd->acName);
|
||||
printf ("Emulating NDEF tag now, please touch it with a second NFC device\n");
|
||||
|
||||
if (0 != nfc_emulate_target (pnd, &emulator)) { // contains already nfc_target_init() call
|
||||
nfc_perror (pnd, "nfc_emulate_target");
|
||||
}
|
||||
|
||||
nfc_disconnect(pnd);
|
||||
|
||||
if (argc == 3) {
|
||||
if (!(ndef_message_save (argv[2], &nfcforum_tag4_data))) {
|
||||
err (EXIT_FAILURE, "Can't save NDEF file '%s'", argv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
|
||||
#define MAX_FRAME_LEN (264)
|
||||
#define SAK_ISO14443_4_COMPLIANT 0x20
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
.TH NFC-LIST 1 "June 26, 2009"
|
||||
.SH NAME
|
||||
nfc-list \- List NFC targets
|
||||
.SH SYNOPSIS
|
||||
.B nfc-list
|
||||
.SH DESCRIPTION
|
||||
.B nfc-list
|
||||
is a utility for listing any available tags like ISO14443-A, FeliCa, Jewel
|
||||
or ISO14443-B (according to the device capabilities).
|
||||
It may detect several tags at once thanks to a mechanism called anti-collision
|
||||
but all types of tags don't support anti-collision and there is some physical
|
||||
limitation of the number of tags the reader can discover.
|
||||
|
||||
This tool displays all available information at selection time.
|
||||
|
||||
.SH OPTIONS
|
||||
\fB-v\fP, \fB--verbose\fP
|
||||
Verbose mode
|
||||
Tries to interpret data
|
||||
|
||||
.SH EXAMPLE
|
||||
For an ISO/IEC 14443-A tag (i.e.Mifare DESFire):
|
||||
|
||||
ATQA (SENS_RES): 03 44
|
||||
UID (NFCID1): 04 45 35 01 db 24 80
|
||||
SAK (SEL_RES): 20
|
||||
ATS (ATR): 75 77 81 02 80
|
||||
|
||||
.SH BUGS
|
||||
Please report any bugs on the
|
||||
.B libnfc
|
||||
forum at
|
||||
.BR http://www.libnfc.org/community/ "."
|
||||
.SH LICENCE
|
||||
.B libnfc
|
||||
and
|
||||
.B libnfc-examples
|
||||
are covered by the GNU Lesser General Public License (LGPL), version 3.
|
||||
.SH AUTHORS
|
||||
Roel Verdult <roel@libnfc.org>
|
||||
Romuald Conty <romuald@libnfc.org>
|
||||
.PP
|
||||
This manual page was written by Romuald Conty <romuald@libnfc.org>.
|
||||
It is licensed under the terms of the GNU GPL (version 2 or later).
|
||||
|
|
@ -1,248 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-list.c
|
||||
* @brief Lists the first target present of each founded device
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
# ifdef DEBUG
|
||||
# include <sys/param.h>
|
||||
# include <usb.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
#define MAX_DEVICE_COUNT 16
|
||||
#define MAX_TARGET_COUNT 16
|
||||
|
||||
static nfc_device_t *pnd;
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
const char *acLibnfcVersion;
|
||||
size_t szDeviceFound;
|
||||
size_t szTargetFound;
|
||||
size_t i;
|
||||
bool verbose = false;
|
||||
nfc_device_desc_t *pnddDevices;
|
||||
|
||||
// Display libnfc version
|
||||
acLibnfcVersion = nfc_version ();
|
||||
printf ("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
|
||||
|
||||
pnddDevices = parse_args (argc, argv, &szDeviceFound, &verbose);
|
||||
#ifdef HAVE_LIBUSB
|
||||
# ifdef DEBUG
|
||||
usb_set_debug (4);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Lazy way to open an NFC device */
|
||||
#if 0
|
||||
pnd = nfc_connect (NULL);
|
||||
#endif
|
||||
|
||||
/* If specific device is wanted, i.e. an ARYGON device on /dev/ttyUSB0 */
|
||||
#if 0
|
||||
nfc_device_desc_t ndd;
|
||||
ndd.pcDriver = "ARYGON";
|
||||
ndd.pcPort = "/dev/ttyUSB0";
|
||||
ndd.uiSpeed = 115200;
|
||||
pnd = nfc_connect (&ndd);
|
||||
#endif
|
||||
|
||||
/* If specific device is wanted, i.e. a SCL3711 on USB */
|
||||
#if 0
|
||||
nfc_device_desc_t ndd;
|
||||
ndd.pcDriver = "PN533_USB";
|
||||
strcpy(ndd.acDevice, "SCM Micro / SCL3711-NFC&RW");
|
||||
pnd = nfc_connect (&ndd);
|
||||
#endif
|
||||
|
||||
if (szDeviceFound == 0) {
|
||||
if (!(pnddDevices = malloc (MAX_DEVICE_COUNT * sizeof (*pnddDevices)))) {
|
||||
fprintf (stderr, "malloc() failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
nfc_list_devices (pnddDevices, MAX_DEVICE_COUNT, &szDeviceFound);
|
||||
}
|
||||
|
||||
if (szDeviceFound == 0) {
|
||||
printf ("No NFC device found.\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < szDeviceFound; i++) {
|
||||
nfc_target_t ant[MAX_TARGET_COUNT];
|
||||
pnd = nfc_connect (&(pnddDevices[i]));
|
||||
|
||||
if (pnd == NULL) {
|
||||
ERR ("%s", "Unable to connect to NFC device.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
nfc_initiator_init (pnd);
|
||||
|
||||
printf ("Connected to NFC device: %s\n", pnd->acName);
|
||||
|
||||
nfc_modulation_t nm;
|
||||
|
||||
nm.nmt = NMT_ISO14443A;
|
||||
nm.nbr = NBR_106;
|
||||
// List ISO14443A targets
|
||||
if (nfc_initiator_list_passive_targets (pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound)) {
|
||||
size_t n;
|
||||
if (verbose || (szTargetFound > 0)) {
|
||||
printf ("%d ISO14443A passive target(s) found%s\n", (int) szTargetFound, (szTargetFound == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < szTargetFound; n++) {
|
||||
print_nfc_iso14443a_info (ant[n].nti.nai, verbose);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
nm.nmt = NMT_FELICA;
|
||||
nm.nbr = NBR_212;
|
||||
// List Felica tags
|
||||
if (nfc_initiator_list_passive_targets (pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound)) {
|
||||
size_t n;
|
||||
if (verbose || (szTargetFound > 0)) {
|
||||
printf ("%d Felica (212 kbps) passive target(s) found%s\n", (int) szTargetFound,
|
||||
(szTargetFound == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < szTargetFound; n++) {
|
||||
print_nfc_felica_info (ant[n].nti.nfi, verbose);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
nm.nbr = NBR_424;
|
||||
if (nfc_initiator_list_passive_targets (pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound)) {
|
||||
size_t n;
|
||||
if (verbose || (szTargetFound > 0)) {
|
||||
printf ("%d Felica (424 kbps) passive target(s) found%s\n", (int) szTargetFound,
|
||||
(szTargetFound == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < szTargetFound; n++) {
|
||||
print_nfc_felica_info (ant[n].nti.nfi, verbose);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
nm.nmt = NMT_ISO14443B;
|
||||
nm.nbr = NBR_106;
|
||||
// List ISO14443B targets
|
||||
if (nfc_initiator_list_passive_targets (pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound)) {
|
||||
size_t n;
|
||||
if (verbose || (szTargetFound > 0)) {
|
||||
printf ("%d ISO14443B passive target(s) found%s\n", (int) szTargetFound, (szTargetFound == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < szTargetFound; n++) {
|
||||
print_nfc_iso14443b_info (ant[n].nti.nbi, verbose);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
nm.nmt = NMT_ISO14443BI;
|
||||
nm.nbr = NBR_106;
|
||||
// List ISO14443B' targets
|
||||
if (nfc_initiator_list_passive_targets (pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound)) {
|
||||
size_t n;
|
||||
if (verbose || (szTargetFound > 0)) {
|
||||
printf ("%d ISO14443B' passive target(s) found%s\n", (int) szTargetFound, (szTargetFound == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < szTargetFound; n++) {
|
||||
print_nfc_iso14443bi_info (ant[n].nti.nii, verbose);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
nm.nmt = NMT_ISO14443B2SR;
|
||||
nm.nbr = NBR_106;
|
||||
// List ISO14443B-2 ST SRx family targets
|
||||
if (nfc_initiator_list_passive_targets (pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound)) {
|
||||
size_t n;
|
||||
if (verbose || (szTargetFound > 0)) {
|
||||
printf ("%d ISO14443B-2 ST SRx passive target(s) found%s\n", (int) szTargetFound, (szTargetFound == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < szTargetFound; n++) {
|
||||
print_nfc_iso14443b2sr_info (ant[n].nti.nsi, verbose);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
nm.nmt = NMT_ISO14443B2CT;
|
||||
nm.nbr = NBR_106;
|
||||
// List ISO14443B-2 ASK CTx family targets
|
||||
if (nfc_initiator_list_passive_targets (pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound)) {
|
||||
size_t n;
|
||||
if (verbose || (szTargetFound > 0)) {
|
||||
printf ("%d ISO14443B-2 ASK CTx passive target(s) found%s\n", (int) szTargetFound, (szTargetFound == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < szTargetFound; n++) {
|
||||
print_nfc_iso14443b2ct_info (ant[n].nti.nci, verbose);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
nm.nmt = NMT_JEWEL;
|
||||
nm.nbr = NBR_106;
|
||||
// List Jewel targets
|
||||
if (nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT, &szTargetFound )) {
|
||||
size_t n;
|
||||
if (verbose || (szTargetFound > 0)) {
|
||||
printf("%d Jewel passive target(s) found%s\n", (int)szTargetFound, (szTargetFound==0)?".\n":":");
|
||||
}
|
||||
for(n=0; n<szTargetFound; n++) {
|
||||
print_nfc_jewel_info (ant[n].nti.nji, verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
nfc_disconnect (pnd);
|
||||
}
|
||||
|
||||
free (pnddDevices);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
.TH NFC-MFCLASSIC 1 "Nov 02, 2009"
|
||||
.SH NAME
|
||||
nfc-mfclassic \- MIFARE Classic command line tool
|
||||
.SH SYNOPSIS
|
||||
.B nfc-mfclassic
|
||||
.RI \fR\fBr\fR|\fR\fBR\fR|\fBw\fR\fR|\fBW\fR
|
||||
.RI \fR\fBa\fR|\fBb\fR
|
||||
.IR DUMP
|
||||
.IR [KEYS]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B nfc-mfclassic
|
||||
is a MIFARE Classic tool that allow to read or write
|
||||
.IR DUMP
|
||||
file using Mifare keys provided in
|
||||
.IR KEYS
|
||||
file.
|
||||
|
||||
MIFARE Classic tag is one of the most widely used RFID tags.
|
||||
|
||||
The firmware in the NFC controller supports authenticating, reading and writing
|
||||
to/from Mifare Classic tags. This tool demonstrates the speed of this library
|
||||
and its ease-of-use. It's possible to read and write the complete content of a
|
||||
Mifare Classic 4KB tag within 1 second. It uses a binary Mifare Dump file (MFD)
|
||||
to store the keys and data for all sectors.
|
||||
|
||||
Be cautious that some parts of a Mifare Classic memory are used for r/w access
|
||||
of the rest of the memory, so please read the tag documentation before experimenting too much!
|
||||
|
||||
The 'W' option allows writing of special Mifare cards that can be 'unlocked' to allow block 0
|
||||
to be overwritten. This includes UID and manufacturer data. Take care when amending UIDs to set
|
||||
the correct BCC (UID checksum). Currently only 4 byte UIDs are supported.
|
||||
|
||||
Similarly, the 'R' option allows an 'unlocked' read. This bypasses authentication and allows
|
||||
reading of the Key A and Key B data regardless of ACLs.
|
||||
|
||||
*** Note that 'W' and 'R' options only work on special versions of Mifare 1K cards (Chinese clones).
|
||||
|
||||
.SH OPTIONS
|
||||
.BR r " | " R " | " w " | " W
|
||||
Perform read from (
|
||||
.B r
|
||||
) or unlocked read from (
|
||||
.B R
|
||||
) or write to (
|
||||
.B w
|
||||
) or unlocked write to (
|
||||
.B W
|
||||
) card.
|
||||
.TP
|
||||
.BR a " | " b
|
||||
Use A or B Mifare keys.
|
||||
.TP
|
||||
.IR DUMP
|
||||
MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)
|
||||
.TP
|
||||
.IR KEYS
|
||||
MiFare Dump (MFD) that contains the keys (optional). Data part of the dump is ignored.
|
||||
|
||||
|
||||
.SH BUGS
|
||||
Please report any bugs on the
|
||||
.B libnfc
|
||||
forum at
|
||||
.BR http://www.libnfc.org/community/ "."
|
||||
.SH LICENCE
|
||||
.B libnfc
|
||||
and
|
||||
.B libnfc-examples
|
||||
are covered by the GNU Lesser General Public License (LGPL), version 3.
|
||||
.SH AUTHORS
|
||||
Roel Verdult <roel@libnfc.org>
|
||||
Romuald Conty <romuald@libnfc.org>
|
||||
Romain Tartière <romain@blogreen.org>
|
||||
Adam Laurie <adam@algroup.co.uk>
|
||||
.PP
|
||||
This manual page was written by Romuald Conty <romuald@libnfc.org>.
|
||||
It is licensed under the terms of the GNU GPL (version 2 or later).
|
||||
|
|
@ -1,663 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
* Copyright (C) 2011, Adam Laurie
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-mfclassic.c
|
||||
* @brief MIFARE Classic manipulation example
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "mifare.h"
|
||||
#include "nfc-utils.h"
|
||||
|
||||
static nfc_device_t *pnd;
|
||||
static nfc_target_t nt;
|
||||
static mifare_param mp;
|
||||
static mifare_classic_tag mtKeys;
|
||||
static mifare_classic_tag mtDump;
|
||||
static bool bUseKeyA;
|
||||
static bool bUseKeyFile;
|
||||
static uint8_t uiBlocks;
|
||||
static byte_t keys[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
|
||||
0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd,
|
||||
0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a,
|
||||
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xab, 0xcd, 0xef, 0x12, 0x34, 0x56
|
||||
};
|
||||
|
||||
static const nfc_modulation_t nmMifare = {
|
||||
.nmt = NMT_ISO14443A,
|
||||
.nbr = NBR_106,
|
||||
};
|
||||
|
||||
static size_t num_keys = sizeof (keys) / 6;
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
|
||||
static byte_t abtRx[MAX_FRAME_LEN];
|
||||
static size_t szRxBits;
|
||||
static size_t szRx = sizeof(abtRx);
|
||||
|
||||
byte_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 };
|
||||
|
||||
// special unlock command
|
||||
byte_t abtUnlock1[1] = { 0x40 };
|
||||
byte_t abtUnlock2[1] = { 0x43 };
|
||||
|
||||
static bool
|
||||
transmit_bits (const byte_t * pbtTx, const size_t szTxBits)
|
||||
{
|
||||
// Show transmitted command
|
||||
printf ("Sent bits: ");
|
||||
print_hex_bits (pbtTx, szTxBits);
|
||||
// Transmit the bit frame command, we don't use the arbitrary parity feature
|
||||
if (!nfc_initiator_transceive_bits (pnd, pbtTx, szTxBits, NULL, abtRx, &szRxBits, NULL))
|
||||
return false;
|
||||
|
||||
// Show received answer
|
||||
printf ("Received bits: ");
|
||||
print_hex_bits (abtRx, szRxBits);
|
||||
// Succesful transfer
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
transmit_bytes (const byte_t * pbtTx, const size_t szTx)
|
||||
{
|
||||
// Show transmitted command
|
||||
printf ("Sent bits: ");
|
||||
print_hex (pbtTx, szTx);
|
||||
// Transmit the command bytes
|
||||
if (!nfc_initiator_transceive_bytes (pnd, pbtTx, szTx, abtRx, &szRx, NULL))
|
||||
return false;
|
||||
|
||||
// Show received answer
|
||||
printf ("Received bits: ");
|
||||
print_hex (abtRx, szRx);
|
||||
// Succesful transfer
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
print_success_or_failure (bool bFailure, uint32_t * uiBlockCounter)
|
||||
{
|
||||
printf ("%c", (bFailure) ? 'x' : '.');
|
||||
if (uiBlockCounter && !bFailure)
|
||||
*uiBlockCounter += (*uiBlockCounter < 128) ? 4 : 16;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_first_block (uint32_t uiBlock)
|
||||
{
|
||||
// Test if we are in the small or big sectors
|
||||
if (uiBlock < 128)
|
||||
return ((uiBlock) % 4 == 0);
|
||||
else
|
||||
return ((uiBlock) % 16 == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_trailer_block (uint32_t uiBlock)
|
||||
{
|
||||
// Test if we are in the small or big sectors
|
||||
if (uiBlock < 128)
|
||||
return ((uiBlock + 1) % 4 == 0);
|
||||
else
|
||||
return ((uiBlock + 1) % 16 == 0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_trailer_block (uint32_t uiFirstBlock)
|
||||
{
|
||||
// Test if we are in the small or big sectors
|
||||
uint32_t trailer_block = 0;
|
||||
if (uiFirstBlock < 128) {
|
||||
trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4));
|
||||
} else {
|
||||
trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16));
|
||||
}
|
||||
return trailer_block;
|
||||
}
|
||||
|
||||
static bool
|
||||
authenticate (uint32_t uiBlock)
|
||||
{
|
||||
mifare_cmd mc;
|
||||
uint32_t uiTrailerBlock;
|
||||
size_t key_index;
|
||||
|
||||
// Set the authentication information (uid)
|
||||
memcpy (mp.mpa.abtUid, nt.nti.nai.abtUid + nt.nti.nai.szUidLen - 4, 4);
|
||||
|
||||
// Should we use key A or B?
|
||||
mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B;
|
||||
|
||||
// Key file authentication.
|
||||
if (bUseKeyFile) {
|
||||
|
||||
// Locate the trailer (with the keys) used for this sector
|
||||
uiTrailerBlock = get_trailer_block (uiBlock);
|
||||
|
||||
// Extract the right key from dump file
|
||||
if (bUseKeyA)
|
||||
memcpy (mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, 6);
|
||||
else
|
||||
memcpy (mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, 6);
|
||||
|
||||
// Try to authenticate for the current sector
|
||||
if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp))
|
||||
return true;
|
||||
} else {
|
||||
// Try to guess the right key
|
||||
for (key_index = 0; key_index < num_keys; key_index++) {
|
||||
memcpy (mp.mpa.abtKey, keys + (key_index * 6), 6);
|
||||
if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp)) {
|
||||
if (bUseKeyA)
|
||||
memcpy (mtKeys.amb[uiBlock].mbt.abtKeyA, &mp.mpa.abtKey, 6);
|
||||
else
|
||||
memcpy (mtKeys.amb[uiBlock].mbt.abtKeyB, &mp.mpa.abtKey, 6);
|
||||
return true;
|
||||
}
|
||||
nfc_initiator_select_passive_target (pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
unlock_card()
|
||||
{
|
||||
printf ("Unlocking card\n");
|
||||
|
||||
// Configure the CRC
|
||||
if (!nfc_configure (pnd, NDO_HANDLE_CRC, false)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// Use raw send/receive methods
|
||||
if (!nfc_configure (pnd, NDO_EASY_FRAMING, false)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
iso14443a_crc_append(abtHalt, 2);
|
||||
transmit_bytes (abtHalt, 4);
|
||||
// now send unlock
|
||||
if (!transmit_bits (abtUnlock1, 7)) {
|
||||
printf("unlock failure!\n");
|
||||
return false;
|
||||
}
|
||||
if (!transmit_bytes (abtUnlock2, 1)) {
|
||||
printf("unlock failure!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// reset reader
|
||||
// Configure the CRC
|
||||
if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// Switch off raw send/receive methods
|
||||
if (!nfc_configure (pnd, NDO_EASY_FRAMING, true)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
read_card (int read_unlocked)
|
||||
{
|
||||
int32_t iBlock;
|
||||
bool bFailure = false;
|
||||
uint32_t uiReadBlocks = 0;
|
||||
|
||||
if(read_unlocked)
|
||||
if (!unlock_card())
|
||||
return false;
|
||||
|
||||
|
||||
printf ("Reading out %d blocks |", uiBlocks + 1);
|
||||
|
||||
// Read the card from end to begin
|
||||
for (iBlock = uiBlocks; iBlock >= 0; iBlock--) {
|
||||
// Authenticate everytime we reach a trailer block
|
||||
if (is_trailer_block (iBlock)) {
|
||||
// Skip this the first time, bFailure it means nothing (yet)
|
||||
if (iBlock != uiBlocks)
|
||||
print_success_or_failure (bFailure, &uiReadBlocks);
|
||||
|
||||
// Show if the readout went well
|
||||
if (bFailure) {
|
||||
// When a failure occured we need to redo the anti-collision
|
||||
if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
|
||||
printf ("!\nError: tag was removed\n");
|
||||
return false;
|
||||
}
|
||||
bFailure = false;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
// Try to authenticate for the current sector
|
||||
if (!read_unlocked && !authenticate (iBlock)) {
|
||||
printf ("!\nError: authentication failed for block 0x%02x\n", iBlock);
|
||||
return false;
|
||||
}
|
||||
// Try to read out the trailer
|
||||
if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) {
|
||||
if(read_unlocked) {
|
||||
memcpy (mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16);
|
||||
} else {
|
||||
// Copy the keys over from our key dump and store the retrieved access bits
|
||||
memcpy (mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, 6);
|
||||
memcpy (mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpd.abtData + 6, 4);
|
||||
memcpy (mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, 6);
|
||||
}
|
||||
} else {
|
||||
printf ("!\nError: unable to read trailer block 0x%02x\n", iBlock);
|
||||
}
|
||||
} else {
|
||||
// Make sure a earlier readout did not fail
|
||||
if (!bFailure) {
|
||||
// Try to read out the data block
|
||||
if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) {
|
||||
memcpy (mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16);
|
||||
} else {
|
||||
bFailure = true;
|
||||
printf ("!\nError: unable to read block 0x%02x\n", iBlock);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
print_success_or_failure (bFailure, &uiReadBlocks);
|
||||
printf ("|\n");
|
||||
printf ("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1);
|
||||
fflush (stdout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
write_card (int write_block_zero)
|
||||
{
|
||||
uint32_t uiBlock;
|
||||
bool bFailure = false;
|
||||
uint32_t uiWriteBlocks = 0;
|
||||
|
||||
|
||||
if(write_block_zero)
|
||||
if (!unlock_card())
|
||||
return false;
|
||||
|
||||
printf ("Writing %d blocks |", uiBlocks + 1);
|
||||
// Write the card from begin to end;
|
||||
for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) {
|
||||
// Authenticate everytime we reach the first sector of a new block
|
||||
if (is_first_block (uiBlock)) {
|
||||
// Skip this the first time, bFailure it means nothing (yet)
|
||||
if (uiBlock != 0)
|
||||
print_success_or_failure (bFailure, &uiWriteBlocks);
|
||||
|
||||
// Show if the readout went well
|
||||
if (bFailure) {
|
||||
// When a failure occured we need to redo the anti-collision
|
||||
if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
|
||||
printf ("!\nError: tag was removed\n");
|
||||
return false;
|
||||
}
|
||||
bFailure = false;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
// Try to authenticate for the current sector
|
||||
if (!write_block_zero && !authenticate (uiBlock)) {
|
||||
printf ("!\nError: authentication failed for block %02x\n", uiBlock);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_trailer_block (uiBlock)) {
|
||||
// Copy the keys over from our key dump and store the retrieved access bits
|
||||
memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbt.abtKeyA, 6);
|
||||
memcpy (mp.mpd.abtData + 6, mtDump.amb[uiBlock].mbt.abtAccessBits, 4);
|
||||
memcpy (mp.mpd.abtData + 10, mtDump.amb[uiBlock].mbt.abtKeyB, 6);
|
||||
|
||||
// Try to write the trailer
|
||||
if (nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp) == false) {
|
||||
printf ("failed to write trailer block %d \n", uiBlock);
|
||||
bFailure = true;
|
||||
}
|
||||
} else {
|
||||
// The first block 0x00 is read only, skip this
|
||||
if (uiBlock == 0 && ! write_block_zero)
|
||||
continue;
|
||||
|
||||
|
||||
// Make sure a earlier write did not fail
|
||||
if (!bFailure) {
|
||||
// Try to write the data block
|
||||
memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, 16);
|
||||
// do not write a block 0 with incorrect BCC - card will be made invalid!
|
||||
if (uiBlock == 0) {
|
||||
if((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00) {
|
||||
printf ("!\nError: incorrect BCC in MFD file!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp))
|
||||
bFailure = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
print_success_or_failure (bFailure, &uiWriteBlocks);
|
||||
printf ("|\n");
|
||||
printf ("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
|
||||
fflush (stdout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
mifare_classic_extract_payload (const char *abDump, char *pbPayload)
|
||||
{
|
||||
uint8_t uiSectorIndex;
|
||||
uint8_t uiBlockIndex;
|
||||
size_t szDumpOffset;
|
||||
size_t szPayloadIndex = 0;
|
||||
|
||||
for (uiSectorIndex = 1; uiSectorIndex < 16; uiSectorIndex++) {
|
||||
for (uiBlockIndex = 0; uiBlockIndex < 3; uiBlockIndex++) {
|
||||
szDumpOffset = uiSectorIndex * 16 * 4 + uiBlockIndex * 16;
|
||||
// for(uint8_t uiByteIndex=0; uiByteIndex<16; uiByteIndex++) printf("%02x ", abDump[szPayloadIndex+uiByteIndex]);
|
||||
memcpy (pbPayload + szPayloadIndex, abDump + szDumpOffset, 16);
|
||||
szPayloadIndex += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
ACTION_READ,
|
||||
ACTION_WRITE,
|
||||
ACTION_EXTRACT,
|
||||
ACTION_USAGE
|
||||
} action_t;
|
||||
|
||||
static void
|
||||
print_usage (const char *pcProgramName)
|
||||
{
|
||||
printf ("Usage: ");
|
||||
printf ("%s r|R|w|W a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
|
||||
printf (" r|R|w|W - Perform read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n");
|
||||
printf (" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
|
||||
printf (" *** unlocked read does not require authentication and will reveal A and B keys\n");
|
||||
printf (" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n");
|
||||
printf (" a|b - Use A or B keys for action\n");
|
||||
printf (" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
|
||||
printf (" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
|
||||
printf ("Or: ");
|
||||
printf ("%s x <dump.mfd> <payload.bin>\n", pcProgramName);
|
||||
printf (" x - Extract payload (data blocks) from MFD\n");
|
||||
printf (" <dump.mfd> - MiFare Dump (MFD) that contains wanted payload\n");
|
||||
printf (" <payload.bin> - Binary file where payload will be extracted\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
action_t atAction = ACTION_USAGE;
|
||||
byte_t *pbtUID;
|
||||
FILE *pfKeys = NULL;
|
||||
FILE *pfDump = NULL;
|
||||
int unlock= 0;
|
||||
|
||||
if (argc < 2) {
|
||||
print_usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
const char *command = argv[1];
|
||||
|
||||
if (strcmp (command, "r") == 0 || strcmp (command, "R") == 0) {
|
||||
if (argc < 4) {
|
||||
print_usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
atAction = ACTION_READ;
|
||||
if (strcmp (command, "R") == 0)
|
||||
unlock= 1;
|
||||
bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
|
||||
bUseKeyFile = (argc > 4);
|
||||
} else if (strcmp (command, "w") == 0 || strcmp (command, "W") == 0) {
|
||||
if (argc < 4) {
|
||||
print_usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
atAction = ACTION_WRITE;
|
||||
if (strcmp (command, "W") == 0)
|
||||
unlock= 1;
|
||||
bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
|
||||
bUseKeyFile = (argc > 4);
|
||||
} else if (strcmp (command, "x") == 0) {
|
||||
if (argc < 4) {
|
||||
print_usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
atAction = ACTION_EXTRACT;
|
||||
}
|
||||
|
||||
switch (atAction) {
|
||||
case ACTION_USAGE:
|
||||
print_usage (argv[0]);
|
||||
exit (EXIT_FAILURE);
|
||||
break;
|
||||
case ACTION_READ:
|
||||
case ACTION_WRITE:
|
||||
if (bUseKeyFile) {
|
||||
pfKeys = fopen (argv[4], "rb");
|
||||
if (pfKeys == NULL) {
|
||||
printf ("Could not open keys file: %s\n", argv[4]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (fread (&mtKeys, 1, sizeof (mtKeys), pfKeys) != sizeof (mtKeys)) {
|
||||
printf ("Could not read keys file: %s\n", argv[4]);
|
||||
fclose (pfKeys);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
fclose (pfKeys);
|
||||
}
|
||||
|
||||
if (atAction == ACTION_READ) {
|
||||
memset (&mtDump, 0x00, sizeof (mtDump));
|
||||
} else {
|
||||
pfDump = fopen (argv[3], "rb");
|
||||
|
||||
if (pfDump == NULL) {
|
||||
printf ("Could not open dump file: %s\n", argv[3]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fread (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
|
||||
printf ("Could not read dump file: %s\n", argv[3]);
|
||||
fclose (pfDump);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
fclose (pfDump);
|
||||
}
|
||||
// printf("Successfully opened required files\n");
|
||||
|
||||
// Try to open the NFC reader
|
||||
pnd = nfc_connect (NULL);
|
||||
if (pnd == NULL) {
|
||||
printf ("Error connecting NFC reader\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
nfc_initiator_init (pnd);
|
||||
|
||||
// Let the reader only try once to find a tag
|
||||
if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// Disable ISO14443-4 switching in order to read devices that emulate Mifare Classic with ISO14443-4 compliance.
|
||||
nfc_configure (pnd, NDO_AUTO_ISO14443_4, false);
|
||||
|
||||
printf ("Connected to NFC reader: %s\n", pnd->acName);
|
||||
|
||||
// Try to find a MIFARE Classic tag
|
||||
if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
|
||||
printf ("Error: no tag was found\n");
|
||||
nfc_disconnect (pnd);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// Test if we are dealing with a MIFARE compatible tag
|
||||
if ((nt.nti.nai.btSak & 0x08) == 0) {
|
||||
printf ("Warning: tag is probably not a MFC!\n");
|
||||
}
|
||||
|
||||
// Get the info from the current tag
|
||||
pbtUID = nt.nti.nai.abtUid;
|
||||
|
||||
if (bUseKeyFile) {
|
||||
byte_t fileUid[4];
|
||||
memcpy (fileUid, mtKeys.amb[0].mbm.abtUID, 4);
|
||||
// Compare if key dump UID is the same as the current tag UID, at least for the first 4 bytes
|
||||
if (memcmp (nt.nti.nai.abtUid, fileUid, 4) != 0) {
|
||||
printf ("Expected MIFARE Classic card with UID starting as: %02x%02x%02x%02x\n",
|
||||
fileUid[0], fileUid[1], fileUid[2], fileUid[3]);
|
||||
}
|
||||
}
|
||||
printf ("Found MIFARE Classic card:\n");
|
||||
print_nfc_iso14443a_info (nt.nti.nai, false);
|
||||
|
||||
// Guessing size
|
||||
if ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x02)
|
||||
// 4K
|
||||
uiBlocks = 0xff;
|
||||
else if ((nt.nti.nai.btSak & 0x01) == 0x01)
|
||||
// 320b
|
||||
uiBlocks = 0x13;
|
||||
else
|
||||
// 1K
|
||||
// TODO: for MFP it is 0x7f (2K) but how to be sure it's a MFP? Try to get RATS?
|
||||
uiBlocks = 0x3f;
|
||||
printf ("Guessing size: seems to be a %i-byte card\n", (uiBlocks + 1) * 16);
|
||||
|
||||
if (atAction == ACTION_READ) {
|
||||
if (read_card (unlock)) {
|
||||
printf ("Writing data to file: %s ...", argv[3]);
|
||||
fflush (stdout);
|
||||
pfDump = fopen (argv[3], "wb");
|
||||
if (pfDump == NULL) {
|
||||
printf ("Could not open dump file: %s\n", argv[3]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (fwrite (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
|
||||
printf ("\nCould not write to file: %s\n", argv[3]);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
printf ("Done.\n");
|
||||
fclose (pfDump);
|
||||
}
|
||||
} else if (atAction == ACTION_WRITE) {
|
||||
write_card (unlock);
|
||||
}
|
||||
|
||||
nfc_disconnect (pnd);
|
||||
break;
|
||||
|
||||
case ACTION_EXTRACT:{
|
||||
const char *pcDump = argv[2];
|
||||
const char *pcPayload = argv[3];
|
||||
|
||||
FILE *pfDump = NULL;
|
||||
FILE *pfPayload = NULL;
|
||||
|
||||
char abDump[4096];
|
||||
char abPayload[4096];
|
||||
|
||||
pfDump = fopen (pcDump, "rb");
|
||||
|
||||
if (pfDump == NULL) {
|
||||
printf ("Could not open dump file: %s\n", pcDump);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fread (abDump, 1, sizeof (abDump), pfDump) != sizeof (abDump)) {
|
||||
printf ("Could not read dump file: %s\n", pcDump);
|
||||
fclose (pfDump);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
fclose (pfDump);
|
||||
|
||||
mifare_classic_extract_payload (abDump, abPayload);
|
||||
|
||||
printf ("Writing data to file: %s\n", pcPayload);
|
||||
pfPayload = fopen (pcPayload, "wb");
|
||||
if (pfPayload == NULL) {
|
||||
printf ("Could not open file %s for writting.\n", pcPayload);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (fwrite (abPayload, 1, sizeof (abPayload), pfPayload) != sizeof (abPayload)) {
|
||||
printf ("Could not write to file: %s\n", pcPayload);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
fclose (pfPayload);
|
||||
printf ("Done, all bytes have been extracted!\n");
|
||||
}
|
||||
};
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
.TH NFC-MFSETUID 1 "Sep 05, 2011"
|
||||
.SH NAME
|
||||
nfc-mfsetuid \- MIFARE 1K special card UID setting and recovery tool
|
||||
.SH SYNOPSIS
|
||||
.B nfc-mfsetuid
|
||||
[UID]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B nfc-mfsetuid
|
||||
is a MIFARE tool that allows setting of UID on special versions (Chinese clones) of Mifare 1K cards. It will also recover
|
||||
damaged cards that have had invalid data written to block 0 (e.g. wrong BCC). Currently only 4 Byte UID is supported.
|
||||
Specify an eight hex character UID or leave blank for the default '01234567'.
|
||||
|
||||
.SH OPTIONS
|
||||
.B -f
|
||||
Format. Wipe all data (set to 0xFF) and reset ACLs to defaults.
|
||||
|
||||
.B -q
|
||||
Quiet. Suppress output of commands and responses.
|
||||
.SH BUGS
|
||||
Please report any bugs on the
|
||||
.B libnfc
|
||||
forum at
|
||||
.BR http://www.libnfc.org/community/ "."
|
||||
.SH LICENCE
|
||||
.B libnfc
|
||||
and
|
||||
.B libnfc-examples
|
||||
are covered by the GNU Lesser General Public License (LGPL), version 3.
|
||||
.SH AUTHORS
|
||||
Roel Verdult <roel@libnfc.org>
|
||||
Adam Laurie <adam@algroup.co.uk>
|
||||
.PP
|
||||
This manual page was written by Adam Laurie <adam@algroup.co.uk>.
|
||||
It is licensed under the terms of the GNU GPL (version 2 or later).
|
||||
|
|
@ -1,352 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2011, Adam Laurie
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-mfsetuid.c
|
||||
* @brief Set UID of special Mifare cards
|
||||
*/
|
||||
|
||||
/**
|
||||
* based on nfc-anticol.c
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
#define SAK_FLAG_ATS_SUPPORTED 0x20
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
|
||||
static byte_t abtRx[MAX_FRAME_LEN];
|
||||
static size_t szRxBits;
|
||||
static size_t szRx = sizeof(abtRx);
|
||||
static byte_t abtRawUid[12];
|
||||
static byte_t abtAtqa[2];
|
||||
static byte_t abtSak;
|
||||
static byte_t abtAts[MAX_FRAME_LEN];
|
||||
static byte_t szAts = 0;
|
||||
static size_t szCL = 1;//Always start with Cascade Level 1 (CL1)
|
||||
static nfc_device_t *pnd;
|
||||
|
||||
bool quiet_output = false;
|
||||
bool iso_ats_supported = false;
|
||||
|
||||
// ISO14443A Anti-Collision Commands
|
||||
byte_t abtReqa[1] = { 0x26 };
|
||||
byte_t abtSelectAll[2] = { 0x93, 0x20 };
|
||||
byte_t abtSelectTag[9] = { 0x93, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
byte_t abtRats[4] = { 0xe0, 0x50, 0x00, 0x00 };
|
||||
byte_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 };
|
||||
#define CASCADE_BIT 0x04
|
||||
|
||||
// special unlock command
|
||||
byte_t abtUnlock1[1] = { 0x40 };
|
||||
byte_t abtUnlock2[1] = { 0x43 };
|
||||
byte_t abtWipe[1] = { 0x41 };
|
||||
byte_t abtWrite[4] = { 0xa0, 0x00, 0x5f, 0xb1 };
|
||||
byte_t abtData[18] = { 0x01, 0x23, 0x45, 0x67, 0x00, 0x08, 0x04, 0x00, 0x46, 0x59, 0x25, 0x58, 0x49, 0x10, 0x23, 0x02, 0x23, 0xeb };
|
||||
byte_t abtBlank[18] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x36, 0xCC };
|
||||
|
||||
|
||||
static bool
|
||||
transmit_bits (const byte_t * pbtTx, const size_t szTxBits)
|
||||
{
|
||||
// Show transmitted command
|
||||
if (!quiet_output) {
|
||||
printf ("Sent bits: ");
|
||||
print_hex_bits (pbtTx, szTxBits);
|
||||
}
|
||||
// Transmit the bit frame command, we don't use the arbitrary parity feature
|
||||
if (!nfc_initiator_transceive_bits (pnd, pbtTx, szTxBits, NULL, abtRx, &szRxBits, NULL))
|
||||
return false;
|
||||
|
||||
// Show received answer
|
||||
if (!quiet_output) {
|
||||
printf ("Received bits: ");
|
||||
print_hex_bits (abtRx, szRxBits);
|
||||
}
|
||||
// Succesful transfer
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
transmit_bytes (const byte_t * pbtTx, const size_t szTx)
|
||||
{
|
||||
// Show transmitted command
|
||||
if (!quiet_output) {
|
||||
printf ("Sent bits: ");
|
||||
print_hex (pbtTx, szTx);
|
||||
}
|
||||
// Transmit the command bytes
|
||||
if (!nfc_initiator_transceive_bytes (pnd, pbtTx, szTx, abtRx, &szRx, NULL))
|
||||
return false;
|
||||
|
||||
// Show received answer
|
||||
if (!quiet_output) {
|
||||
printf ("Received bits: ");
|
||||
print_hex (abtRx, szRx);
|
||||
}
|
||||
// Succesful transfer
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
print_usage (char *argv[])
|
||||
{
|
||||
printf ("Usage: %s [OPTIONS] [UID]\n", argv[0]);
|
||||
printf ("Options:\n");
|
||||
printf ("\t-h\tHelp. Print this message.\n");
|
||||
printf ("\t-f\tFormat. Delete all data (set to 0xFF) and reset ACLs to default.\n");
|
||||
printf ("\t-q\tQuiet mode. Suppress output of READER and CARD data (improves timing).\n");
|
||||
printf ("\n\tSpecify UID (4 HEX bytes) to set UID, or leave blank for default '01234567'.\n");
|
||||
printf ("\tThis utility can be used to recover cards that have been damaged by writing bad\n");
|
||||
printf ("\tdata (e.g. wrong BCC), thus making them non-selectable by most tools/readers.\n");
|
||||
printf ("\n\t*** Note: this utility only works with special Mifare 1K cards (Chinese clones).\n\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int arg, i;
|
||||
bool format= false;
|
||||
unsigned int c;
|
||||
char tmp[3]= { 0x00, 0x00, 0x00 };
|
||||
|
||||
|
||||
// Get commandline options
|
||||
for (arg = 1; arg < argc; arg++) {
|
||||
if (0 == strcmp (argv[arg], "-h")) {
|
||||
print_usage (argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (0 == strcmp (argv[arg], "-f")) {
|
||||
format= true;
|
||||
} else if (0 == strcmp (argv[arg], "-q")) {
|
||||
quiet_output = true;
|
||||
} else if (strlen(argv[arg]) == 8) {
|
||||
for(i= 0 ; i < 4 ; ++i) {
|
||||
memcpy(tmp, argv[arg]+i*2, 2);
|
||||
sscanf(tmp, "%02x", &c);
|
||||
abtData[i]= (char) c;
|
||||
}
|
||||
abtData[4]= abtData[0] ^ abtData[1] ^ abtData[2] ^ abtData[3];
|
||||
iso14443a_crc_append (abtData, 16);
|
||||
} else {
|
||||
ERR ("%s is not supported option.", argv[arg]);
|
||||
print_usage (argv);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to open the NFC reader
|
||||
pnd = nfc_connect (NULL);
|
||||
|
||||
if (!pnd) {
|
||||
printf ("Error connecting NFC reader\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Initialise NFC device as "initiator"
|
||||
nfc_initiator_init (pnd);
|
||||
|
||||
// Configure the CRC
|
||||
if (!nfc_configure (pnd, NDO_HANDLE_CRC, false)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// Use raw send/receive methods
|
||||
if (!nfc_configure (pnd, NDO_EASY_FRAMING, false)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// Disable 14443-4 autoswitching
|
||||
if (!nfc_configure (pnd, NDO_AUTO_ISO14443_4, false)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf ("Connected to NFC reader: %s\n\n", pnd->acName);
|
||||
|
||||
// Send the 7 bits request command specified in ISO 14443A (0x26)
|
||||
if (!transmit_bits (abtReqa, 7)) {
|
||||
printf ("Error: No tag available\n");
|
||||
nfc_disconnect (pnd);
|
||||
return 1;
|
||||
}
|
||||
memcpy (abtAtqa, abtRx, 2);
|
||||
|
||||
// Anti-collision
|
||||
transmit_bytes (abtSelectAll, 2);
|
||||
|
||||
// Check answer
|
||||
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
|
||||
printf("WARNING: BCC check failed!\n");
|
||||
}
|
||||
|
||||
// Save the UID CL1
|
||||
memcpy (abtRawUid, abtRx, 4);
|
||||
|
||||
//Prepare and send CL1 Select-Command
|
||||
memcpy (abtSelectTag + 2, abtRx, 5);
|
||||
iso14443a_crc_append (abtSelectTag, 7);
|
||||
transmit_bytes (abtSelectTag, 9);
|
||||
abtSak = abtRx[0];
|
||||
|
||||
// Test if we are dealing with a CL2
|
||||
if (abtSak & CASCADE_BIT) {
|
||||
szCL = 2;//or more
|
||||
// Check answer
|
||||
if (abtRawUid[0] != 0x88) {
|
||||
printf("WARNING: Cascade bit set but CT != 0x88!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(szCL == 2) {
|
||||
// We have to do the anti-collision for cascade level 2
|
||||
|
||||
// Prepare CL2 commands
|
||||
abtSelectAll[0] = 0x95;
|
||||
|
||||
// Anti-collision
|
||||
transmit_bytes (abtSelectAll, 2);
|
||||
|
||||
// Check answer
|
||||
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
|
||||
printf("WARNING: BCC check failed!\n");
|
||||
}
|
||||
|
||||
// Save UID CL2
|
||||
memcpy (abtRawUid + 4, abtRx, 4);
|
||||
|
||||
// Selection
|
||||
abtSelectTag[0] = 0x95;
|
||||
memcpy (abtSelectTag + 2, abtRx, 5);
|
||||
iso14443a_crc_append (abtSelectTag, 7);
|
||||
transmit_bytes (abtSelectTag, 9);
|
||||
abtSak = abtRx[0];
|
||||
|
||||
// Test if we are dealing with a CL3
|
||||
if (abtSak & CASCADE_BIT) {
|
||||
szCL = 3;
|
||||
// Check answer
|
||||
if (abtRawUid[0] != 0x88) {
|
||||
printf("WARNING: Cascade bit set but CT != 0x88!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ( szCL == 3) {
|
||||
// We have to do the anti-collision for cascade level 3
|
||||
|
||||
// Prepare and send CL3 AC-Command
|
||||
abtSelectAll[0] = 0x97;
|
||||
transmit_bytes (abtSelectAll, 2);
|
||||
|
||||
// Check answer
|
||||
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
|
||||
printf("WARNING: BCC check failed!\n");
|
||||
}
|
||||
|
||||
// Save UID CL3
|
||||
memcpy (abtRawUid + 8, abtRx, 4);
|
||||
|
||||
// Prepare and send final Select-Command
|
||||
abtSelectTag[0] = 0x97;
|
||||
memcpy (abtSelectTag + 2, abtRx, 5);
|
||||
iso14443a_crc_append (abtSelectTag, 7);
|
||||
transmit_bytes (abtSelectTag, 9);
|
||||
abtSak = abtRx[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Request ATS, this only applies to tags that support ISO 14443A-4
|
||||
if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) {
|
||||
iso_ats_supported = true;
|
||||
}
|
||||
|
||||
printf ("\nFound tag with\n UID: ");
|
||||
switch (szCL) {
|
||||
case 1:
|
||||
printf ("%02x%02x%02x%02x", abtRawUid[0], abtRawUid[1], abtRawUid[2], abtRawUid[3]);
|
||||
break;
|
||||
case 2:
|
||||
printf ("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]);
|
||||
printf ("%02x%02x%02x%02x", abtRawUid[4], abtRawUid[5], abtRawUid[6], abtRawUid[7]);
|
||||
break;
|
||||
case 3:
|
||||
printf ("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]);
|
||||
printf ("%02x%02x%02x", abtRawUid[5], abtRawUid[6], abtRawUid[7]);
|
||||
printf ("%02x%02x%02x%02x", abtRawUid[8], abtRawUid[9], abtRawUid[10], abtRawUid[11]);
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
printf("ATQA: %02x%02x\n SAK: %02x\n", abtAtqa[1], abtAtqa[0], abtSak);
|
||||
if (szAts > 1) { // if = 1, it's not actual ATS but error code
|
||||
printf(" ATS: ");
|
||||
print_hex (abtAts, szAts);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// now reset UID
|
||||
iso14443a_crc_append(abtHalt, 2);
|
||||
transmit_bytes (abtHalt, 4);
|
||||
transmit_bits (abtUnlock1,7);
|
||||
if(format) {
|
||||
transmit_bytes (abtWipe,1);
|
||||
transmit_bytes (abtHalt, 4);
|
||||
transmit_bits (abtUnlock1,7);
|
||||
}
|
||||
transmit_bytes (abtUnlock2,1);
|
||||
transmit_bytes (abtWrite,4);
|
||||
transmit_bytes (abtData,18);
|
||||
if(format) {
|
||||
for(i= 3 ; i < 64 ; i += 4) {
|
||||
abtWrite[1]= (char) i;
|
||||
iso14443a_crc_append (abtWrite, 2);
|
||||
transmit_bytes (abtWrite,4);
|
||||
transmit_bytes (abtBlank,18);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nfc_disconnect (pnd);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
.TH NFC-MFULTRALIGHT 1 "Nov 02, 2009"
|
||||
.SH NAME
|
||||
nfc-mfultralight \- MIFARE Ultralight command line tool
|
||||
.SH SYNOPSIS
|
||||
.B nfc-mfultralight
|
||||
.RI \fR\fBr\fR|\fBw\fR
|
||||
.IR DUMP
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B nfc-mfultralight
|
||||
is a MIFARE Ultralight tool that allows to read or write
|
||||
a tag data to/from a
|
||||
.IR DUMP
|
||||
file.
|
||||
|
||||
MIFARE Ultralight tag is one of the most widely used RFID tags for ticketing application.
|
||||
It uses a binary Mifare Dump file (MFD) to store data for all sectors.
|
||||
|
||||
Be cautious that some parts of a Ultralight memory can be written only once
|
||||
and some parts are used as lock bits, so please read the tag documentation
|
||||
before experimenting too much!
|
||||
|
||||
.SH OPTIONS
|
||||
.BR r " | " w
|
||||
Perform read from (
|
||||
.B r
|
||||
) or write to (
|
||||
.B w
|
||||
) card.
|
||||
.TP
|
||||
.IR DUMP
|
||||
MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)
|
||||
|
||||
|
||||
.SH BUGS
|
||||
Please report any bugs on the
|
||||
.B libnfc
|
||||
forum at
|
||||
.BR http://www.libnfc.org/community/ "."
|
||||
.SH LICENCE
|
||||
.B libnfc
|
||||
and
|
||||
.B libnfc-examples
|
||||
are covered by the GNU Lesser General Public License (LGPL), version 3.
|
||||
.SH AUTHORS
|
||||
Roel Verdult <roel@libnfc.org>
|
||||
Romuald Conty <romuald@libnfc.org>
|
||||
.PP
|
||||
This manual page was written by Romuald Conty <romuald@libnfc.org>.
|
||||
It is licensed under the terms of the GNU GPL (version 2 or later).
|
||||
|
|
@ -1,268 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-mfultralight.c
|
||||
* @brief MIFARE Ultralight dump/restore tool
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "mifare.h"
|
||||
|
||||
static nfc_device_t *pnd;
|
||||
static nfc_target_t nt;
|
||||
static mifare_param mp;
|
||||
static mifareul_tag mtDump;
|
||||
static uint32_t uiBlocks = 0xF;
|
||||
|
||||
static const nfc_modulation_t nmMifare = {
|
||||
.nmt = NMT_ISO14443A,
|
||||
.nbr = NBR_106,
|
||||
};
|
||||
|
||||
static void
|
||||
print_success_or_failure (bool bFailure, uint32_t * uiCounter)
|
||||
{
|
||||
printf ("%c", (bFailure) ? 'x' : '.');
|
||||
if (uiCounter)
|
||||
*uiCounter += (bFailure) ? 0 : 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
read_card (void)
|
||||
{
|
||||
uint32_t page;
|
||||
bool bFailure = false;
|
||||
uint32_t uiReadedPages = 0;
|
||||
|
||||
printf ("Reading %d pages |", uiBlocks + 1);
|
||||
|
||||
for (page = 0; page <= uiBlocks; page += 4) {
|
||||
// Try to read out the data block
|
||||
if (nfc_initiator_mifare_cmd (pnd, MC_READ, page, &mp)) {
|
||||
memcpy (mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16);
|
||||
} else {
|
||||
bFailure = true;
|
||||
break;
|
||||
}
|
||||
|
||||
print_success_or_failure (bFailure, &uiReadedPages);
|
||||
print_success_or_failure (bFailure, &uiReadedPages);
|
||||
print_success_or_failure (bFailure, &uiReadedPages);
|
||||
print_success_or_failure (bFailure, &uiReadedPages);
|
||||
}
|
||||
printf ("|\n");
|
||||
printf ("Done, %d of %d pages readed.\n", uiReadedPages, uiBlocks + 1);
|
||||
fflush (stdout);
|
||||
|
||||
return (!bFailure);
|
||||
}
|
||||
|
||||
static bool
|
||||
write_card (void)
|
||||
{
|
||||
uint32_t uiBlock = 0;
|
||||
bool bFailure = false;
|
||||
uint32_t uiWritenPages = 0;
|
||||
uint32_t uiSkippedPages;
|
||||
|
||||
char buffer[BUFSIZ];
|
||||
bool write_otp;
|
||||
bool write_lock;
|
||||
|
||||
printf ("Write OTP bytes ? [yN] ");
|
||||
if (!fgets (buffer, BUFSIZ, stdin)) {
|
||||
ERR ("Unable to read standard input.");
|
||||
}
|
||||
write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
|
||||
printf ("Write Lock bytes ? [yN] ");
|
||||
if (!fgets (buffer, BUFSIZ, stdin)) {
|
||||
ERR ("Unable to read standard input.");
|
||||
}
|
||||
write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
|
||||
|
||||
printf ("Writing %d pages |", uiBlocks + 1);
|
||||
/* We need to skip 2 first pages. */
|
||||
printf ("ss");
|
||||
uiSkippedPages = 2;
|
||||
|
||||
for (int page = 0x2; page <= 0xF; page++) {
|
||||
if ((page==0x2) && (!write_lock)) {
|
||||
printf ("s");
|
||||
uiSkippedPages++;
|
||||
continue;
|
||||
}
|
||||
if ((page==0x3) && (!write_otp)) {
|
||||
printf ("s");
|
||||
uiSkippedPages++;
|
||||
continue;
|
||||
}
|
||||
// Show if the readout went well
|
||||
if (bFailure) {
|
||||
// When a failure occured we need to redo the anti-collision
|
||||
if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
|
||||
ERR ("tag was removed");
|
||||
return false;
|
||||
}
|
||||
bFailure = false;
|
||||
}
|
||||
// For the Mifare Ultralight, this write command can be used
|
||||
// in compatibility mode, which only actually writes the first
|
||||
// page (4 bytes). The Ultralight-specific Write command only
|
||||
// writes one page at a time.
|
||||
uiBlock = page / 4;
|
||||
memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData + ((page % 4) * 4), 16);
|
||||
if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, page, &mp))
|
||||
bFailure = true;
|
||||
|
||||
print_success_or_failure (bFailure, &uiWritenPages);
|
||||
}
|
||||
printf ("|\n");
|
||||
printf ("Done, %d of %d pages written (%d pages skipped).\n", uiWritenPages, uiBlocks + 1, uiSkippedPages);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
bool bReadAction;
|
||||
FILE *pfDump;
|
||||
|
||||
if (argc < 3) {
|
||||
printf ("\n");
|
||||
printf ("%s r|w <dump.mfd>\n", argv[0]);
|
||||
printf ("\n");
|
||||
printf ("r|w - Perform read from or write to card\n");
|
||||
printf ("<dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
|
||||
printf ("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DBG ("\nChecking arguments and settings\n");
|
||||
|
||||
bReadAction = tolower ((int) ((unsigned char) *(argv[1])) == 'r');
|
||||
|
||||
if (bReadAction) {
|
||||
memset (&mtDump, 0x00, sizeof (mtDump));
|
||||
} else {
|
||||
pfDump = fopen (argv[2], "rb");
|
||||
|
||||
if (pfDump == NULL) {
|
||||
ERR ("Could not open dump file: %s\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fread (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
|
||||
ERR ("Could not read from dump file: %s\n", argv[2]);
|
||||
fclose (pfDump);
|
||||
return 1;
|
||||
}
|
||||
fclose (pfDump);
|
||||
}
|
||||
DBG ("Successfully opened the dump file\n");
|
||||
|
||||
// Try to open the NFC device
|
||||
pnd = nfc_connect (NULL);
|
||||
if (pnd == NULL) {
|
||||
ERR ("Error connecting NFC device\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
nfc_initiator_init (pnd);
|
||||
|
||||
// Let the device only try once to find a tag
|
||||
if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf ("Connected to NFC device: %s\n", pnd->acName);
|
||||
|
||||
// Try to find a MIFARE Ultralight tag
|
||||
if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
|
||||
ERR ("no tag was found\n");
|
||||
nfc_disconnect (pnd);
|
||||
return 1;
|
||||
}
|
||||
// Test if we are dealing with a MIFARE compatible tag
|
||||
|
||||
if (nt.nti.nai.abtAtqa[1] != 0x44) {
|
||||
ERR ("tag is not a MIFARE Ultralight card\n");
|
||||
nfc_disconnect (pnd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Get the info from the current tag
|
||||
printf ("Found MIFARE Ultralight card with UID: ");
|
||||
size_t szPos;
|
||||
for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) {
|
||||
printf ("%02x", nt.nti.nai.abtUid[szPos]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (bReadAction) {
|
||||
if (read_card ()) {
|
||||
printf ("Writing data to file: %s ... ", argv[2]);
|
||||
fflush (stdout);
|
||||
pfDump = fopen (argv[2], "wb");
|
||||
if (pfDump == NULL) {
|
||||
printf ("Could not open file: %s\n", argv[2]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (fwrite (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
|
||||
printf ("Could not write to file: %s\n", argv[2]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fclose (pfDump);
|
||||
printf ("Done.\n");
|
||||
}
|
||||
} else {
|
||||
write_card ();
|
||||
}
|
||||
|
||||
nfc_disconnect (pnd);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
#include <nfc/nfc.h>
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
|
||||
#define MAX_DEVICE_COUNT 16
|
||||
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
.TH NFC-RELAY-PICC 1 "October 12, 2010"
|
||||
.SH NAME
|
||||
nfc-relay-picc \- Relay demonstration tool for ISO14443-4
|
||||
.SH SYNOPSIS
|
||||
.B nfc-relay-picc
|
||||
.SH DESCRIPTION
|
||||
.B nfc-relay-picc
|
||||
|
||||
This tool requires two NFC devices. One device (configured as target) will
|
||||
emulate an ISO/IEC 14443-4 type A tag, while the second device (configured as
|
||||
initiator) will act as a reader. The genuine tag can be placed on the second
|
||||
device (initiator) and the tag emulator (target) can be placed close to the
|
||||
original reader. All communication is now relayed and shown in the screen on
|
||||
real-time.
|
||||
|
||||
tag <---> initiator (relay) <---> target (relay) <---> original reader
|
||||
|
||||
.SH OPTIONS
|
||||
\fB-h\fP
|
||||
Help
|
||||
List options
|
||||
|
||||
\fB-q\fP
|
||||
Quiet mode
|
||||
Suppress printing of relayed data (improves timing)
|
||||
|
||||
\fB-t\fP
|
||||
Target mode only (to be used on reader side)
|
||||
Commands are sent to file descriptor 4
|
||||
Responses are read from file descriptor 3
|
||||
|
||||
\fB-i\fP
|
||||
Initiator mode only (to be used on tag side)
|
||||
Commands are read from file descriptor 3
|
||||
Responses are sent to file descriptor 4
|
||||
|
||||
\fB-n\fP \fIN\fP
|
||||
Adds a waiting time of \fIN\fP seconds (integer) in the loop
|
||||
|
||||
.SH EXAMPLES
|
||||
Basic usage:
|
||||
|
||||
\fBnfc-relay-picc\fP
|
||||
|
||||
Remote relay over TCP/IP:
|
||||
|
||||
\fBsocat\fP
|
||||
TCP-LISTEN:port,reuseaddr
|
||||
"EXEC:\fBnfc-relay-picc -i\fP,fdin=3,fdout=4"
|
||||
\fBsocat\fP
|
||||
TCP:remotehost:port
|
||||
"EXEC:\fBnfc-relay-picc -t\fP,fdin=3,fdout=4"
|
||||
|
||||
.SH NOTES
|
||||
There are some differences with \fBnfc-relay\fP:
|
||||
|
||||
This example only works with PN532 because it relies on
|
||||
its internal handling of ISO14443-4 specificities.
|
||||
|
||||
Thanks to this internal handling & injection of WTX frames,
|
||||
this example works on readers very strict on timing.
|
||||
|
||||
.SH BUGS
|
||||
Please report any bugs on the
|
||||
.B libnfc
|
||||
forum at
|
||||
.BR http://www.libnfc.org/community/ "."
|
||||
.SH LICENCE
|
||||
.B libnfc
|
||||
and
|
||||
.B libnfc-examples
|
||||
are covered by the GNU Lesser General Public License (LGPL), version 3.
|
||||
.PP
|
||||
This manual page is licensed under the terms of the GNU GPL (version 2 or later).
|
||||
|
|
@ -1,461 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2010, Romuald Conty
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-relay-picc.c
|
||||
* @brief Relay example using two PN532 devices.
|
||||
*/
|
||||
|
||||
// Notes & differences with nfc-relay:
|
||||
// - This example only works with PN532 because it relies on
|
||||
// its internal handling of ISO14443-4 specificities.
|
||||
// - Thanks to this internal handling & injection of WTX frames,
|
||||
// this example works on readers very strict on timing
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
#define MAX_DEVICE_COUNT 2
|
||||
|
||||
static byte_t abtCapdu[MAX_FRAME_LEN];
|
||||
static size_t szCapduLen;
|
||||
static byte_t abtRapdu[MAX_FRAME_LEN];
|
||||
static size_t szRapduLen;
|
||||
static nfc_device_t *pndInitiator;
|
||||
static nfc_device_t *pndTarget;
|
||||
static bool quitting = false;
|
||||
static bool quiet_output = false;
|
||||
static bool initiator_only_mode = false;
|
||||
static bool target_only_mode = false;
|
||||
static int waiting_time = 0;
|
||||
FILE * fd3;
|
||||
FILE * fd4;
|
||||
|
||||
void
|
||||
intr_hdlr (void)
|
||||
{
|
||||
printf ("\nQuitting...\n");
|
||||
printf ("Please send a last command to the emulator to quit properly.\n");
|
||||
quitting = true;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
print_usage (char *argv[])
|
||||
{
|
||||
printf ("Usage: %s [OPTIONS]\n", argv[0]);
|
||||
printf ("Options:\n");
|
||||
printf ("\t-h\tHelp. Print this message.\n");
|
||||
printf ("\t-q\tQuiet mode. Suppress printing of relayed data (improves timing).\n");
|
||||
printf ("\t-t\tTarget mode only (the one on reader side). Data expected from FD3 to FD4.\n");
|
||||
printf ("\t-i\tInitiator mode only (the one on tag side). Data expected from FD3 to FD4.\n");
|
||||
printf ("\t-n N\tAdds a waiting time of N seconds (integer) in the relay to mimic long distance.\n");
|
||||
}
|
||||
|
||||
bool print_hex_fd4 (const byte_t * pbtData, const size_t szBytes, const char * pchPrefix)
|
||||
{
|
||||
size_t szPos;
|
||||
if (szBytes > MAX_FRAME_LEN) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (fprintf (fd4, "#%s %04zx: ", pchPrefix, szBytes)<0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (szPos = 0; szPos < szBytes; szPos++) {
|
||||
if (fprintf (fd4, "%02x ", pbtData[szPos])<0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
if (fprintf (fd4, "\n")<0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fflush(fd4);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
bool scan_hex_fd3 (byte_t *pbtData, size_t *pszBytes, const char * pchPrefix)
|
||||
{
|
||||
size_t szPos;
|
||||
unsigned int uiBytes;
|
||||
unsigned int uiData;
|
||||
char pchScan[256];
|
||||
int c;
|
||||
// Look for our next sync marker
|
||||
while ( (c=fgetc(fd3)) != '#') {
|
||||
if (c == EOF) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
strncpy(pchScan, pchPrefix, 250);
|
||||
strcat(pchScan, " %04x:");
|
||||
if (fscanf (fd3, pchScan, &uiBytes)<1) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
*pszBytes=uiBytes;
|
||||
if (*pszBytes > MAX_FRAME_LEN) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (szPos = 0; szPos < *pszBytes; szPos++) {
|
||||
if (fscanf (fd3, "%02x", &uiData)<1) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pbtData[szPos]=uiData;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int arg;
|
||||
size_t szFound;
|
||||
nfc_device_desc_t *pnddDevices;
|
||||
const char *acLibnfcVersion = nfc_version ();
|
||||
nfc_target_t ntRealTarget;
|
||||
|
||||
// Get commandline options
|
||||
for (arg = 1; arg < argc; arg++) {
|
||||
if (0 == strcmp (argv[arg], "-h")) {
|
||||
print_usage (argv);
|
||||
return EXIT_SUCCESS;
|
||||
} else if (0 == strcmp (argv[arg], "-q")) {
|
||||
quiet_output = true;
|
||||
} else if (0 == strcmp (argv[arg], "-t")) {
|
||||
printf ("INFO: %s\n", "Target mode only.");
|
||||
initiator_only_mode = false;
|
||||
target_only_mode = true;
|
||||
} else if (0 == strcmp (argv[arg], "-i")) {
|
||||
printf ("INFO: %s\n", "Initiator mode only.");
|
||||
initiator_only_mode = true;
|
||||
target_only_mode = false;
|
||||
} else if (0 == strcmp (argv[arg], "-n")) {
|
||||
if (++arg==argc || (sscanf(argv[arg], "%i", &waiting_time)<1)) {
|
||||
ERR ("Missing or wrong waiting time value: %s.", argv[arg]);
|
||||
print_usage (argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf ("Waiting time: %i secs.\n", waiting_time);
|
||||
} else {
|
||||
ERR ("%s is not supported option.", argv[arg]);
|
||||
print_usage (argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Display libnfc version
|
||||
printf ("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
|
||||
|
||||
#ifdef WIN32
|
||||
signal (SIGINT, (void (__cdecl *) (int)) intr_hdlr);
|
||||
#else
|
||||
signal (SIGINT, (void (*)()) intr_hdlr);
|
||||
#endif
|
||||
|
||||
// Allocate memory to put the result of available devices listing
|
||||
if (!(pnddDevices = malloc (MAX_DEVICE_COUNT * sizeof (*pnddDevices)))) {
|
||||
fprintf (stderr, "malloc() failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// List available devices
|
||||
nfc_list_devices (pnddDevices, MAX_DEVICE_COUNT, &szFound);
|
||||
|
||||
if (initiator_only_mode || target_only_mode) {
|
||||
if (szFound < 1) {
|
||||
ERR ("No device found");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fd3 = fdopen(3, "r");
|
||||
fd4 = fdopen(4, "w");
|
||||
}
|
||||
else {
|
||||
if (szFound < 2) {
|
||||
ERR ("%zd device found but two connected devices are needed to relay NFC.", szFound);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!target_only_mode) {
|
||||
// Try to open the NFC reader used as initiator
|
||||
// Little hack to allow using initiator no matter if
|
||||
// there is already a target used locally or not on the same machine:
|
||||
// if there is more than one readers connected we connect to the second reader
|
||||
// (we hope they're always detected in the same order)
|
||||
if (szFound == 1) {
|
||||
pndInitiator = nfc_connect (&(pnddDevices[0]));
|
||||
} else {
|
||||
pndInitiator = nfc_connect (&(pnddDevices[1]));
|
||||
}
|
||||
|
||||
if (!pndInitiator) {
|
||||
printf ("Error connecting NFC reader\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf ("Connected to the NFC reader device: %s\n", pndInitiator->acName);
|
||||
|
||||
if (!nfc_initiator_init (pndInitiator)) {
|
||||
printf ("Error: fail initializing initiator\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Try to find a ISO 14443-4A tag
|
||||
nfc_modulation_t nm = {
|
||||
.nmt = NMT_ISO14443A,
|
||||
.nbr = NBR_106,
|
||||
};
|
||||
if (!nfc_initiator_select_passive_target (pndInitiator, nm, NULL, 0, &ntRealTarget)) {
|
||||
printf ("Error: no tag was found\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Found tag:\n");
|
||||
print_nfc_iso14443a_info (ntRealTarget.nti.nai, false);
|
||||
if (initiator_only_mode) {
|
||||
if (print_hex_fd4(ntRealTarget.nti.nai.abtUid, ntRealTarget.nti.nai.szUidLen, "UID") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while printing UID to FD4\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (print_hex_fd4(ntRealTarget.nti.nai.abtAtqa, 2, "ATQA") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while printing ATQA to FD4\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (print_hex_fd4(&(ntRealTarget.nti.nai.btSak), 1, "SAK") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while printing SAK to FD4\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (print_hex_fd4(ntRealTarget.nti.nai.abtAts, ntRealTarget.nti.nai.szAtsLen, "ATS") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while printing ATS to FD4\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (initiator_only_mode) {
|
||||
printf ("Hint: tag <---> *INITIATOR* (relay) <-FD3/FD4-> target (relay) <---> original reader\n\n");
|
||||
} else if (target_only_mode) {
|
||||
printf ("Hint: tag <---> initiator (relay) <-FD3/FD4-> *TARGET* (relay) <---> original reader\n\n");
|
||||
} else {
|
||||
printf ("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n");
|
||||
}
|
||||
if (!initiator_only_mode) {
|
||||
nfc_target_t ntEmulatedTarget = {
|
||||
.nm = {
|
||||
.nmt = NMT_ISO14443A,
|
||||
.nbr = NBR_106,
|
||||
},
|
||||
};
|
||||
if (target_only_mode) {
|
||||
size_t foo;
|
||||
if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtUid, &(ntEmulatedTarget.nti.nai.szUidLen), "UID") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while scanning UID from FD3\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAtqa, &foo, "ATQA") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while scanning ATQA from FD3\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (scan_hex_fd3(&(ntEmulatedTarget.nti.nai.btSak), &foo, "SAK") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while scanning SAK from FD3\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAts, &(ntEmulatedTarget.nti.nai.szAtsLen), "ATS") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while scanning ATS from FD3\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
ntEmulatedTarget.nti = ntRealTarget.nti;
|
||||
}
|
||||
// We can only emulate a short UID, so fix length & ATQA bit:
|
||||
ntEmulatedTarget.nti.nai.szUidLen = 4;
|
||||
ntEmulatedTarget.nti.nai.abtAtqa[1] &= (0xFF-0x40);
|
||||
// First byte of UID is always automatically replaced by 0x08 in this mode anyway
|
||||
ntEmulatedTarget.nti.nai.abtUid[0] = 0x08;
|
||||
// ATS is always automatically replaced by PN532, we've no control on it:
|
||||
// ATS = (05) 75 33 92 03
|
||||
// (TL) T0 TA TB TC
|
||||
// | | | +-- CID supported, NAD supported
|
||||
// | | +----- FWI=9 SFGI=2 => FWT=154ms, SFGT=1.21ms
|
||||
// | +-------- DR=2,4 DS=2,4 => supports 106, 212 & 424bps in both directions
|
||||
// +----------- TA,TB,TC, FSCI=5 => FSC=64
|
||||
// It seems hazardous to tell we support NAD if the tag doesn't support NAD but I don't know how to disable it
|
||||
// PC/SC pseudo-ATR = 3B 80 80 01 01 if there is no historical bytes
|
||||
|
||||
// Creates ATS and copy max 48 bytes of Tk:
|
||||
byte_t * pbtTk;
|
||||
size_t szTk;
|
||||
pbtTk = iso14443a_locate_historical_bytes (ntEmulatedTarget.nti.nai.abtAts, ntEmulatedTarget.nti.nai.szAtsLen, &szTk);
|
||||
szTk = (szTk > 48) ? 48 : szTk;
|
||||
byte_t pbtTkt[48];
|
||||
memcpy(pbtTkt, pbtTk, szTk);
|
||||
ntEmulatedTarget.nti.nai.abtAts[0] = 0x75;
|
||||
ntEmulatedTarget.nti.nai.abtAts[1] = 0x33;
|
||||
ntEmulatedTarget.nti.nai.abtAts[2] = 0x92;
|
||||
ntEmulatedTarget.nti.nai.abtAts[3] = 0x03;
|
||||
ntEmulatedTarget.nti.nai.szAtsLen = 4 + szTk;
|
||||
memcpy(&(ntEmulatedTarget.nti.nai.abtAts[4]), pbtTkt, szTk);
|
||||
|
||||
printf("We will emulate:\n");
|
||||
print_nfc_iso14443a_info (ntEmulatedTarget.nti.nai, false);
|
||||
|
||||
// Try to open the NFC emulator device
|
||||
pndTarget = nfc_connect (&(pnddDevices[0]));
|
||||
if (pndTarget == NULL) {
|
||||
printf ("Error connecting NFC emulator device\n");
|
||||
if (!target_only_mode) {
|
||||
nfc_disconnect (pndInitiator);
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf ("Connected to the NFC emulator device: %s\n", pndTarget->acName);
|
||||
|
||||
if (!nfc_target_init (pndTarget, &ntEmulatedTarget, abtCapdu, &szCapduLen)) {
|
||||
ERR ("%s", "Initialization of NFC emulator failed");
|
||||
if (!target_only_mode) {
|
||||
nfc_disconnect (pndInitiator);
|
||||
}
|
||||
nfc_disconnect (pndTarget);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf ("%s\n", "Done, relaying frames now!");
|
||||
}
|
||||
|
||||
|
||||
while (!quitting) {
|
||||
bool ret;
|
||||
if (!initiator_only_mode) {
|
||||
// Receive external reader command through target
|
||||
if (!nfc_target_receive_bytes(pndTarget,abtCapdu,&szCapduLen, NULL)) {
|
||||
nfc_perror (pndTarget, "nfc_target_receive_bytes");
|
||||
if (!target_only_mode) {
|
||||
nfc_disconnect (pndInitiator);
|
||||
}
|
||||
nfc_disconnect (pndTarget);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (target_only_mode) {
|
||||
if (print_hex_fd4(abtCapdu, szCapduLen, "C-APDU") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while printing C-APDU to FD4\n");
|
||||
nfc_disconnect (pndTarget);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (scan_hex_fd3(abtCapdu, &szCapduLen, "C-APDU") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while scanning C-APDU from FD3\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
// Show transmitted response
|
||||
if (!quiet_output) {
|
||||
printf ("Forwarding C-APDU: ");
|
||||
print_hex (abtCapdu, szCapduLen);
|
||||
}
|
||||
|
||||
if (!target_only_mode) {
|
||||
// Forward the frame to the original tag
|
||||
ret = nfc_initiator_transceive_bytes
|
||||
(pndInitiator, abtCapdu, szCapduLen, abtRapdu, &szRapduLen, NULL);
|
||||
} else {
|
||||
if (scan_hex_fd3(abtRapdu, &szRapduLen, "R-APDU") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while scanning R-APDU from FD3\n");
|
||||
nfc_disconnect (pndTarget);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
if (ret) {
|
||||
// Redirect the answer back to the external reader
|
||||
if (waiting_time > 0) {
|
||||
if (!quiet_output) {
|
||||
printf ("Waiting %is to simulate longer relay...\n", waiting_time);
|
||||
}
|
||||
sleep(waiting_time);
|
||||
}
|
||||
// Show transmitted response
|
||||
if (!quiet_output) {
|
||||
printf ("Forwarding R-APDU: ");
|
||||
print_hex (abtRapdu, szRapduLen);
|
||||
}
|
||||
if (!initiator_only_mode) {
|
||||
// Transmit the response bytes
|
||||
if (!nfc_target_send_bytes(pndTarget, abtRapdu, szRapduLen, NULL)) {
|
||||
nfc_perror (pndTarget, "nfc_target_send_bytes");
|
||||
if (!target_only_mode) {
|
||||
nfc_disconnect (pndInitiator);
|
||||
}
|
||||
if (!initiator_only_mode) {
|
||||
nfc_disconnect (pndTarget);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (print_hex_fd4(abtRapdu, szRapduLen, "R-APDU") != EXIT_SUCCESS) {
|
||||
fprintf (stderr, "Error while printing R-APDU to FD4\n");
|
||||
nfc_disconnect (pndInitiator);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!target_only_mode) {
|
||||
nfc_disconnect (pndInitiator);
|
||||
}
|
||||
if (!initiator_only_mode) {
|
||||
nfc_disconnect (pndTarget);
|
||||
}
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
#define MAX_DEVICE_COUNT 2
|
||||
|
|
|
|||
|
|
@ -1,777 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
static const byte_t OddParity[256] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
|
||||
};
|
||||
|
||||
byte_t
|
||||
oddparity (const byte_t bt)
|
||||
{
|
||||
return OddParity[bt];
|
||||
}
|
||||
|
||||
void
|
||||
oddparity_bytes_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar)
|
||||
{
|
||||
size_t szByteNr;
|
||||
// Calculate the parity bits for the command
|
||||
for (szByteNr = 0; szByteNr < szLen; szByteNr++) {
|
||||
pbtPar[szByteNr] = OddParity[pbtData[szByteNr]];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_hex (const byte_t * pbtData, const size_t szBytes)
|
||||
{
|
||||
size_t szPos;
|
||||
|
||||
for (szPos = 0; szPos < szBytes; szPos++) {
|
||||
printf ("%02x ", pbtData[szPos]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void
|
||||
print_hex_bits (const byte_t * pbtData, const size_t szBits)
|
||||
{
|
||||
uint8_t uRemainder;
|
||||
size_t szPos;
|
||||
size_t szBytes = szBits / 8;
|
||||
|
||||
for (szPos = 0; szPos < szBytes; szPos++) {
|
||||
printf ("%02x ", pbtData[szPos]);
|
||||
}
|
||||
|
||||
uRemainder = szBits % 8;
|
||||
// Print the rest bits
|
||||
if (uRemainder != 0) {
|
||||
if (uRemainder < 5)
|
||||
printf ("%01x (%d bits)", pbtData[szBytes], uRemainder);
|
||||
else
|
||||
printf ("%02x (%d bits)", pbtData[szBytes], uRemainder);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void
|
||||
print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar)
|
||||
{
|
||||
uint8_t uRemainder;
|
||||
size_t szPos;
|
||||
size_t szBytes = szBits / 8;
|
||||
|
||||
for (szPos = 0; szPos < szBytes; szPos++) {
|
||||
printf ("%02x", pbtData[szPos]);
|
||||
if (OddParity[pbtData[szPos]] != pbtDataPar[szPos]) {
|
||||
printf ("! ");
|
||||
} else {
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
|
||||
uRemainder = szBits % 8;
|
||||
// Print the rest bits, these cannot have parity bit
|
||||
if (uRemainder != 0) {
|
||||
if (uRemainder < 5)
|
||||
printf ("%01x (%d bits)", pbtData[szBytes], uRemainder);
|
||||
else
|
||||
printf ("%02x (%d bits)", pbtData[szBytes], uRemainder);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
#define SAK_UID_NOT_COMPLETE 0x04
|
||||
#define SAK_ISO14443_4_COMPLIANT 0x20
|
||||
#define SAK_ISO18092_COMPLIANT 0x40
|
||||
|
||||
void
|
||||
print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose)
|
||||
{
|
||||
printf (" ATQA (SENS_RES): ");
|
||||
print_hex (nai.abtAtqa, 2);
|
||||
if (verbose) {
|
||||
printf("* UID size: ");
|
||||
switch ((nai.abtAtqa[1] & 0xc0)>>6) {
|
||||
case 0:
|
||||
printf("single\n");
|
||||
break;
|
||||
case 1:
|
||||
printf("double\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("triple\n");
|
||||
break;
|
||||
case 3:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf("* bit frame anticollision ");
|
||||
switch (nai.abtAtqa[1] & 0x1f) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x04:
|
||||
case 0x08:
|
||||
case 0x10:
|
||||
printf("supported\n");
|
||||
break;
|
||||
default:
|
||||
printf("not supported\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf (" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
|
||||
print_hex (nai.abtUid, nai.szUidLen);
|
||||
if (verbose) {
|
||||
if (nai.abtUid[0] == 0x08) {
|
||||
printf ("* Random UID\n");
|
||||
}
|
||||
}
|
||||
printf (" SAK (SEL_RES): ");
|
||||
print_hex (&nai.btSak, 1);
|
||||
if (verbose) {
|
||||
if (nai.btSak & SAK_UID_NOT_COMPLETE) {
|
||||
printf ("* Warning! Cascade bit set: UID not complete\n");
|
||||
}
|
||||
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
|
||||
printf ("* Compliant with ISO/IEC 14443-4\n");
|
||||
} else {
|
||||
printf ("* Not compliant with ISO/IEC 14443-4\n");
|
||||
}
|
||||
if (nai.btSak & SAK_ISO18092_COMPLIANT) {
|
||||
printf ("* Compliant with ISO/IEC 18092\n");
|
||||
} else {
|
||||
printf ("* Not compliant with ISO/IEC 18092\n");
|
||||
}
|
||||
}
|
||||
if (nai.szAtsLen) {
|
||||
printf (" ATS: ");
|
||||
print_hex (nai.abtAts, nai.szAtsLen);
|
||||
}
|
||||
if (nai.szAtsLen && verbose) {
|
||||
// Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
|
||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||
printf ("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
|
||||
|
||||
size_t offset = 1;
|
||||
if (nai.abtAts[0] & 0x10) { // TA(1) present
|
||||
byte_t TA = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf ("* Bit Rate Capability:\n");
|
||||
if (TA == 0) {
|
||||
printf (" * PICC supports only 106 kbits/s in both directions\n");
|
||||
}
|
||||
if (TA & 1<<7) {
|
||||
printf (" * Same bitrate in both directions mandatory\n");
|
||||
}
|
||||
if (TA & 1<<4) {
|
||||
printf (" * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<5) {
|
||||
printf (" * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<6) {
|
||||
printf (" * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<0) {
|
||||
printf (" * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<1) {
|
||||
printf (" * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<2) {
|
||||
printf (" * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<3) {
|
||||
printf (" * ERROR unknown value\n");
|
||||
}
|
||||
}
|
||||
if (nai.abtAts[0] & 0x20) { // TB(1) present
|
||||
byte_t TB= nai.abtAts[offset];
|
||||
offset++;
|
||||
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((TB & 0xf0) >> 4))/13560.0);
|
||||
if ((TB & 0x0f) == 0) {
|
||||
printf ("* No Start-up Frame Guard Time required\n");
|
||||
} else {
|
||||
printf ("* Start-up Frame Guard Time: %.4g ms\n",256.0*16.0*(1<<(TB & 0x0f))/13560.0);
|
||||
}
|
||||
}
|
||||
if (nai.abtAts[0] & 0x40) { // TC(1) present
|
||||
byte_t TC = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (TC & 0x1) {
|
||||
printf("* Node ADdress supported\n");
|
||||
} else {
|
||||
printf("* Node ADdress not supported\n");
|
||||
}
|
||||
if (TC & 0x2) {
|
||||
printf("* Card IDentifier supported\n");
|
||||
} else {
|
||||
printf("* Card IDentifier not supported\n");
|
||||
}
|
||||
}
|
||||
if (nai.szAtsLen > offset) {
|
||||
printf ("* Historical bytes Tk: " );
|
||||
print_hex (nai.abtAts + offset, (nai.szAtsLen - offset));
|
||||
byte_t CIB = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
|
||||
printf(" * Proprietary format\n");
|
||||
if (CIB == 0xc1) {
|
||||
printf(" * Tag byte: Mifare or virtual cards of various types\n");
|
||||
byte_t L = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (L != (nai.szAtsLen - offset)) {
|
||||
printf(" * Warning: Type Identification Coding length (%i)", L);
|
||||
printf(" not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
|
||||
}
|
||||
if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
|
||||
byte_t CTC = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Chip Type: ");
|
||||
switch (CTC & 0xf0) {
|
||||
case 0x00:
|
||||
printf("(Multiple) Virtual Cards\n");
|
||||
break;
|
||||
case 0x10:
|
||||
printf("Mifare DESFire\n");
|
||||
break;
|
||||
case 0x20:
|
||||
printf("Mifare Plus\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf(" * Memory size: ");
|
||||
switch (CTC & 0x0f) {
|
||||
case 0x00:
|
||||
printf("<1 kbyte\n");
|
||||
break;
|
||||
case 0x01:
|
||||
printf("1 kbyte\n");
|
||||
break;
|
||||
case 0x02:
|
||||
printf("2 kbyte\n");
|
||||
break;
|
||||
case 0x03:
|
||||
printf("4 kbyte\n");
|
||||
break;
|
||||
case 0x04:
|
||||
printf("8 kbyte\n");
|
||||
break;
|
||||
case 0x0f:
|
||||
printf("Unspecified\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
|
||||
byte_t CVC = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Chip Status: ");
|
||||
switch (CVC & 0xf0) {
|
||||
case 0x00:
|
||||
printf("Engineering sample\n");
|
||||
break;
|
||||
case 0x20:
|
||||
printf("Released\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf(" * Chip Generation: ");
|
||||
switch (CVC & 0x0f) {
|
||||
case 0x00:
|
||||
printf("Generation 1\n");
|
||||
break;
|
||||
case 0x01:
|
||||
printf("Generation 2\n");
|
||||
break;
|
||||
case 0x02:
|
||||
printf("Generation 3\n");
|
||||
break;
|
||||
case 0x0f:
|
||||
printf("Unspecified\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
|
||||
byte_t VCS = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Specifics (Virtual Card Selection):\n");
|
||||
if ((VCS & 0x09) == 0x00) {
|
||||
printf(" * Only VCSL supported\n");
|
||||
} else if ((VCS & 0x09) == 0x01) {
|
||||
printf(" * VCS, VCSL and SVC supported\n");
|
||||
}
|
||||
if ((VCS & 0x0e) == 0x00) {
|
||||
printf(" * SL1, SL2(?), SL3 supported\n");
|
||||
} else if ((VCS & 0x0e) == 0x02) {
|
||||
printf(" * SL3 only card\n");
|
||||
} else if ((VCS & 0x0f) == 0x0e) {
|
||||
printf(" * No VCS command supported\n");
|
||||
} else if ((VCS & 0x0f) == 0x0f) {
|
||||
printf(" * Unspecified\n");
|
||||
} else {
|
||||
printf(" * RFU\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (CIB == 0x00) {
|
||||
printf(" * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n");
|
||||
printf(" followed by a mandatory status indicator (the last three bytes, not in TLV)\n");
|
||||
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
|
||||
}
|
||||
if (CIB == 0x10) {
|
||||
printf(" * DIR data reference: %02x\n", nai.abtAts[offset]);
|
||||
}
|
||||
if (CIB == 0x80) {
|
||||
if (nai.szAtsLen == offset) {
|
||||
printf(" * No COMPACT-TLV objects found, no status found\n");
|
||||
} else {
|
||||
printf(" * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n");
|
||||
printf(" the last data object may carry a status indicator of one, two or three bytes.\n");
|
||||
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
printf("Fingerprinting based on ATQA & SAK values:\n");
|
||||
uint32_t atqasak = 0;
|
||||
atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff)<<16);
|
||||
atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff)<<8);
|
||||
atqasak += ((uint32_t)nai.btSak & 0xff);
|
||||
bool found_possible_match = false;
|
||||
switch (atqasak) {
|
||||
case 0x000218:
|
||||
printf("* Mifare Classic 4K\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000408:
|
||||
printf("* Mifare Classic 1K\n");
|
||||
printf("* Mifare Plus (4-byte UID) 2K SL1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000409:
|
||||
printf("* Mifare MINI\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000410:
|
||||
printf("* Mifare Plus (4-byte UID) 2K SL2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000411:
|
||||
printf("* Mifare Plus (4-byte UID) 4K SL2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000418:
|
||||
printf("* Mifare Plus (4-byte UID) 4K SL1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000420:
|
||||
printf("* Mifare Plus (4-byte UID) 2K/4K SL3\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004400:
|
||||
printf("* Mifare Ultralight\n");
|
||||
printf("* Mifare UltralightC\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004208:
|
||||
case 0x004408:
|
||||
printf("* Mifare Plus (7-byte UID) 2K SL1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004218:
|
||||
case 0x004418:
|
||||
printf("* Mifare Plus (7-byte UID) 4K SL1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004210:
|
||||
case 0x004410:
|
||||
printf("* Mifare Plus (7-byte UID) 2K SL2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004211:
|
||||
case 0x004411:
|
||||
printf("* Mifare Plus (7-byte UID) 4K SL2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004220:
|
||||
case 0x004420:
|
||||
printf("* Mifare Plus (7-byte UID) 2K/4K SL3\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x034420:
|
||||
printf("* Mifare DESFire / Desfire EV1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Other matches not described in
|
||||
// AN MIFARE Type Identification Procedure
|
||||
// but seen in the field:
|
||||
switch (atqasak) {
|
||||
case 0x000488:
|
||||
printf("* Mifare Classic 1K Infineon\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000298:
|
||||
printf("* Gemplus MPCOS\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x030428:
|
||||
printf("* JCOP31\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004820:
|
||||
printf("* JCOP31 v2.4.1\n");
|
||||
printf("* JCOP31 v2.2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000428:
|
||||
printf("* JCOP31 v2.3.1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000453:
|
||||
printf("* Fudan FM1208SH01\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000820:
|
||||
printf("* Fudan FM1208\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000238:
|
||||
printf("* MFC 4K emulated by Nokia 6212 Classic\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000838:
|
||||
printf("* MFC 4K emulated by Nokia 6131 NFC\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
}
|
||||
if ((nai.abtAtqa[0] & 0xf0) == 0) {
|
||||
switch (nai.abtAtqa[1]) {
|
||||
case 0x02:
|
||||
printf("* SmartMX with Mifare 4K emulation\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x04:
|
||||
printf("* SmartMX with Mifare 1K emulation\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x48:
|
||||
printf("* SmartMX with 7-byte UID\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! found_possible_match) {
|
||||
printf("* Unknown card, sorry\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf (" ID (NFCID2): ");
|
||||
print_hex (nfi.abtId, 8);
|
||||
printf (" Parameter (PAD): ");
|
||||
print_hex (nfi.abtPad, 8);
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf (" ATQA (SENS_RES): ");
|
||||
print_hex (nji.btSensRes, 2);
|
||||
printf (" 4-LSB JEWELID: ");
|
||||
print_hex (nji.btId, 4);
|
||||
}
|
||||
|
||||
#define PI_ISO14443_4_SUPPORTED 0x01
|
||||
#define PI_NAD_SUPPORTED 0x01
|
||||
#define PI_CID_SUPPORTED 0x02
|
||||
void
|
||||
print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose)
|
||||
{
|
||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||
printf (" PUPI: ");
|
||||
print_hex (nbi.abtPupi, 4);
|
||||
printf (" Application Data: ");
|
||||
print_hex (nbi.abtApplicationData, 4);
|
||||
printf (" Protocol Info: ");
|
||||
print_hex (nbi.abtProtocolInfo, 3);
|
||||
if (verbose) {
|
||||
printf ("* Bit Rate Capability:\n");
|
||||
if (nbi.abtProtocolInfo[0] == 0) {
|
||||
printf (" * PICC supports only 106 kbits/s in both directions\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<7) {
|
||||
printf (" * Same bitrate in both directions mandatory\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<4) {
|
||||
printf (" * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<5) {
|
||||
printf (" * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<6) {
|
||||
printf (" * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<0) {
|
||||
printf (" * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<1) {
|
||||
printf (" * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<2) {
|
||||
printf (" * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<3) {
|
||||
printf (" * ERROR unknown value\n");
|
||||
}
|
||||
if( (nbi.abtProtocolInfo[1] & 0xf0) <= 0x80 ) {
|
||||
printf ("* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]);
|
||||
}
|
||||
if((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) {
|
||||
printf ("* Protocol types supported: ISO/IEC 14443-4\n");
|
||||
}
|
||||
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((nbi.abtProtocolInfo[2] & 0xf0) >> 4))/13560.0);
|
||||
if((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED|PI_CID_SUPPORTED)) != 0) {
|
||||
printf ("* Frame options supported: ");
|
||||
if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) printf ("NAD ");
|
||||
if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) printf ("CID ");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_iso14443bi_info (const nfc_iso14443bi_info_t nii, bool verbose)
|
||||
{
|
||||
printf (" DIV: ");
|
||||
print_hex (nii.abtDIV, 4);
|
||||
if (verbose) {
|
||||
int version = (nii.btVerLog & 0x1e)>>1;
|
||||
printf (" Software Version: ");
|
||||
if (version == 15) {
|
||||
printf ("Undefined\n");
|
||||
} else {
|
||||
printf ("%i\n", version);
|
||||
}
|
||||
|
||||
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x80)){
|
||||
printf (" Wait Enable: yes");
|
||||
}
|
||||
}
|
||||
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x40)) {
|
||||
printf (" ATS: ");
|
||||
print_hex (nii.abtAtr, nii.szAtrLen);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_iso14443b2sr_info (const nfc_iso14443b2sr_info_t nsi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf (" UID: ");
|
||||
print_hex (nsi.abtUID, 8);
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_iso14443b2ct_info (const nfc_iso14443b2ct_info_t nci, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
uint32_t uid;
|
||||
uid = (nci.abtUID[3] << 24) + (nci.abtUID[2] << 16) + (nci.abtUID[1] << 8) + nci.abtUID[0];
|
||||
printf (" UID: ");
|
||||
print_hex (nci.abtUID, sizeof(nci.abtUID));
|
||||
printf (" UID (decimal): %010u\n", uid);
|
||||
printf (" Product Code: %02X\n", nci.btProdCode);
|
||||
printf (" Fab Code: %02X\n", nci.btFabCode);
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf (" NFCID3: ");
|
||||
print_hex (ndi.abtNFCID3, 10);
|
||||
printf (" BS: %02x\n", ndi.btBS);
|
||||
printf (" BR: %02x\n", ndi.btBR);
|
||||
printf (" TO: %02x\n", ndi.btTO);
|
||||
printf (" PP: %02x\n", ndi.btPP);
|
||||
if (ndi.szGB) {
|
||||
printf ("General Bytes: ");
|
||||
print_hex (ndi.abtGB, ndi.szGB);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to parse arguments to find device descriptions.
|
||||
* @return Returns the list of found device descriptions.
|
||||
*/
|
||||
nfc_device_desc_t *
|
||||
parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose)
|
||||
{
|
||||
nfc_device_desc_t *pndd = 0;
|
||||
int arg;
|
||||
*szFound = 0;
|
||||
|
||||
// Get commandline options
|
||||
for (arg = 1; arg < argc; arg++) {
|
||||
|
||||
if (0 == strcmp (argv[arg], "--device")) {
|
||||
// FIXME: this device selection by command line options is terrible & does not support USB/PCSC drivers
|
||||
if (argc > arg + 1) {
|
||||
char buffer[256];
|
||||
|
||||
pndd = malloc (sizeof (nfc_device_desc_t));
|
||||
|
||||
strncpy (buffer, argv[++arg], 256);
|
||||
|
||||
// Driver.
|
||||
pndd->pcDriver = (char *) malloc (256);
|
||||
strcpy (pndd->pcDriver, strtok (buffer, ":"));
|
||||
|
||||
// Port.
|
||||
strcpy (pndd->acPort, strtok (NULL, ":"));
|
||||
|
||||
// Speed.
|
||||
sscanf (strtok (NULL, ":"), "%u", &pndd->uiSpeed);
|
||||
|
||||
*szFound = 1;
|
||||
} else {
|
||||
errx (1, "usage: %s [--device driver:port:speed]", argv[0]);
|
||||
}
|
||||
}
|
||||
if ((0 == strcmp (argv[arg], "-v")) || (0 == strcmp (argv[arg], "--verbose"))) {
|
||||
*verbose = true;
|
||||
}
|
||||
}
|
||||
return pndd;
|
||||
}
|
||||
|
||||
const char *
|
||||
str_nfc_baud_rate (const nfc_baud_rate_t nbr)
|
||||
{
|
||||
switch(nbr) {
|
||||
case NBR_UNDEFINED:
|
||||
return "undefined baud rate";
|
||||
break;
|
||||
case NBR_106:
|
||||
return "106 kbps";
|
||||
break;
|
||||
case NBR_212:
|
||||
return "212 kbps";
|
||||
break;
|
||||
case NBR_424:
|
||||
return "424 kbps";
|
||||
break;
|
||||
case NBR_847:
|
||||
return "847 kbps";
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_target (const nfc_target_t nt, bool verbose)
|
||||
{
|
||||
switch(nt.nm.nmt) {
|
||||
case NMT_ISO14443A:
|
||||
printf ("ISO/IEC 14443A (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_iso14443a_info (nt.nti.nai, verbose);
|
||||
break;
|
||||
case NMT_JEWEL:
|
||||
printf ("Innovision Jewel (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_jewel_info (nt.nti.nji, verbose);
|
||||
break;
|
||||
case NMT_FELICA:
|
||||
printf ("FeliCa (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_felica_info (nt.nti.nfi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B:
|
||||
printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_iso14443b_info (nt.nti.nbi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443BI:
|
||||
printf ("ISO/IEC 14443-4B' (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_iso14443bi_info (nt.nti.nii, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B2SR:
|
||||
printf ("ISO/IEC 14443-2B ST SRx (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_iso14443b2sr_info (nt.nti.nsi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B2CT:
|
||||
printf ("ISO/IEC 14443-2B ASK CTx (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_iso14443b2ct_info (nt.nti.nci, verbose);
|
||||
break;
|
||||
case NMT_DEP:
|
||||
printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_dep_info (nt.nti.ndi, verbose);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-utils.h
|
||||
* @brief Provide some examples shared functions like print, parity calculation, options parsing.
|
||||
*/
|
||||
|
||||
#ifndef _EXAMPLES_NFC_UTILS_H_
|
||||
# define _EXAMPLES_NFC_UTILS_H_
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <err.h>
|
||||
|
||||
/**
|
||||
* @macro DBG
|
||||
* @brief Print a message of standard output only in DEBUG mode
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
# define DBG(...) do { \
|
||||
warnx ("DBG %s:%d", __FILE__, __LINE__); \
|
||||
warnx (" " __VA_ARGS__ ); \
|
||||
} while (0)
|
||||
#else
|
||||
# define DBG(...) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @macro WARN
|
||||
* @brief Print a warn message
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
# define WARN(...) do { \
|
||||
warnx ("WARNING %s:%d", __FILE__, __LINE__); \
|
||||
warnx (" " __VA_ARGS__ ); \
|
||||
} while (0)
|
||||
#else
|
||||
# define WARN(...) warnx ("WARNING: " __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @macro ERR
|
||||
* @brief Print a error message
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
# define ERR(...) do { \
|
||||
warnx ("ERROR %s:%d", __FILE__, __LINE__); \
|
||||
warnx (" " __VA_ARGS__ ); \
|
||||
} while (0)
|
||||
#else
|
||||
# define ERR(...) warnx ("ERROR: " __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
byte_t oddparity (const byte_t bt);
|
||||
void oddparity_byte_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar);
|
||||
|
||||
void print_hex (const byte_t * pbtData, const size_t szLen);
|
||||
void print_hex_bits (const byte_t * pbtData, const size_t szBits);
|
||||
void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar);
|
||||
|
||||
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose);
|
||||
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose);
|
||||
void print_nfc_iso14443bi_info (const nfc_iso14443bi_info_t nii, bool verbose);
|
||||
void print_nfc_iso14443b2sr_info (const nfc_iso14443b2sr_info_t nsi, bool verbose);
|
||||
void print_nfc_iso14443b2ct_info (const nfc_iso14443b2ct_info_t nci, bool verbose);
|
||||
void print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose);
|
||||
void print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose);
|
||||
void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose);
|
||||
|
||||
void print_nfc_target (const nfc_target_t nt, bool verbose);
|
||||
|
||||
nfc_device_desc_t *parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose);
|
||||
|
||||
#endif
|
||||
|
|
@ -44,8 +44,8 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "chips/pn53x.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
#include "libnfc/chips/pn53x.h"
|
||||
|
||||
#define MAX_DEVICE_COUNT 16
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
#include "chips/pn53x.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
#include "libnfc/chips/pn53x.h"
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
#define TIMEOUT 60 // secs.
|
||||
|
|
|
|||
|
|
@ -64,9 +64,8 @@
|
|||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
#include "chips/pn53x.h"
|
||||
#include "utils/nfc-utils.h"
|
||||
#include "libnfc/chips/pn53x.h"
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue