Rearrange source code.

This commit is contained in:
Romain Tartiere 2010-04-07 14:37:19 +00:00
parent be1639b452
commit c7d77d7664
59 changed files with 43 additions and 107 deletions

20
examples/CMakeLists.txt Normal file
View file

@ -0,0 +1,20 @@
SET(EXAMPLES-SOURCES nfc-list nfc-mfclassic nfc-mfultralight nfcip-initiator nfcip-target nfc-anticol nfc-emulate nfc-relay)
# 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})
# Examples
FOREACH(source ${EXAMPLES-SOURCES})
ADD_EXECUTABLE(${source} ${source}.c)
TARGET_LINK_LIBRARIES(${source} nfc)
INSTALL(TARGETS ${source} RUNTIME DESTINATION bin COMPONENT examples)
ENDFOREACH(source)
IF(NOT MSVC)
# Manuals for the examples
FILE(GLOB manuals "${CMAKE_CURRENT_SOURCE_DIR}/*.1")
INSTALL(FILES ${manuals} DESTINATION ${SHARE_INSTALL_PREFIX}/man/man1 COMPONENT manuals)
ENDIF(NOT MSVC)

37
examples/Makefile.am Normal file
View file

@ -0,0 +1,37 @@
bin_PROGRAMS = nfc-anticol nfc-list nfc-mfclassic nfc-mfultralight nfc-relay nfc-emulate nfcip-target nfcip-initiator
# set the include path found by configure
INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
nfcinclude_HEADERS = mifaretag.h mifareultag.h
nfcincludedir = $(includedir)/nfc
AM_CFLAGS = -I$(top_srcdir)/libnfc
nfc_anticol_SOURCES = nfc-anticol.c
nfc_anticol_LDADD = $(top_builddir)/libnfc/libnfc.la
nfc_list_SOURCES = nfc-list.c
nfc_list_LDADD = $(top_builddir)/libnfc/libnfc.la
nfc_mfultralight_SOURCES = nfc-mfultralight.c mifareultag.h
nfc_mfultralight_LDADD = $(top_builddir)/libnfc/libnfc.la
nfc_mfclassic_SOURCES = nfc-mfclassic.c mifaretag.h
nfc_mfclassic_LDADD = $(top_builddir)/libnfc/libnfc.la
nfc_relay_SOURCES = nfc-relay.c
nfc_relay_LDADD = $(top_builddir)/libnfc/libnfc.la
nfc_emulate_SOURCES = nfc-emulate.c
nfc_emulate_LDADD = $(top_builddir)/libnfc/libnfc.la
nfcip_target_SOURCES = nfcip-target.c
nfcip_target_LDADD = $(top_builddir)/libnfc/libnfc.la
nfcip_initiator_SOURCES = nfcip-initiator.c
nfcip_initiator_LDADD = $(top_builddir)/libnfc/libnfc.la
dist_man_MANS = nfc-anticol.1 nfc-emulate.1 nfc-list.1 nfc-mfclassic.1 nfc-mfultralight.1 nfc-relay.1
EXTRA_DIST = CMakeLists.txt

View file

@ -0,0 +1,58 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <stdlib.h>
#include <nfc/nfc.h>
int main(int argc, const char* argv[])
{
nfc_device_t* pnd;
nfc_target_info_t nti;
// Display libnfc version
const char* acLibnfcVersion = nfc_version();
printf("%s use libnfc %s\n", argv[0], acLibnfcVersion);
// Connect using the first available NFC device
pnd = nfc_connect(NULL);
if (pnd == NULL) {
printf("Unable to connect to NFC device.");
return EXIT_FAILURE;
}
// Set connected NFC device to initiator mode
nfc_initiator_init(pnd);
// Drop the field for a while
nfc_configure(pnd,NDO_ACTIVATE_FIELD,false);
// Let the reader only try once to find a tag
nfc_configure(pnd,NDO_INFINITE_SELECT,false);
// Configure the CRC and Parity settings
nfc_configure(pnd,NDO_HANDLE_CRC,true);
nfc_configure(pnd,NDO_HANDLE_PARITY,true);
// Enable field so more power consuming cards can power themselves up
nfc_configure(pnd,NDO_ACTIVATE_FIELD,true);
printf("Connected to NFC reader: %s\n",pnd->acName);
// Poll for a ISO14443A (MIFARE) tag
if (nfc_initiator_select_tag(pnd,NM_ISO14443A_106,NULL,0,&nti)) {
printf("The following (NFC) ISO14443A tag was found:\n");
printf(" ATQA (SENS_RES): "); print_hex(nti.nai.abtAtqa,2);
printf(" UID (NFCID%c): ",(nti.nai.abtUid[0]==0x08?'3':'1')); print_hex(nti.nai.abtUid,nti.nai.szUidLen);
printf(" SAK (SEL_RES): "); print_hex(&nti.nai.btSak,1);
if (nti.nai.szAtsLen) {
printf(" ATS (ATR): ");
print_hex(nti.nai.abtAts,nti.nai.szAtsLen);
}
}
// Disconnect from NFC device
nfc_disconnect(pnd);
return EXIT_SUCCESS;
}

55
examples/mifaretag.h Normal file
View file

@ -0,0 +1,55 @@
/**
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*
* @file mifaretag.h
* @brief
*/
#ifndef _LIBNFC_MIFARE_TAG_H_
#define _LIBNFC_MIFARE_TAG_H_
typedef struct {
byte_t abtUID[4];
byte_t btBCC;
byte_t btUnknown;
byte_t abtATQA[2];
byte_t abtUnknown[8];
} mifare_block_manufacturer;
typedef struct {
byte_t abtData[16];
} mifare_block_data;
typedef struct {
byte_t abtKeyA[6];
byte_t abtAccessBits[4];
byte_t abtKeyB[6];
} mifare_block_trailer;
typedef union {
mifare_block_manufacturer mbm;
mifare_block_data mbd;
mifare_block_trailer mbt;
} mifare_block;
typedef struct {
mifare_block amb[256];
} mifare_tag;
#endif // _LIBNFC_MIFARE_TAG_H_

50
examples/mifareultag.h Normal file
View file

@ -0,0 +1,50 @@
/**
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*
* @file mifareultag.h
* @brief
*/
#ifndef _LIBNFC_MIFARE_UL_TAG_H_
#define _LIBNFC_MIFARE_UL_TAG_H_
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;
#endif // _LIBNFC_MIFARE_UL_TAG_H_

30
examples/nfc-anticol.1 Normal file
View file

@ -0,0 +1,30 @@
.TH NFC-ANTICOL 1 "June 26, 2009"
.SH NAME
nfc-anticol \- Demonstration NFC anti-collison command line tool based on libnfc
.SH SYNOPSIS
.B nfc-anticol
.SH DESCRIPTION
.B nfc-anticol
is an anti-collision demonstration tool for ISO/IEC 14443-A tags, performed
by custom constructed frames. The first frame must be a short frame which
is only 7 bits long. Commercial SDK's often don't support a feature to send
frames that are not a multiple of 8 bits (1 byte) long.
This makes it impossible to do the anti-collision yourself.
The developer has to rely on closed proprietary software and should hope it does not contain vulnerabilities during the anti-collision phase.
Performing the anti-collision using custom frames could protect against a malicious tag that, for example, violates the standard by sending frames with unsupported lengths.
.SH BUGS
Please report any bugs on the
.B libnfc
forum at
.BR http://www.libnfc.org/community/ "."
.SH LICENCE
.B libnfc
and
.B nfc-tools
are covered by the GNU Lesser General Public License (LGPL), version 3.
.SH AUTHORS
Roel Verdult <roel@libnfc.org>
.PP
This manual page was written by Romuald Conty <romuald.conty@free.fr>.
It is licensed under the terms of the GNU GPL (version 2 or later).

210
examples/nfc-anticol.c Normal file
View file

@ -0,0 +1,210 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file nfc-anticol.c
* @brief
*/
#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/nfc-messages.h>
#include "bitutils.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 szRxLen;
static byte_t abtUid[10];
static size_t szUidLen = 4;
static nfc_device_t* pnd;
bool quiet_output = 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,0xbc,0xa5 };
byte_t abtHalt [4] = { 0x50,0x00,0x57,0xcd };
bool transmit_bits(const byte_t* pbtTx, const size_t szTxBits)
{
// Show transmitted command
if(!quiet_output)
{
printf("R: ");
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("T: ");
print_hex_bits(abtRx,szRxBits);
}
// Succesful transfer
return true;
}
bool transmit_bytes(const byte_t* pbtTx, const size_t szTxLen)
{
// Show transmitted command
if(!quiet_output)
{
printf("R: ");
print_hex(pbtTx,szTxLen);
}
// Transmit the command bytes
if (!nfc_initiator_transceive_bytes(pnd,pbtTx,szTxLen,abtRx,&szRxLen)) return false;
// Show received answer
if(!quiet_output)
{
printf("T: ");
print_hex(abtRx,szRxLen);
}
// Succesful transfer
return true;
}
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 output of READER and EMULATOR data (improves timing).\n");
}
int main(int argc,char* argv[])
{
int arg;
// Get commandline options
for (arg=1;arg<argc;arg++) {
if (0 == strcmp(argv[arg], "-h")) {
print_usage(argv);
return 0;
} else if (0 == strcmp(argv[arg], "-q")) {
INFO("%s", "Quiet mode.");
quiet_output = true;
} else {
ERR("%s is not supported option.", argv[arg]);
print_usage(argv);
return -1;
}
}
// Try to open the NFC reader
pnd = nfc_connect(NULL);
if (!pnd)
{
printf("Error connecting NFC reader\n");
return 1;
}
nfc_initiator_init(pnd);
// Drop the field for a while
nfc_configure(pnd,NDO_ACTIVATE_FIELD,false);
// Configure the CRC and Parity settings
nfc_configure(pnd,NDO_HANDLE_CRC,false);
nfc_configure(pnd,NDO_HANDLE_PARITY,true);
// Enable field so more power consuming cards can power themselves up
nfc_configure(pnd,NDO_ACTIVATE_FIELD,true);
printf("\nConnected 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;
}
// Anti-collision
transmit_bytes(abtSelectAll,2);
// Save the UID
memcpy(abtUid,abtRx,4);
memcpy(abtSelectTag+2,abtRx,5);
append_iso14443a_crc(abtSelectTag,7);
transmit_bytes(abtSelectTag,9);
// Test if we are dealing with a 4 bytes uid
if (abtUid[0]!= 0x88)
{
szUidLen = 4;
} else {
// We have to do the anti-collision for cascade level 2
abtSelectAll[0] = 0x95;
abtSelectTag[0] = 0x95;
// Anti-collision
transmit_bytes(abtSelectAll,2);
// Save the UID
memcpy(abtUid+4,abtRx,4);
memcpy(abtSelectTag+2,abtRx,5);
append_iso14443a_crc(abtSelectTag,7);
transmit_bytes(abtSelectTag,9);
szUidLen = 7;
}
// Request ATS, this only applies to tags that support ISO 14443A-4
if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) transmit_bytes(abtRats,4);
// Done, halt the tag now
transmit_bytes(abtHalt,4);
printf("\nFound tag with UID: ");
if (szUidLen == 4)
{
printf("%08x\n",swap_endian32(abtUid));
} else {
printf("%014llx\n",swap_endian64(abtUid)&0x00ffffffffffffffull);
}
nfc_disconnect(pnd);
return 0;
}

37
examples/nfc-emulate.1 Normal file
View file

@ -0,0 +1,37 @@
.TH NFC-EMULATE 1 "June 26, 2009"
.SH NAME
nfc-emulate \- NFC target emulation command line tool based on libnfc
.SH SYNOPSIS
.B nfc-emulate
.RI [ UID ]
.SH DESCRIPTION
.B nfc-emulate
is an tag emulatation tool. Tag emulation is one of the main added features in NFC.
To avoid abuse of existing systems, manufacturers of the NFC controller intentionally did not
support emulation of custom UID numbers.
The emulate tool demonstrates that this can still be done using transmission of raw-frames,
and the desired UID can be optionally specified.
Fast communication is necessary to respond in time during the anti-collision protocol.
Using the USB interface gives some timing issues but an embedded microprocessor could
be fast enough to emulate a tag with any UID. This makes it a serious thread
for security systems that rely only on the uniqueness of the UID.
.SH OPTIONS
.IR UID
8 hex digits format that represents desired UID (default is DEADBEAF).
.SH BUGS
Please report any bugs on the
.B libnfc
forum at
.BR http://www.libnfc.org/community/ "."
.SH LICENCE
.B libnfc
and
.B nfc-tools
are covered by the GNU Lesser General Public License (LGPL), version 3.
.SH AUTHORS
Roel Verdult <roel@libnfc.org>
.PP
This manual page was written by Romuald Conty <romuald.conty@free.fr>.
It is licensed under the terms of the GNU GPL (version 2 or later).

172
examples/nfc-emulate.c Normal file
View file

@ -0,0 +1,172 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file nfc-emulate.c
* @brief
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <nfc/nfc.h>
#include <nfc/nfc-messages.h>
#include "bitutils.h"
#define MAX_FRAME_LEN 264
static byte_t abtRecv[MAX_FRAME_LEN];
static size_t szRecvBits;
static nfc_device_t* pnd;
// ISO14443A Anti-Collision response
byte_t abtAtqa [2] = { 0x04,0x00 };
byte_t abtUidBcc [5] = { 0xDE,0xAD,0xBE,0xAF,0x62 };
byte_t abtSak [9] = { 0x08,0xb6,0xdd };
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-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n");
printf("\n");
printf("\t[UID]\tUID to emulate, specified as 8 HEX digits (default is DEADBEAF).\n");
}
int main(int argc, char *argv[])
{
byte_t* pbtTx = NULL;
size_t szTxBits;
bool quiet_output = false;
int arg, i;
// Get commandline options
for (arg=1;arg<argc;arg++) {
if (0 == strcmp(argv[arg], "-h")) {
print_usage(argv);
return 0;
} else if (0 == strcmp(argv[arg], "-q")) {
INFO("%s", "Quiet mode.");
quiet_output = true;
} else if((arg == argc-1) && (strlen(argv[arg]) == 8)) { // See if UID was specified as HEX string
byte_t abtTmp[3] = { 0x00,0x00,0x00 };
printf("[+] Using UID: %s\n",argv[arg]);
abtUidBcc[4]= 0x00;
for(i= 0; i < 4; ++i)
{
memcpy(abtTmp,argv[arg]+i*2,2);
abtUidBcc[i]= (byte_t) strtol((char*)abtTmp,NULL,16);
abtUidBcc[4] ^= abtUidBcc[i];
}
} else {
ERR("%s is not supported option.", argv[arg]);
print_usage(argv);
return -1;
}
}
// Try to open the NFC reader
pnd = nfc_connect(NULL);
if (pnd == NULL)
{
printf("Error connecting NFC reader\n");
return 1;
}
printf("\n");
printf("[+] Connected to NFC reader: %s\n",pnd->acName);
printf("[+] Try to break out the auto-emulation, this requires a second reader!\n");
printf("[+] To do this, please send any command after the anti-collision\n");
printf("[+] For example, send a RATS command or use the \"nfc-anticol\" tool\n");
if (!nfc_target_init(pnd,abtRecv,&szRecvBits))
{
printf("Error: Could not come out of auto-emulation, no command was received\n");
return 1;
}
printf("[+] Received initiator command: ");
print_hex_bits(abtRecv,szRecvBits);
printf("[+] Configuring communication\n");
nfc_configure(pnd,NDO_HANDLE_CRC,false);
nfc_configure(pnd,NDO_HANDLE_PARITY,true);
printf("[+] Done, the emulated tag is initialized with UID: %02X%02X%02X%02X\n\n",abtUidBcc[0],abtUidBcc[1],abtUidBcc[2],abtUidBcc[3]);
while(true)
{
// Test if we received a frame
if (nfc_target_receive_bits(pnd,abtRecv,&szRecvBits,NULL))
{
// Prepare the command to send back for the anti-collision request
switch(szRecvBits)
{
case 7: // Request or Wakeup
pbtTx = abtAtqa;
szTxBits = 16;
// New anti-collsion session started
if (!quiet_output) printf("\n");
break;
case 16: // Select All
pbtTx = abtUidBcc;
szTxBits = 40;
break;
case 72: // Select Tag
pbtTx = abtSak;
szTxBits = 24;
break;
default: // unknown length?
szTxBits = 0;
break;
}
if(!quiet_output)
{
printf("R: ");
print_hex_bits(abtRecv,szRecvBits);
}
// Test if we know how to respond
if(szTxBits)
{
// Send and print the command to the screen
nfc_target_send_bits(pnd,pbtTx,szTxBits,NULL);
if(!quiet_output)
{
printf("T: ");
print_hex_bits(pbtTx,szTxBits);
}
}
}
}
nfc_disconnect(pnd);
}

27
examples/nfc-list.1 Normal file
View file

@ -0,0 +1,27 @@
.TH NFC-LIST 1 "June 26, 2009"
.SH NAME
nfc-list \- List NFC targets command line tool based on libnfc
.SH SYNOPSIS
.B nfc-list
.SH DESCRIPTION
.B nfc-list
utility attempts to select available tags in the field. The NFC
controller is used to perform the selection procedure. This is different for each modulation type.
It tries to find a ISO/IEC 14443 type A, type B, Felica or Jewel Topaz tags.
This tool demonstrates that it is possible to setup a simple NFC system using less than 10 lines of code.
.SH BUGS
Please report any bugs on the
.B libnfc
forum at
.BR http://www.libnfc.org/community/ "."
.SH LICENCE
.B libnfc
and
.B nfc-tools
are covered by the GNU Lesser General Public License (LGPL), version 3.
.SH AUTHORS
Roel Verdult <roel@libnfc.org>
.PP
This manual page was written by Romuald Conty <romuald.conty@free.fr>.
It is licensed under the terms of the GNU GPL (version 2 or later).

170
examples/nfc-list.c Normal file
View file

@ -0,0 +1,170 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file nfc-list.c
* @brief
*/
#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 <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <nfc/nfc.h>
#include <nfc/nfc-messages.h>
#include "bitutils.h"
#define MAX_DEVICE_COUNT 16
static nfc_device_t* pnd;
static byte_t abtFelica[5] = { 0x00, 0xff, 0xff, 0x00, 0x00 };
int main(int argc, const char* argv[])
{
size_t szFound;
size_t i;
nfc_target_info_t nti;
nfc_device_desc_t *pnddDevices;
// Display libnfc version
const char* acLibnfcVersion = nfc_version();
printf("%s use libnfc %s\n", argv[0], acLibnfcVersion);
#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 (!(pnddDevices = malloc (MAX_DEVICE_COUNT * sizeof (*pnddDevices))))
{
fprintf (stderr, "malloc() failed\n");
return EXIT_FAILURE;
}
nfc_list_devices (pnddDevices, MAX_DEVICE_COUNT, &szFound);
if (szFound == 0)
{
INFO("%s", "No device found.");
}
for (i = 0; i < szFound; i++)
{
pnd = nfc_connect(&(pnddDevices[i]));
if (pnd == NULL)
{
ERR("%s", "Unable to connect to NFC device.");
return 1;
}
nfc_initiator_init(pnd);
// Drop the field for a while
nfc_configure(pnd,NDO_ACTIVATE_FIELD,false);
// Let the reader only try once to find a tag
nfc_configure(pnd,NDO_INFINITE_SELECT,false);
// Configure the CRC and Parity settings
nfc_configure(pnd,NDO_HANDLE_CRC,true);
nfc_configure(pnd,NDO_HANDLE_PARITY,true);
// Enable field so more power consuming cards can power themselves up
nfc_configure(pnd,NDO_ACTIVATE_FIELD,true);
printf("\nConnected to NFC reader: %s\n\n",pnd->acName);
// Poll for a ISO14443A (MIFARE) tag
if (nfc_initiator_select_tag(pnd,NM_ISO14443A_106,NULL,0,&nti))
{
printf("The following (NFC) ISO14443A tag was found:\n\n");
printf(" ATQA (SENS_RES): "); print_hex(nti.nai.abtAtqa,2);
printf(" UID (NFCID%c): ",(nti.nai.abtUid[0]==0x08?'3':'1')); print_hex(nti.nai.abtUid,nti.nai.szUidLen);
printf(" SAK (SEL_RES): "); print_hex(&nti.nai.btSak,1);
if (nti.nai.szAtsLen)
{
printf(" ATS (ATR): ");
print_hex(nti.nai.abtAts,nti.nai.szAtsLen);
}
}
// Poll for a Felica tag
if (nfc_initiator_select_tag(pnd,NM_FELICA_212,abtFelica,5,&nti) || nfc_initiator_select_tag(pnd,NM_FELICA_424,abtFelica,5,&nti))
{
printf("The following (NFC) Felica tag was found:\n\n");
printf("%18s","ID (NFCID2): "); print_hex(nti.nfi.abtId,8);
printf("%18s","Parameter (PAD): "); print_hex(nti.nfi.abtPad,8);
}
// Poll for a ISO14443B tag
if (nfc_initiator_select_tag(pnd,NM_ISO14443B_106,(byte_t*)"\x00",1,&nti))
{
printf("The following (NFC) ISO14443-B tag was found:\n\n");
printf(" ATQB: "); print_hex(nti.nbi.abtAtqb,12);
printf(" ID: "); print_hex(nti.nbi.abtId,4);
printf(" CID: %02x\n",nti.nbi.btCid);
if (nti.nbi.szInfLen>0)
{
printf(" INF: "); print_hex(nti.nbi.abtInf,nti.nbi.szInfLen);
}
printf("PARAMS: %02x %02x %02x %02x\n",nti.nbi.btParam1,nti.nbi.btParam2,nti.nbi.btParam3,nti.nbi.btParam4);
}
// Poll for a Jewel tag
if (nfc_initiator_select_tag(pnd,NM_JEWEL_106,NULL,0,&nti))
{
// No test results yet
printf("jewel\n");
}
nfc_disconnect(pnd);
}
free (pnddDevices);
return 0;
}

57
examples/nfc-mfclassic.1 Normal file
View file

@ -0,0 +1,57 @@
.TH NFC-MFCLASSIC 1 "Nov 02, 2009"
.SH NAME
nfc-mfclassic \- MIFARE Classic command line tool based on libnfc
.SH SYNOPSIS
.B nfc-mfclassic
.RI \fR\fBr\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 provide 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 demonstrate the speed of this library and its easy-of-use.
It 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.
.SH OPTIONS
.BR r " | " w
Perform read from (
.B r
) or 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 contain the keys (optional)
.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>
.PP
This manual page was written by Romuald Conty <romuald.conty@free.fr>.
It is licensed under the terms of the GNU GPL (version 2 or later).

542
examples/nfc-mfclassic.c Normal file
View file

@ -0,0 +1,542 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @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 "mifaretag.h"
#include "bitutils.h"
static nfc_device_t* pnd;
static nfc_target_info_t nti;
static mifare_param mp;
static mifare_tag mtKeys;
static mifare_tag mtDump;
static bool bUseKeyA;
static bool bUseKeyFile;
static uint32_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
};
static size_t num_keys = sizeof(keys) / 6;
void print_success_or_failure(bool bFailure, uint32_t* uiBlockCounter)
{
printf("%c",(bFailure)?'x':'.');
if (uiBlockCounter)
*uiBlockCounter += (bFailure)?0:4;
}
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);
}
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);
}
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;
}
bool authenticate(uint32_t uiBlock)
{
mifare_cmd mc;
uint32_t uiTrailerBlock;
size_t key_index;
// Key file authentication.
if (bUseKeyFile)
{
// Set the authentication information (uid)
memcpy(mp.mpa.abtUid,nti.nai.abtUid,4);
// Locate the trailer (with the keys) used for this sector
uiTrailerBlock = get_trailer_block(uiBlock);
// Determin if we should use the a or the b key
if (bUseKeyA)
{
mc = MC_AUTH_A;
memcpy(mp.mpa.abtKey,mtKeys.amb[uiTrailerBlock].mbt.abtKeyA,6);
} else {
mc = MC_AUTH_B;
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;
}
// Auto authentication.
else
{
// Determin if we should use the a or the b key
mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B;
// Set the authentication information (uid)
memcpy(mp.mpa.abtUid,nti.nai.abtUid,4);
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))
{
/**
* @note: what about the other key?
*/
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_tag(pnd, NM_ISO14443A_106, mp.mpa.abtUid, 4, NULL);
}
}
return false;
}
bool read_card()
{
int32_t iBlock;
bool bFailure = false;
uint32_t uiReadBlocks = 0;
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_tag(pnd,NM_ISO14443A_106,NULL,0,&nti))
{
printf("!\nError: tag was removed\n");
return 1;
}
bFailure = false;
}
fflush(stdout);
// Try to authenticate for the current sector
if (!authenticate(iBlock))
{
printf("!\nError: authentication failed for block %02x\n",iBlock);
return false;
}
// Try to read out the trailer
if (nfc_initiator_mifare_cmd(pnd,MC_READ,iBlock,&mp))
{
// 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 {
// 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;
}
}
}
}
print_success_or_failure(bFailure, &uiReadBlocks);
printf("|\n");
printf("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks+1);
fflush(stdout);
return true;
}
bool write_card()
{
uint32_t uiBlock;
bool bFailure = false;
uint32_t uiWriteBlocks = 0;
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 != uiBlocks)
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_tag(pnd,NM_ISO14443A_106,NULL,0,&nti))
{
printf("!\nError: tag was removed\n");
return false;
}
bFailure = false;
}
fflush(stdout);
// Try to authenticate for the current sector
if (!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) 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);
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;
}
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;
void print_usage(const char* pcProgramName)
{
printf("Usage: ");
printf("%s r|w a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
printf(" r|w - Perform read from (r) or write to (w) card\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[])
{
bool b4K;
action_t atAction = ACTION_USAGE;
byte_t* pbtUID;
FILE* pfKeys = NULL;
FILE* pfDump = NULL;
const char* command = argv[1];
if(argc < 2)
{
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
if(strcmp(command, "r") == 0)
{
atAction = ACTION_READ;
bUseKeyA = tolower((int)((unsigned char)*(argv[2]))) == 'a';
bUseKeyFile = (argc > 4);
} else if(strcmp(command, "w") == 0)
{
atAction = ACTION_WRITE;
bUseKeyA = tolower((int)((unsigned char)*(argv[2]))) == 'a';
bUseKeyFile = (argc > 4);
} else if(strcmp(command, "x") == 0)
{
atAction = ACTION_EXTRACT;
}
switch(atAction) {
case ACTION_USAGE:
print_usage(argv[0]);
exit(EXIT_FAILURE);
break;
case ACTION_READ:
case ACTION_WRITE:
if (argc < 4)
{
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
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);
// Drop the field for a while
nfc_configure(pnd,NDO_ACTIVATE_FIELD,false);
// Let the reader only try once to find a tag
nfc_configure(pnd,NDO_INFINITE_SELECT,false);
nfc_configure(pnd,NDO_HANDLE_CRC,true);
nfc_configure(pnd,NDO_HANDLE_PARITY,true);
// Enable field so more power consuming cards can power themselves up
nfc_configure(pnd,NDO_ACTIVATE_FIELD,true);
printf("Connected to NFC reader: %s\n",pnd->acName);
// Try to find a MIFARE Classic tag
if (!nfc_initiator_select_tag(pnd,NM_ISO14443A_106,NULL,0,&nti))
{
printf("Error: no tag was found\n");
nfc_disconnect(pnd);
exit(EXIT_FAILURE);
}
// Test if we are dealing with a MIFARE compatible tag
if ((nti.nai.btSak & 0x08) == 0)
{
printf("Error: tag is not a MIFARE Classic card\n");
nfc_disconnect(pnd);
exit(EXIT_FAILURE);
}
if (bUseKeyFile)
{
// Get the info from the key dump
b4K = (mtKeys.amb[0].mbm.abtATQA[1] == 0x02);
pbtUID = mtKeys.amb[0].mbm.abtUID;
// Compare if key dump UID is the same as the current tag UID
if (memcmp(nti.nai.abtUid,pbtUID,4) != 0)
{
printf("Expected MIFARE Classic %cK card with UID: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
}
}
// Get the info from the current tag
pbtUID = nti.nai.abtUid;
b4K = (nti.nai.abtAtqa[1] == 0x02);
printf("Found MIFARE Classic %cK card with UID: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
uiBlocks = (b4K)?0xff:0x3f;
if (atAction == ACTION_READ)
{
if (read_card())
{
printf("Writing data to file: %s ... ",argv[3]);
fflush(stdout);
pfDump = fopen(argv[3],"wb");
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 {
write_card();
}
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 (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);
}

View file

@ -0,0 +1,44 @@
.TH NFC-MFULTRALIGHT 1 "Nov 02, 2009"
.SH NAME
nfc-mfultralight \- MIFARE Ultralight command line tool based on libnfc
.SH SYNOPSIS
.B nfc-mfultralight
.RI \fR\fBr\fR|\fBw\fR
.IR DUMP
.SH DESCRIPTION
.B nfc-mfultralight
is a MIFARE Ultralight tool that allow to read or write
.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.
.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>
.PP
This manual page was written by Romuald Conty <romuald.conty@free.fr>.
It is licensed under the terms of the GNU GPL (version 2 or later).

249
examples/nfc-mfultralight.c Normal file
View file

@ -0,0 +1,249 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file nfc-mfultool.c
* @brief
*/
#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 "mifareultag.h"
#include "bitutils.h"
static nfc_device_t* pnd;
static nfc_target_info_t nti;
static mifare_param mp;
static mifareul_tag mtDump;
static uint32_t uiBlocks = 0xF;
void print_success_or_failure(bool bFailure, uint32_t* uiBlockCounter)
{
printf("%c",(bFailure)?'x':'.');
if (uiBlockCounter)
*uiBlockCounter += (bFailure)?0:1;
}
bool read_card()
{
uint32_t page;
bool bFailure = false;
uint32_t uiReadBlocks = 0;
printf("Reading out %d blocks |",uiBlocks+1);
for (page = 0; page <= uiBlocks; page += 4)
{
// Skip this the first time, bFailure it means nothing (yet)
if (page != 0)
{
print_success_or_failure(bFailure, &uiReadBlocks);
print_success_or_failure(bFailure, &uiReadBlocks);
print_success_or_failure(bFailure, &uiReadBlocks);
print_success_or_failure(bFailure, &uiReadBlocks);
}
// 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;
}
}
//return bSuccess;
print_success_or_failure(bFailure, &uiReadBlocks);
printf("|\n");
printf("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks+1);
fflush(stdout);
return (!bFailure);
}
bool write_card()
{
uint32_t uiBlock = 0;
int page;
bool bFailure = false;
uint32_t uiWriteBlocks = 0;
for (page = 0x4; page <= 0xF; page++) {
// Show if the readout went well
if (bFailure)
{
printf("x");
// When a failure occured we need to redo the anti-collision
if (!nfc_initiator_select_tag(pnd,NM_ISO14443A_106,NULL,0,&nti))
{
printf("!\nError: tag was removed\n");
return false;
}
bFailure = false;
}
fflush(stdout);
// Make sure a earlier write did not fail
if (!bFailure)
{
// 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, &uiWriteBlocks);
printf("|\n");
printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks+1);
fflush(stdout);
return true;
}
int main(int argc, const char* argv[])
{
bool bReadAction;
byte_t* pbtUID;
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;
}
printf("\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)
{
printf("Could not open dump file: %s\n",argv[2]);
return 1;
}
if (fread(&mtDump,1,sizeof(mtDump),pfDump) != sizeof(mtDump))
{
printf("Could not read from dump file: %s\n",argv[2]);
fclose(pfDump);
return 1;
}
fclose(pfDump);
}
printf("Succesful opened the dump file\n");
// Try to open the NFC reader
pnd = nfc_connect(NULL);
if (pnd == NULL)
{
printf("Error connecting NFC reader\n");
return 1;
}
nfc_initiator_init(pnd);
// Drop the field for a while
nfc_configure(pnd,NDO_ACTIVATE_FIELD,false);
// Let the reader only try once to find a tag
nfc_configure(pnd,NDO_INFINITE_SELECT,false);
nfc_configure(pnd,NDO_HANDLE_CRC,true);
nfc_configure(pnd,NDO_HANDLE_PARITY,true);
// Enable field so more power consuming cards can power themselves up
nfc_configure(pnd,NDO_ACTIVATE_FIELD,true);
printf("Connected to NFC reader: %s\n",pnd->acName);
// Try to find a MIFARE Ultralight tag
if (!nfc_initiator_select_tag(pnd,NM_ISO14443A_106,NULL,0,&nti))
{
printf("Error: no tag was found\n");
nfc_disconnect(pnd);
return 1;
}
// Test if we are dealing with a MIFARE compatible tag
if (nti.nai.abtAtqa[1] != 0x44){
printf("Error: tag is not a MIFARE Ultralight card\n");
nfc_disconnect(pnd);
return 1;
}
// Get the info from the current tag
pbtUID = nti.nai.abtUid;
printf("Found MIFARE Ultralight card with uid: %08x\n", swap_endian32(pbtUID));
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 1;
}
if (fwrite(&mtDump,1,sizeof(mtDump),pfDump) != sizeof(mtDump))
{
printf("Could not write to file: %s\n",argv[2]);
return 1;
}
fclose(pfDump);
printf("Done.\n");
}
} else {
write_card();
}
nfc_disconnect(pnd);
return 0;
}

28
examples/nfc-relay.1 Normal file
View file

@ -0,0 +1,28 @@
.TH NFC-RELAY 1 "June 26, 2009"
.SH NAME
nfc-relay \- Relay attack command line tool based on libnfc
.SH SYNOPSIS
.B nfc-relay
.SH DESCRIPTION
.B nfc-relay
is an utility that demonstrates an relay attack. For this it requires two
NFC devices. One will emulate an ISO/IEC 14443 type A tag, while the 2nd
device will act as a reader. The genuine tag can be placed on the 2nd reader and
the tag emulator can be placed close to the original reader. All communication
is now relayed and shown in the screen on real-time.
.SH BUGS
Please report any bugs on the
.B libnfc
forum at
.BR http://www.libnfc.org/community/ "."
.SH LICENCE
.B libnfc
and
.B nfc-tools
are covered by the GNU Lesser General Public License (LGPL), version 3.
.SH AUTHORS
Roel Verdult <roel@libnfc.org>
.PP
This manual page was written by Romuald Conty <romuald.conty@free.fr>.
It is licensed under the terms of the GNU GPL (version 2 or later).

191
examples/nfc-relay.c Normal file
View file

@ -0,0 +1,191 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file nfc-relay.c
* @brief Relay example using two devices.
*/
#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 <nfc/nfc.h>
#include <nfc/nfc-messages.h>
#include "bitutils.h"
#define MAX_FRAME_LEN 264
#define MAX_DEVICE_COUNT 2
static byte_t abtReaderRx[MAX_FRAME_LEN];
static byte_t abtReaderRxPar[MAX_FRAME_LEN];
static size_t szReaderRxBits;
static byte_t abtTagRx[MAX_FRAME_LEN];
static byte_t abtTagRxPar[MAX_FRAME_LEN];
static size_t szTagRxBits;
static nfc_device_t* pndReader;
static nfc_device_t* pndTag;
static bool quitting=false;
void intr_hdlr(void)
{
printf("\nQuitting...\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 output of READER and EMULATOR data (improves timing).\n");
}
int main(int argc,char* argv[])
{
int arg;
bool quiet_output = false;
size_t szFound;
nfc_device_desc_t *pnddDevices;
const char* acLibnfcVersion = nfc_version();
// 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")) {
INFO("%s", "Quiet mode.");
quiet_output = true;
} else {
ERR("%s is not supported option.", argv[arg]);
print_usage(argv);
return EXIT_FAILURE;
}
}
// Display libnfc version
printf("%s use 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 (szFound < 2) {
ERR("%zd device found but two connected devices are needed to relay NFC.", szFound);
return EXIT_FAILURE;
}
// Try to open the NFC emulator device
pndTag = nfc_connect(&(pnddDevices[0]));
if (pndTag == NULL)
{
printf("Error connecting NFC emulator device\n");
return EXIT_FAILURE;
}
printf("Hint: tag <---> emulator (relay) <---> reader (relay) <---> original reader\n\n");
printf("Connected to the NFC emulator device: %s\n", pndTag->acName);
printf("[+] Try to break out the auto-emulation, this requires a second reader!\n");
printf("[+] To do this, please send any command after the anti-collision\n");
printf("[+] For example, send a RATS command or use the \"nfc-anticol\" tool\n");
if (!nfc_target_init(pndTag,abtReaderRx,&szReaderRxBits))
{
ERR("%s", "Initialization of NFC emulator failed");
nfc_disconnect(pndTag);
return EXIT_FAILURE;
}
printf("%s", "Configuring emulator settings...");
nfc_configure(pndTag,NDO_HANDLE_CRC,false);
nfc_configure(pndTag,NDO_HANDLE_PARITY,false);
nfc_configure(pndTag,NDO_ACCEPT_INVALID_FRAMES,true);
printf("%s", "Done, emulated tag is initialized");
// Try to open the NFC reader
pndReader = nfc_connect(&(pnddDevices[1]));
printf("Connected to the NFC reader device: %s", pndReader->acName);
printf("%s", "Configuring NFC reader settings...");
nfc_initiator_init(pndReader);
nfc_configure(pndReader,NDO_HANDLE_CRC,false);
nfc_configure(pndReader,NDO_HANDLE_PARITY,false);
nfc_configure(pndReader,NDO_ACCEPT_INVALID_FRAMES,true);
printf("%s", "Done, relaying frames now!");
while(!quitting)
{
// Test if we received a frame from the reader
if (nfc_target_receive_bits(pndTag,abtReaderRx,&szReaderRxBits,abtReaderRxPar))
{
// Drop down the field before sending a REQA command and start a new session
if (szReaderRxBits == 7 && abtReaderRx[0] == 0x26)
{
// Drop down field for a very short time (original tag will reboot)
nfc_configure(pndReader,NDO_ACTIVATE_FIELD,false);
if(!quiet_output)
printf("\n");
nfc_configure(pndReader,NDO_ACTIVATE_FIELD,true);
}
// Print the reader frame to the screen
if(!quiet_output)
{
printf("R: ");
print_hex_par(abtReaderRx,szReaderRxBits,abtReaderRxPar);
}
// Forward the frame to the original tag
if (nfc_initiator_transceive_bits(pndReader,abtReaderRx,szReaderRxBits,abtReaderRxPar,abtTagRx,&szTagRxBits,abtTagRxPar))
{
// Redirect the answer back to the reader
nfc_target_send_bits(pndTag,abtTagRx,szTagRxBits,abtTagRxPar);
// Print the tag frame to the screen
if(!quiet_output)
{
printf("T: ");
print_hex_par(abtTagRx,szTagRxBits,abtTagRxPar);
}
}
}
}
nfc_disconnect(pndTag);
nfc_disconnect(pndReader);
exit(EXIT_SUCCESS);
}

View file

@ -0,0 +1,67 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file nfcip-initiator.c
* @brief
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <stdio.h>
#include <string.h>
#include <nfc/nfc.h>
#define MAX_FRAME_LEN 264
int main(int argc, const char *argv[])
{
nfc_device_t *pnd;
nfc_target_info_t ti;
byte_t abtRecv[MAX_FRAME_LEN];
size_t szRecvBits;
byte_t send[] = "Hello World!";
pnd = nfc_connect(NULL);
if (!pnd || !nfc_initiator_init(pnd)
|| !nfc_initiator_select_dep_target(pnd, NM_PASSIVE_DEP, NULL, 0,
NULL, 0, NULL, 0, &ti)) {
printf
("unable to connect, initialize, or select the target\n");
return 1;
}
printf("Sending : %s\n", send);
if (!nfc_initiator_transceive_dep_bytes(pnd,
send,
strlen((char*)send), abtRecv,
&szRecvBits)) {
printf("unable to send data\n");
return 1;
}
abtRecv[szRecvBits] = 0;
printf("Received: %s\n", abtRecv);
nfc_initiator_deselect_tag(pnd);
nfc_disconnect(pnd);
return 0;
}

62
examples/nfcip-target.c Normal file
View file

@ -0,0 +1,62 @@
/*-
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
/**
* @file nfcip-target.c
* @brief
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <stdio.h>
#include <nfc/nfc.h>
#define MAX_FRAME_LEN 264
int main(int argc, const char *argv[])
{
byte_t abtRecv[MAX_FRAME_LEN];
size_t szRecvBits;
byte_t send[] = "Hello Mars!";
nfc_device_t *pnd = nfc_connect(NULL);
if (!pnd || !nfc_target_init(pnd, abtRecv, &szRecvBits)) {
printf("unable to connect or initialize\n");
return 1;
}
if (!nfc_target_receive_dep_bytes(pnd, abtRecv, &szRecvBits)) {
printf("unable to receive data\n");
return 1;
}
abtRecv[szRecvBits] = 0;
printf("Received: %s\n", abtRecv);
printf("Sending : %s\n", send);
if (!nfc_target_send_dep_bytes(pnd, send, 11)) {
printf("unable to send data\n");
return 1;
}
nfc_disconnect(pnd);
return 0;
}