Rearrange source code.
This commit is contained in:
parent
be1639b452
commit
c7d77d7664
59 changed files with 43 additions and 107 deletions
20
examples/CMakeLists.txt
Normal file
20
examples/CMakeLists.txt
Normal 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
37
examples/Makefile.am
Normal 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
|
||||
58
examples/doc/quick_start_example1.c
Normal file
58
examples/doc/quick_start_example1.c
Normal 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
55
examples/mifaretag.h
Normal 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
50
examples/mifareultag.h
Normal 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
30
examples/nfc-anticol.1
Normal 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
210
examples/nfc-anticol.c
Normal 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
37
examples/nfc-emulate.1
Normal 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
172
examples/nfc-emulate.c
Normal 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
27
examples/nfc-list.1
Normal 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
170
examples/nfc-list.c
Normal 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
57
examples/nfc-mfclassic.1
Normal 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
542
examples/nfc-mfclassic.c
Normal 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);
|
||||
}
|
||||
|
||||
44
examples/nfc-mfultralight.1
Normal file
44
examples/nfc-mfultralight.1
Normal 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
249
examples/nfc-mfultralight.c
Normal 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
28
examples/nfc-relay.1
Normal 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
191
examples/nfc-relay.c
Normal 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);
|
||||
}
|
||||
67
examples/nfcip-initiator.c
Normal file
67
examples/nfcip-initiator.c
Normal 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
62
examples/nfcip-target.c
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue