Moving sources into src/ directory.
This commit is contained in:
parent
0b979eaee2
commit
f5acfd7af3
20 changed files with 30 additions and 27 deletions
28
src/Makefile.am
Normal file
28
src/Makefile.am
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
bin_PROGRAMS = anticol list mftool relay emulate
|
||||
|
||||
# set the include path found by configure
|
||||
INCLUDES= $(all_includes)
|
||||
|
||||
nfcinclude_HEADERS = libnfc.h bitutils.h defines.h dev_acr122.h dev_pn531.h types.h mifaretag.h devices.h
|
||||
nfcincludedir = $(includedir)/libnfc
|
||||
|
||||
lib_LTLIBRARIES = libnfc.la
|
||||
|
||||
libnfc_la_CFLAGS = @LIBUSB_CFLAGS@ @LIBPCSCLITE_CFLAGS@
|
||||
libnfc_la_SOURCES = dev_pn531.c dev_acr122.c bitutils.c libnfc.c
|
||||
libnfc_la_LIBADD = @LIBUSB_LIBS@ @LIBPCSCLITE_LIBS@
|
||||
|
||||
anticol_SOURCES = anticol.c
|
||||
anticol_LDADD = libnfc.la
|
||||
|
||||
list_SOURCES = list.c
|
||||
list_LDADD = libnfc.la
|
||||
|
||||
mftool_SOURCES = mftool.c
|
||||
mftool_LDADD = libnfc.la
|
||||
|
||||
relay_SOURCES = relay.c
|
||||
relay_LDADD = libnfc.la
|
||||
|
||||
emulate_SOURCES = emulate.c
|
||||
emulate_LDADD = libnfc.la
|
||||
150
src/anticol.c
Normal file
150
src/anticol.c
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libnfc.h"
|
||||
|
||||
#define SAK_FLAG_ATS_SUPPORTED 0x20
|
||||
|
||||
static byte abtRx[MAX_FRAME_LEN];
|
||||
static ui32 uiRxBits;
|
||||
static ui32 uiRxLen;
|
||||
static byte abtUid[10];
|
||||
static ui32 uiUidLen = 4;
|
||||
static dev_info* pdi;
|
||||
|
||||
// ISO14443A Anti-Collision Commands
|
||||
byte abtReqa [1] = { 0x26 };
|
||||
byte abtSelectAll [2] = { 0x93,0x20 };
|
||||
byte abtSelectTag [9] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
|
||||
byte abtRats [4] = { 0xe0,0x50,0xbc,0xa5 };
|
||||
byte abtHalt [4] = { 0x50,0x00,0x57,0xcd };
|
||||
|
||||
bool transmit_bits(const byte* pbtTx, const ui32 uiTxBits)
|
||||
{
|
||||
// Show transmitted command
|
||||
printf("R: "); print_hex_bits(pbtTx,uiTxBits);
|
||||
|
||||
// Transmit the bit frame command, we don't use the arbitrary parity feature
|
||||
if (!nfc_reader_transceive_bits(pdi,pbtTx,uiTxBits,null,abtRx,&uiRxBits,null)) return false;
|
||||
|
||||
// Show received answer
|
||||
printf("T: "); print_hex_bits(abtRx,uiRxBits);
|
||||
|
||||
// Succesful transfer
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool transmit_bytes(const byte* pbtTx, const ui32 uiTxLen)
|
||||
{
|
||||
// Show transmitted command
|
||||
printf("R: "); print_hex(pbtTx,uiTxLen);
|
||||
|
||||
// Transmit the command bytes
|
||||
if (!nfc_reader_transceive_bytes(pdi,pbtTx,uiTxLen,abtRx,&uiRxLen)) return false;
|
||||
|
||||
// Show received answer
|
||||
printf("T: "); print_hex(abtRx,uiRxLen);
|
||||
|
||||
// Succesful transfer
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
// Try to open the NFC reader
|
||||
pdi = nfc_connect();
|
||||
|
||||
if (!pdi)
|
||||
{
|
||||
printf("Error connecting NFC reader\n");
|
||||
return 1;
|
||||
}
|
||||
nfc_reader_init(pdi);
|
||||
|
||||
// Drop the field for a while
|
||||
nfc_configure(pdi,DCO_ACTIVATE_FIELD,false);
|
||||
|
||||
// Configure the CRC and Parity settings
|
||||
nfc_configure(pdi,DCO_HANDLE_CRC,false);
|
||||
nfc_configure(pdi,DCO_HANDLE_PARITY,true);
|
||||
|
||||
// Enable field so more power consuming cards can power themselves up
|
||||
nfc_configure(pdi,DCO_ACTIVATE_FIELD,true);
|
||||
|
||||
printf("\nConnected to NFC reader: %s\n\n",pdi->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(pdi);
|
||||
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)
|
||||
{
|
||||
uiUidLen = 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);
|
||||
uiUidLen = 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 (uiUidLen == 4)
|
||||
{
|
||||
printf("%08x\n",swap_endian32(abtUid));
|
||||
} else {
|
||||
printf("%014llx\n",swap_endian64(abtUid)&0x00ffffffffffffffull);
|
||||
}
|
||||
|
||||
nfc_disconnect(pdi);
|
||||
return 0;
|
||||
}
|
||||
186
src/bitutils.c
Normal file
186
src/bitutils.c
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bitutils.h"
|
||||
|
||||
const static byte OddParity[256] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
|
||||
};
|
||||
|
||||
const static byte ByteMirror[256] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30,
|
||||
0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98,
|
||||
0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64,
|
||||
0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc,
|
||||
0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02,
|
||||
0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2,
|
||||
0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a,
|
||||
0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e,
|
||||
0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81,
|
||||
0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71,
|
||||
0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
|
||||
0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15,
|
||||
0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad,
|
||||
0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43,
|
||||
0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b,
|
||||
0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97,
|
||||
0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f,
|
||||
0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||||
};
|
||||
|
||||
byte oddparity(const byte bt)
|
||||
{
|
||||
return OddParity[bt];
|
||||
}
|
||||
|
||||
void oddparity_bytes(const byte* pbtData, const ui32 uiLen, byte* pbtPar)
|
||||
{
|
||||
ui32 uiByteNr;
|
||||
|
||||
// Calculate the parity bits for the command
|
||||
for (uiByteNr=0; uiByteNr<uiLen; uiByteNr++)
|
||||
{
|
||||
pbtPar[uiByteNr] = OddParity[pbtData[uiByteNr]];
|
||||
}
|
||||
}
|
||||
|
||||
byte mirror(byte bt)
|
||||
{
|
||||
return ByteMirror[bt];
|
||||
}
|
||||
|
||||
ui32 mirror32(ui32 ui32Bits)
|
||||
{
|
||||
mirror_bytes((byte*)&ui32Bits,4);
|
||||
return ui32Bits;
|
||||
}
|
||||
|
||||
ui64 mirror64(ui64 ui64Bits)
|
||||
{
|
||||
mirror_bytes((byte*)&ui64Bits,8);
|
||||
return ui64Bits;
|
||||
}
|
||||
|
||||
void mirror_bytes(byte *pbts, ui32 uiLen)
|
||||
{
|
||||
ui32 btNr;
|
||||
|
||||
for (btNr=0; btNr<uiLen; btNr++)
|
||||
{
|
||||
*pbts = ByteMirror[*pbts];
|
||||
pbts++;
|
||||
}
|
||||
}
|
||||
|
||||
ui32 swap_endian32(const void* pui32)
|
||||
{
|
||||
ui32 ui32N = *((ui32*)pui32);
|
||||
return (((ui32N&0xFF)<<24)+((ui32N&0xFF00)<<8)+((ui32N&0xFF0000)>>8)+((ui32N&0xFF000000)>>24));
|
||||
}
|
||||
|
||||
ui64 swap_endian64(const void* pui64)
|
||||
{
|
||||
ui64 ui64N = *((ui64*)pui64);
|
||||
return (((ui64N&0xFF)<<56)+((ui64N&0xFF00)<<40)+((ui64N&0xFF0000)<<24)+((ui64N&0xFF000000)<<8)+((ui64N&0xFF00000000ull)>>8)+((ui64N&0xFF0000000000ull)>>24)+((ui64N&0xFF000000000000ull)>>40)+((ui64N&0xFF00000000000000ull)>>56));
|
||||
}
|
||||
|
||||
void append_iso14443a_crc(byte* pbtData, ui32 uiLen)
|
||||
{
|
||||
byte bt;
|
||||
ui32 wCrc = 0x6363;
|
||||
|
||||
do {
|
||||
bt = *pbtData++;
|
||||
bt = (bt^(byte)(wCrc & 0x00FF));
|
||||
bt = (bt^(bt<<4));
|
||||
wCrc = (wCrc >> 8)^((ui32)bt << 8)^((ui32)bt<<3)^((ui32)bt>>4);
|
||||
} while (--uiLen);
|
||||
|
||||
*pbtData++ = (byte) (wCrc & 0xFF);
|
||||
*pbtData = (byte) ((wCrc >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void print_hex(const byte* pbtData, const ui32 uiBytes)
|
||||
{
|
||||
ui32 uiPos;
|
||||
|
||||
for (uiPos=0; uiPos < uiBytes; uiPos++)
|
||||
{
|
||||
printf("%02x ",pbtData[uiPos]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_hex_bits(const byte* pbtData, const ui32 uiBits)
|
||||
{
|
||||
ui32 uiPos;
|
||||
ui32 uiBytes = uiBits/8;
|
||||
|
||||
for (uiPos=0; uiPos < uiBytes; uiPos++)
|
||||
{
|
||||
printf("%02x ",pbtData[uiPos]);
|
||||
}
|
||||
|
||||
// Print the rest bits, these cannot have no parity bit
|
||||
if (uiBits%8 != 0) printf("%02x",pbtData[uiBytes]);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_hex_par(const byte* pbtData, const ui32 uiBits, const byte* pbtDataPar)
|
||||
{
|
||||
ui32 uiPos;
|
||||
ui32 uiBytes = uiBits/8;
|
||||
|
||||
for (uiPos=0; uiPos < uiBytes; uiPos++)
|
||||
{
|
||||
printf("%02x",pbtData[uiPos]);
|
||||
if (OddParity[pbtData[uiPos]] != pbtDataPar[uiPos])
|
||||
{
|
||||
printf("! ");
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
// Print the rest bits, these cannot have no parity bit
|
||||
if (uiBits%8 != 0) printf("%02x",pbtData[uiBytes]);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
44
src/bitutils.h
Normal file
44
src/bitutils.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_BITUTILS_H_
|
||||
#define _LIBNFC_BITUTILS_H_
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
byte oddparity(const byte bt);
|
||||
void oddparity_bytes(const byte* pbtData, const ui32 uiLen, byte* pbtPar);
|
||||
|
||||
byte mirror(byte bt);
|
||||
ui32 mirror32(ui32 ui32Bits);
|
||||
ui64 mirror64(ui64 ui64Bits);
|
||||
void mirror_bytes(byte *pbts, ui32 uiLen);
|
||||
|
||||
ui32 swap_endian32(const void* pui32);
|
||||
ui64 swap_endian64(const void* pui64);
|
||||
|
||||
void append_iso14443a_crc(byte* pbtData, ui32 uiLen);
|
||||
|
||||
void print_hex(const byte* pbtData, const ui32 uiLen);
|
||||
void print_hex_bits(const byte* pbtData, const ui32 uiBits);
|
||||
void print_hex_par(const byte* pbtData, const ui32 uiBits, const byte* pbtDataPar);
|
||||
|
||||
#endif // _LIBNFC_BITUTILS_H_
|
||||
|
||||
50
src/defines.h
Normal file
50
src/defines.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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_DEFINES_H_
|
||||
#define _LIBNFC_DEFINES_H_
|
||||
|
||||
// #define _LIBNFC_VERBOSE_
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char ui8;
|
||||
typedef unsigned short ui16;
|
||||
typedef unsigned int ui32;
|
||||
typedef unsigned long long ui64;
|
||||
typedef unsigned long ulong;
|
||||
typedef char i8;
|
||||
typedef short i16;
|
||||
typedef int i32;
|
||||
|
||||
#define null 0
|
||||
|
||||
typedef void* dev_spec; // Device connection specification
|
||||
#define INVALID_DEVICE_INFO null
|
||||
#define MAX_FRAME_LEN 264
|
||||
#define DEVICE_NAME_LENGTH 256
|
||||
|
||||
// Useful macros
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define INNER_XOR8(n) {n ^= (n >> 4); n ^= (n >> 2); n ^= (n >> 1); n &= 0x01; }
|
||||
#define INNER_XOR32(n) {n ^= (n >> 16); n ^= (n >> 8); INNER_XOR8(n); }
|
||||
#define INNER_XOR64(n) {n ^= (n >> 32); INNER_XOR32(n); }
|
||||
|
||||
#endif // _LIBNFC_DEFINES_H_
|
||||
269
src/dev_acr122.c
Normal file
269
src/dev_acr122.c
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#include <winscard.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "dev_acr122.h"
|
||||
#include "bitutils.h"
|
||||
|
||||
// WINDOWS: #define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500)
|
||||
#define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
|
||||
#define SCARD_OPERATION_SUCCESS 0x61
|
||||
#define SCARD_OPERATION_ERROR 0x63
|
||||
|
||||
#ifndef SCARD_PROTOCOL_UNDEFINED
|
||||
#define SCARD_PROTOCOL_UNDEFINED SCARD_PROTOCOL_UNSET
|
||||
#endif
|
||||
|
||||
#define FIRMWARE_TEXT "ACR122U" // Tested on: ACR122U101(ACS), ACR122U102(Tikitag), ACR122U203(ACS)
|
||||
|
||||
#define ACR122_WRAP_LEN 5
|
||||
#define ACR122_COMMAND_LEN 266
|
||||
#define ACR122_RESPONSE_LEN 268
|
||||
#define MAX_READERS 16
|
||||
|
||||
typedef struct {
|
||||
SCARDCONTEXT hCtx;
|
||||
SCARDHANDLE hCard;
|
||||
SCARD_IO_REQUEST ioCard;
|
||||
} dev_spec_acr122;
|
||||
|
||||
static byte abtTxBuf[ACR122_WRAP_LEN+ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 };
|
||||
static byte abtRxCmd[5] = { 0xFF,0xC0,0x00,0x00 };
|
||||
static byte uiRxCmdLen = sizeof(abtRxCmd);
|
||||
static byte abtRxBuf[ACR122_RESPONSE_LEN];
|
||||
static ulong ulRxBufLen;
|
||||
static byte abtGetFw[5] = { 0xFF,0x00,0x48,0x00,0x00 };
|
||||
static byte abtLed[9] = { 0xFF,0x00,0x40,0x05,0x04,0x00,0x00,0x00,0x00 };
|
||||
|
||||
dev_info* dev_acr122_connect(const ui32 uiIndex)
|
||||
{
|
||||
char* pacReaders[MAX_READERS];
|
||||
char acList[256+64*MAX_READERS];
|
||||
ulong ulListLen = sizeof(acList);
|
||||
ui32 uiPos;
|
||||
ui32 uiReaderCount;
|
||||
ui32 uiReader;
|
||||
ui32 uiDevIndex;
|
||||
dev_info* pdi;
|
||||
dev_spec_acr122* pdsa;
|
||||
dev_spec_acr122 dsa;
|
||||
char* pcFirmware;
|
||||
|
||||
// Clear the reader list
|
||||
memset(acList,0x00,ulListLen);
|
||||
|
||||
// Test if context succeeded
|
||||
if (SCardEstablishContext(SCARD_SCOPE_USER,null,null,&(dsa.hCtx)) != SCARD_S_SUCCESS) return INVALID_DEVICE_INFO;
|
||||
|
||||
// Retrieve the string array of all available pcsc readers
|
||||
if (SCardListReaders(dsa.hCtx,null,acList,(void*)&ulListLen) != SCARD_S_SUCCESS) return INVALID_DEVICE_INFO;
|
||||
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Found the following PCSC device(s)\n");
|
||||
printf("- %s\n",acList);
|
||||
#endif
|
||||
|
||||
pacReaders[0] = acList;
|
||||
uiReaderCount = 1;
|
||||
for (uiPos=0; uiPos<ulListLen; uiPos++)
|
||||
{
|
||||
// Make sure don't break out of our reader array
|
||||
if (uiReaderCount == MAX_READERS) break;
|
||||
|
||||
// Test if there is a next reader available
|
||||
if (acList[uiPos] == 0x00)
|
||||
{
|
||||
// Test if we are at the end of the list
|
||||
if (acList[uiPos+1] == 0x00)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Store the position of the next reader and search for more readers
|
||||
pacReaders[uiReaderCount] = acList+uiPos+1;
|
||||
uiReaderCount++;
|
||||
|
||||
// Debug info
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("- %s\n",acList+uiPos+1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the device index we are seaching for
|
||||
uiDevIndex = uiIndex;
|
||||
|
||||
// Iterate through all readers and try to find the ACR122 on requested index
|
||||
for (uiReader=0; uiReader<uiReaderCount; uiReader++)
|
||||
{
|
||||
// Test if we were able to connect to the "emulator" card
|
||||
if (SCardConnect(dsa.hCtx,pacReaders[uiReader],SCARD_SHARE_EXCLUSIVE,SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,&(dsa.hCard),(void*)&(dsa.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
|
||||
{
|
||||
// Connect to ACR122 firmware version >2.0
|
||||
if (SCardConnect(dsa.hCtx,pacReaders[uiReader],SCARD_SHARE_DIRECT,0,&(dsa.hCard),(void*)&(dsa.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
|
||||
{
|
||||
// We can not connect to this device, we will just ignore it
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Configure I/O settings for card communication
|
||||
dsa.ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST);
|
||||
|
||||
// Retrieve the current firmware version
|
||||
pcFirmware = dev_acr122_firmware((dev_info*)&dsa);
|
||||
if (strstr(pcFirmware,FIRMWARE_TEXT) != null)
|
||||
{
|
||||
// We found a occurence, test if it has the right index
|
||||
if (uiDevIndex != 0)
|
||||
{
|
||||
// Let's look for the next reader
|
||||
uiDevIndex--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allocate memory and store the device specification
|
||||
pdsa = malloc(sizeof(dev_spec_acr122));
|
||||
*pdsa = dsa;
|
||||
|
||||
// Done, we found the reader we are looking for
|
||||
pdi = malloc(sizeof(dev_info));
|
||||
strcpy(pdi->acName,pcFirmware);
|
||||
pdi->ct = CT_PN532;
|
||||
pdi->ds = (dev_spec)pdsa;
|
||||
pdi->bActive = true;
|
||||
pdi->bCrc = true;
|
||||
pdi->bPar = true;
|
||||
pdi->ui8TxBits = 0;
|
||||
return pdi;
|
||||
}
|
||||
}
|
||||
|
||||
// Too bad, the reader could not be located;
|
||||
return INVALID_DEVICE_INFO;
|
||||
}
|
||||
|
||||
void dev_acr122_disconnect(dev_info* pdi)
|
||||
{
|
||||
dev_spec_acr122* pdsa = (dev_spec_acr122*)pdi->ds;
|
||||
SCardDisconnect(pdsa->hCard,SCARD_LEAVE_CARD);
|
||||
SCardReleaseContext(pdsa->hCtx);
|
||||
free(pdsa);
|
||||
free(pdi);
|
||||
}
|
||||
|
||||
bool dev_acr122_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
|
||||
{
|
||||
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
|
||||
|
||||
// Make sure the command does not overflow the send buffer
|
||||
if (uiTxLen > ACR122_COMMAND_LEN) return false;
|
||||
|
||||
// Store the length of the command we are going to send
|
||||
abtTxBuf[4] = uiTxLen;
|
||||
|
||||
// Prepare and transmit the send buffer
|
||||
memcpy(abtTxBuf+5,pbtTx,uiTxLen);
|
||||
ulRxBufLen = sizeof(abtRxBuf);
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Tx: ");
|
||||
print_hex(abtTxBuf,uiTxLen+5);
|
||||
#endif
|
||||
|
||||
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
|
||||
{
|
||||
if (SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtTxBuf,uiTxLen+5,abtRxBuf,ulRxBufLen,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
|
||||
} else {
|
||||
if (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtTxBuf,uiTxLen+5,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
|
||||
}
|
||||
|
||||
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_T0)
|
||||
{
|
||||
// Make sure we received the byte-count we expected
|
||||
if (ulRxBufLen != 2) return false;
|
||||
|
||||
// Check if the operation was successful, so an answer is available
|
||||
if (*abtRxBuf == SCARD_OPERATION_ERROR) return false;
|
||||
|
||||
// Retrieve the response bytes
|
||||
abtRxCmd[4] = abtRxBuf[1];
|
||||
ulRxBufLen = sizeof(abtRxBuf);
|
||||
if (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtRxCmd,uiRxCmdLen,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
|
||||
}
|
||||
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Rx: ");
|
||||
print_hex(abtRxBuf,ulRxBufLen);
|
||||
#endif
|
||||
|
||||
// When the answer should be ignored, just return a succesful result
|
||||
if (pbtRx == null || puiRxLen == null) return true;
|
||||
|
||||
// Make sure we have an emulated answer that fits the return buffer
|
||||
if (ulRxBufLen < 4 || (ulRxBufLen-4) > *puiRxLen) return false;
|
||||
// Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00
|
||||
*puiRxLen = ulRxBufLen-4;
|
||||
memcpy(pbtRx,abtRxBuf+2,*puiRxLen);
|
||||
|
||||
// Transmission went successful
|
||||
return true;
|
||||
}
|
||||
|
||||
char* dev_acr122_firmware(const dev_spec ds)
|
||||
{
|
||||
ui32 uiResult;
|
||||
|
||||
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
|
||||
static char abtFw[11];
|
||||
ulong ulFwLen = sizeof(abtFw);
|
||||
memset(abtFw,0x00,ulFwLen);
|
||||
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
|
||||
{
|
||||
uiResult = SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtGetFw,sizeof(abtGetFw),abtFw,ulFwLen,(void*)&ulFwLen);
|
||||
} else {
|
||||
uiResult = SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtGetFw,sizeof(abtGetFw),null,(byte*)abtFw,(void*)&ulFwLen);
|
||||
}
|
||||
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
if (uiResult != SCARD_S_SUCCESS)
|
||||
{
|
||||
printf("No ACR122 firmware received, Error: %08x\n",uiResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
return abtFw;
|
||||
}
|
||||
|
||||
bool dev_acr122_led_red(const dev_spec ds, bool bOn)
|
||||
{
|
||||
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
|
||||
byte abtBuf[2];
|
||||
ulong ulBufLen = sizeof(abtBuf);
|
||||
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
|
||||
{
|
||||
return (SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtLed,sizeof(abtLed),abtBuf,ulBufLen,(void*)&ulBufLen) == SCARD_S_SUCCESS);
|
||||
} else {
|
||||
return (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtLed,sizeof(abtLed),null,(byte*)abtBuf,(void*)&ulBufLen) == SCARD_S_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
39
src/dev_acr122.h
Normal file
39
src/dev_acr122.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_DEV_ACR122_H_
|
||||
#define _LIBNFC_DEV_ACR122_H_
|
||||
|
||||
#include "defines.h"
|
||||
#include "types.h"
|
||||
|
||||
// Functions used by developer to handle connection to this device
|
||||
dev_info* dev_acr122_connect(const ui32 uiIndex);
|
||||
void dev_acr122_disconnect(dev_info* pdi);
|
||||
|
||||
// Callback function used by libnfc to transmit commands to the PN53X chip
|
||||
bool dev_acr122_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
|
||||
|
||||
// Various additional features this device supports
|
||||
char* dev_acr122_firmware(const dev_spec ds);
|
||||
bool dev_acr122_led_red(const dev_spec ds, bool bOn);
|
||||
|
||||
#endif // _LIBNFC_DEV_ACR122_H_
|
||||
|
||||
247
src/dev_pn531.c
Normal file
247
src/dev_pn531.c
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Thanks to d18c7db and Okko for example code
|
||||
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#include <usb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "dev_pn531.h"
|
||||
#include "bitutils.h"
|
||||
|
||||
#define BUFFER_LENGTH 256
|
||||
#define USB_TIMEOUT 30000
|
||||
static char buffer[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
||||
|
||||
typedef struct {
|
||||
usb_dev_handle* pudh;
|
||||
ui32 uiEndPointIn;
|
||||
ui32 uiEndPointOut;
|
||||
} dev_spec_pn531;
|
||||
|
||||
// Find transfer endpoints for bulk transfers
|
||||
void get_end_points(struct usb_device *dev, dev_spec_pn531* pdsp)
|
||||
{
|
||||
ui32 uiIndex;
|
||||
ui32 uiEndPoint;
|
||||
struct usb_interface_descriptor* puid = dev->config->interface->altsetting;
|
||||
|
||||
// 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
|
||||
for(uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++)
|
||||
{
|
||||
// Only accept bulk transfer endpoints (ignore interrupt endpoints)
|
||||
if(puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue;
|
||||
|
||||
// Copy the endpoint to a local var, makes it more readable code
|
||||
uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress;
|
||||
|
||||
// Test if we dealing with a bulk IN endpoint
|
||||
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN)
|
||||
{
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
|
||||
#endif
|
||||
pdsp->uiEndPointIn = uiEndPoint;
|
||||
}
|
||||
|
||||
// Test if we dealing with a bulk OUT endpoint
|
||||
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
|
||||
{
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
|
||||
#endif
|
||||
pdsp->uiEndPointOut = uiEndPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev_info* dev_pn531_connect(const ui32 uiIndex)
|
||||
{
|
||||
int idvendor = 0x04CC;
|
||||
int idproduct = 0x0531;
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev;
|
||||
dev_info* pdi = INVALID_DEVICE_INFO;
|
||||
dev_spec_pn531* pdsp;
|
||||
dev_spec_pn531 dsp;
|
||||
ui32 uiDevIndex;
|
||||
|
||||
dsp.uiEndPointIn = 0;
|
||||
dsp.uiEndPointOut = 0;
|
||||
dsp.pudh = null;
|
||||
|
||||
usb_init();
|
||||
if (usb_find_busses() < 0) return INVALID_DEVICE_INFO;
|
||||
if (usb_find_devices() < 0) return INVALID_DEVICE_INFO;
|
||||
|
||||
// Initialize the device index we are seaching for
|
||||
uiDevIndex = uiIndex;
|
||||
|
||||
for (bus = usb_get_busses(); bus; bus = bus->next)
|
||||
{
|
||||
for (dev = bus->devices; dev; dev = dev->next)
|
||||
{
|
||||
if (idvendor==dev->descriptor.idVendor && idproduct==dev->descriptor.idProduct)
|
||||
{
|
||||
// Make sure there are 2 endpoints available
|
||||
if (dev->config->interface->altsetting->bNumEndpoints < 2) return pdi;
|
||||
|
||||
// Test if we are looking for this device according to the current index
|
||||
if (uiDevIndex != 0)
|
||||
{
|
||||
// Nope, we maybe want the next one, let's try to find another
|
||||
uiDevIndex--;
|
||||
continue;
|
||||
}
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Found PN531 device\n");
|
||||
#endif
|
||||
|
||||
// Open the PN531 USB device
|
||||
dsp.pudh = usb_open(dev);
|
||||
|
||||
get_end_points(dev,&dsp);
|
||||
if(usb_set_configuration(dsp.pudh,1) < 0)
|
||||
{
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Setting config failed\n");
|
||||
#endif
|
||||
usb_close(dsp.pudh);
|
||||
return INVALID_DEVICE_INFO;
|
||||
}
|
||||
|
||||
if(usb_claim_interface(dsp.pudh,0) < 0)
|
||||
{
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Can't claim interface\n");
|
||||
#endif
|
||||
usb_close(dsp.pudh);
|
||||
return INVALID_DEVICE_INFO;
|
||||
}
|
||||
// Allocate memory for the device info and specification, fill it and return the info
|
||||
pdsp = malloc(sizeof(dev_spec_pn531));
|
||||
*pdsp = dsp;
|
||||
pdi = malloc(sizeof(dev_info));
|
||||
strcpy(pdi->acName,"PN531USB");
|
||||
pdi->ct = CT_PN531;
|
||||
pdi->ds = (dev_spec)pdsp;
|
||||
pdi->bActive = true;
|
||||
pdi->bCrc = true;
|
||||
pdi->bPar = true;
|
||||
pdi->ui8TxBits = 0;
|
||||
return pdi;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pdi;
|
||||
}
|
||||
|
||||
void dev_pn531_disconnect(dev_info* pdi)
|
||||
{
|
||||
dev_spec_pn531* pdsp = (dev_spec_pn531*)pdi->ds;
|
||||
usb_release_interface(pdsp->pudh,0);
|
||||
usb_close(pdsp->pudh);
|
||||
free(pdi->ds);
|
||||
free(pdi);
|
||||
}
|
||||
|
||||
bool dev_pn531_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
|
||||
{
|
||||
ui32 uiPos = 0;
|
||||
int ret = 0;
|
||||
char buf[BUFFER_LENGTH];
|
||||
dev_spec_pn531* pdsp = (dev_spec_pn531*)ds;
|
||||
|
||||
// Packet length = data length (len) + checksum (1) + end of stream marker (1)
|
||||
buffer[3] = uiTxLen;
|
||||
// Packet length checksum
|
||||
buffer[4] = BUFFER_LENGTH - buffer[3];
|
||||
// Copy the PN53X command into the packet buffer
|
||||
memmove(buffer+5,pbtTx,uiTxLen);
|
||||
|
||||
// Calculate data payload checksum
|
||||
buffer[uiTxLen+5] = 0;
|
||||
for(uiPos=0; uiPos < uiTxLen; uiPos++)
|
||||
{
|
||||
buffer[uiTxLen+5] -= buffer[uiPos+5];
|
||||
}
|
||||
|
||||
// End of stream marker
|
||||
buffer[uiTxLen+6] = 0;
|
||||
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Tx: ");
|
||||
print_hex((byte*)buffer,uiTxLen+7);
|
||||
#endif
|
||||
|
||||
ret = usb_bulk_write(pdsp->pudh, pdsp->uiEndPointOut, buffer, uiTxLen+7, USB_TIMEOUT);
|
||||
if( ret < 0 )
|
||||
{
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("usb_bulk_write failed with error %d\n", ret);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, buf, BUFFER_LENGTH, USB_TIMEOUT);
|
||||
if( ret < 0 )
|
||||
{
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf( "usb_bulk_read failed with error %d\n", ret);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Rx: ");
|
||||
print_hex((byte*)buf,ret);
|
||||
#endif
|
||||
|
||||
if( ret == 6 )
|
||||
{
|
||||
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, buf, BUFFER_LENGTH, USB_TIMEOUT);
|
||||
if( ret < 0 )
|
||||
{
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("usb_bulk_read failed with error %d\n", ret);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _LIBNFC_VERBOSE_
|
||||
printf("Rx: ");
|
||||
print_hex((byte*)buf,ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
// When the answer should be ignored, just return a succesful result
|
||||
if(pbtRx == null || puiRxLen == null) return true;
|
||||
|
||||
// Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
|
||||
if(ret < 9) return false;
|
||||
|
||||
// Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
|
||||
*puiRxLen = ret - 7 - 2;
|
||||
memcpy( pbtRx, buf + 7, *puiRxLen);
|
||||
|
||||
return true;
|
||||
}
|
||||
35
src/dev_pn531.h
Normal file
35
src/dev_pn531.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_DEV_PN531_H_
|
||||
#define _LIBNFC_DEV_PN531_H_
|
||||
|
||||
#include "defines.h"
|
||||
#include "types.h"
|
||||
|
||||
// Functions used by developer to handle connection to this device
|
||||
dev_info* dev_pn531_connect(const ui32 uiIndex);
|
||||
void dev_pn531_disconnect(dev_info* pdi);
|
||||
|
||||
// Callback function used by libnfc to transmit commands to the PN53X chip
|
||||
bool dev_pn531_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
|
||||
|
||||
#endif // _LIBNFC_DEV_PN531_H_
|
||||
|
||||
36
src/devices.h
Normal file
36
src/devices.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_DEVICES_H_
|
||||
#define _LIBNFC_DEVICES_H_
|
||||
|
||||
#include "defines.h"
|
||||
#include "types.h"
|
||||
#include "dev_acr122.h"
|
||||
#include "dev_pn531.h"
|
||||
|
||||
const static struct dev_callbacks dev_callbacks_list[] = {
|
||||
// Driver Name Connect Transceive Disconect
|
||||
{ "ACR122", dev_acr122_connect, dev_acr122_transceive, dev_acr122_disconnect },
|
||||
{ "PN531USB", dev_pn531_connect, dev_pn531_transceive, dev_pn531_disconnect }
|
||||
};
|
||||
|
||||
#endif // _LIBNFC_DEVICES_H_
|
||||
|
||||
112
src/emulate.c
Normal file
112
src/emulate.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libnfc.h"
|
||||
|
||||
static byte abtRecv[MAX_FRAME_LEN];
|
||||
static ui32 uiRecvBits;
|
||||
static dev_info* pdi;
|
||||
|
||||
// ISO14443A Anti-Collision response
|
||||
byte abtAtqa [2] = { 0x04,0x00 };
|
||||
byte abtUidBcc [5] = { 0xDE,0xAD,0xBE,0xAF,0x62 };
|
||||
byte abtSak [9] = { 0x08,0xb6,0xdd };
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
byte* pbtTx = null;
|
||||
ui32 uiTxBits;
|
||||
|
||||
// Try to open the NFC reader
|
||||
pdi = nfc_connect();
|
||||
|
||||
if (pdi == INVALID_DEVICE_INFO)
|
||||
{
|
||||
printf("Error connecting NFC second reader\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("[+] Connected to NFC reader: %s\n",pdi->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 \"anticol\" tool\n");
|
||||
if (!nfc_target_init(pdi,abtRecv,&uiRecvBits))
|
||||
{
|
||||
printf("Error: Could not come out of auto-emulation, no command was received\n");
|
||||
return 1;
|
||||
}
|
||||
printf("[+] Received initiator command: ");
|
||||
print_hex_bits(abtRecv,uiRecvBits);
|
||||
printf("[+] Configuring communication\n");
|
||||
nfc_configure(pdi,DCO_HANDLE_CRC,false);
|
||||
nfc_configure(pdi,DCO_HANDLE_PARITY,true);
|
||||
printf("[+] Done, the emulated tag is initialized\n\n");
|
||||
|
||||
while(true)
|
||||
{
|
||||
// Test if we received a frame
|
||||
if (nfc_target_receive_bits(pdi,abtRecv,&uiRecvBits,null))
|
||||
{
|
||||
// Prepare the command to send back for the anti-collision request
|
||||
switch(uiRecvBits)
|
||||
{
|
||||
case 7: // Request or Wakeup
|
||||
pbtTx = abtAtqa;
|
||||
uiTxBits = 16;
|
||||
// New anti-collsion session started
|
||||
printf("\n");
|
||||
break;
|
||||
|
||||
case 16: // Select All
|
||||
pbtTx = abtUidBcc;
|
||||
uiTxBits = 40;
|
||||
break;
|
||||
|
||||
case 72: // Select Tag
|
||||
pbtTx = abtSak;
|
||||
uiTxBits = 24;
|
||||
break;
|
||||
|
||||
default: // unknown length?
|
||||
uiTxBits = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
printf("R: ");
|
||||
print_hex_bits(abtRecv,uiRecvBits);
|
||||
|
||||
// Test if we know how to respond
|
||||
if(uiTxBits)
|
||||
{
|
||||
// Send and print the command to the screen
|
||||
nfc_target_send_bits(pdi,pbtTx,uiTxBits,null);
|
||||
printf("T: ");
|
||||
print_hex_bits(pbtTx,uiTxBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nfc_disconnect(pdi);
|
||||
}
|
||||
|
||||
761
src/libnfc.c
Normal file
761
src/libnfc.c
Normal file
|
|
@ -0,0 +1,761 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include "libnfc.h"
|
||||
#include "bitutils.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// Registers and symbols masks used to covers parts within a register
|
||||
#define REG_CIU_TX_MODE 0x6302
|
||||
#define SYMBOL_TX_CRC_ENABLE 0x80
|
||||
#define REG_CIU_RX_MODE 0x6303
|
||||
#define SYMBOL_RX_CRC_ENABLE 0x80
|
||||
#define SYMBOL_RX_NO_ERROR 0x08
|
||||
#define SYMBOL_RX_MULTIPLE 0x04
|
||||
#define REG_CIU_TX_AUTO 0x6305
|
||||
#define SYMBOL_FORCE_100_ASK 0x40
|
||||
#define SYMBOL_AUTO_WAKE_UP 0x20
|
||||
#define SYMBOL_INITIAL_RF_ON 0x04
|
||||
#define REG_CIU_MANUAL_RCV 0x630D
|
||||
#define SYMBOL_PARITY_DISABLE 0x10
|
||||
#define REG_CIU_STATUS2 0x6338
|
||||
#define SYMBOL_MF_CRYPTO1_ON 0x08
|
||||
#define REG_CIU_CONTROL 0x633C
|
||||
#define SYMBOL_INITIATOR 0x10
|
||||
#define SYMBOL_RX_LAST_BITS 0x07
|
||||
#define REG_CIU_BIT_FRAMING 0x633D
|
||||
#define SYMBOL_TX_LAST_BITS 0x07
|
||||
|
||||
#define PARAM_NONE 0x00
|
||||
#define PARAM_NAD_USED 0x01
|
||||
#define PARAM_DID_USED 0x02
|
||||
#define PARAM_AUTO_ATR_RES 0x04
|
||||
#define PARAM_AUTO_RATS 0x10
|
||||
#define PARAM_14443_4_PICC 0x20
|
||||
#define PARAM_NO_AMBLE 0x40
|
||||
|
||||
// PN53X configuration
|
||||
byte pncmd_get_firmware_version [ 2] = { 0xD4,0x02 };
|
||||
byte pncmd_get_general_status [ 2] = { 0xD4,0x04 };
|
||||
byte pncmd_get_register [ 4] = { 0xD4,0x06 };
|
||||
byte pncmd_set_register [ 5] = { 0xD4,0x08 };
|
||||
byte pncmd_set_parameters [ 3] = { 0xD4,0x12 };
|
||||
|
||||
// RF field configuration
|
||||
byte pncmd_rf_configure_field [ 4] = { 0xD4,0x32,0x01 };
|
||||
byte pncmd_rf_configure_timing [ 4] = { 0xD4,0x32,0x02 };
|
||||
byte pncmd_rf_configure_retry_data [ 4] = { 0xD4,0x32,0x04 };
|
||||
byte pncmd_rf_configure_retry_select [ 6] = { 0xD4,0x32,0x05 };
|
||||
|
||||
// Reader
|
||||
byte pncmd_reader_list_passive [264] = { 0xD4,0x4A };
|
||||
byte pncmd_reader_select [ 3] = { 0xD4,0x54 };
|
||||
byte pncmd_reader_deselect [ 3] = { 0xD4,0x44,0x00 };
|
||||
byte pncmd_reader_release [ 3] = { 0xD4,0x52,0x00 };
|
||||
byte pncmd_reader_set_baud_rate [ 5] = { 0xD4,0x4E };
|
||||
byte pncmd_reader_exchange_data [265] = { 0xD4,0x40 };
|
||||
byte pncmd_reader_auto_poll [ 5] = { 0xD4,0x60 };
|
||||
|
||||
// Target
|
||||
byte pncmd_target_get_data [ 2] = { 0xD4,0x86 };
|
||||
byte pncmd_target_init [ 39] = { 0xD4,0x8C };
|
||||
byte pncmd_target_virtual_card [ 4] = { 0xD4,0x14 };
|
||||
byte pncmd_target_receive [ 2] = { 0xD4,0x88 };
|
||||
byte pncmd_target_send [264] = { 0xD4,0x90 };
|
||||
byte pncmd_target_get_status [ 2] = { 0xD4,0x8A };
|
||||
|
||||
// Exchange raw data frames
|
||||
byte pncmd_exchange_raw_data [266] = { 0xD4,0x42 };
|
||||
|
||||
// Global buffers used for communication with the PN53X chip
|
||||
#define MAX_FRAME_LEN 264
|
||||
static byte abtRx[MAX_FRAME_LEN];
|
||||
static ui32 uiRxLen;
|
||||
|
||||
bool pn53x_transceive(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen)
|
||||
{
|
||||
// Reset the receiving buffer
|
||||
uiRxLen = MAX_FRAME_LEN;
|
||||
|
||||
// Call the tranceive callback function of the current device
|
||||
if (!pdi->pdc->transceive(pdi->ds,pbtTx,uiTxLen,abtRx,&uiRxLen)) return false;
|
||||
|
||||
// Make sure there was no failure reported by the PN53X chip (0x00 == OK)
|
||||
if (abtRx[0] != 0) return false;
|
||||
|
||||
// Succesful transmission
|
||||
return true;
|
||||
}
|
||||
|
||||
byte pn53x_get_reg(const dev_info* pdi, ui16 ui16Reg)
|
||||
{
|
||||
ui8 ui8Value;
|
||||
ui32 uiValueLen = 1;
|
||||
pncmd_get_register[2] = ui16Reg >> 8;
|
||||
pncmd_get_register[3] = ui16Reg & 0xff;
|
||||
pdi->pdc->transceive(pdi->ds,pncmd_get_register,4,&ui8Value,&uiValueLen);
|
||||
return ui8Value;
|
||||
}
|
||||
|
||||
bool pn53x_set_reg(const dev_info* pdi, ui16 ui16Reg, ui8 ui8SybmolMask, ui8 ui8Value)
|
||||
{
|
||||
pncmd_set_register[2] = ui16Reg >> 8;
|
||||
pncmd_set_register[3] = ui16Reg & 0xff;
|
||||
pncmd_set_register[4] = ui8Value | (pn53x_get_reg(pdi,ui16Reg) & (~ui8SybmolMask));
|
||||
return pdi->pdc->transceive(pdi->ds,pncmd_set_register,5,null,null);
|
||||
}
|
||||
|
||||
bool pn53x_set_parameters(const dev_info* pdi, ui8 ui8Value)
|
||||
{
|
||||
pncmd_set_parameters[2] = ui8Value;
|
||||
return pdi->pdc->transceive(pdi->ds,pncmd_set_parameters,3,null,null);
|
||||
}
|
||||
|
||||
bool pn53x_set_tx_bits(const dev_info* pdi, ui8 ui8Bits)
|
||||
{
|
||||
// Test if we need to update the transmission bits register setting
|
||||
if (pdi->ui8TxBits != ui8Bits)
|
||||
{
|
||||
// Set the amount of transmission bits in the PN53X chip register
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_BIT_FRAMING,SYMBOL_TX_LAST_BITS,ui8Bits)) return false;
|
||||
|
||||
// Store the new setting
|
||||
((dev_info*)pdi)->ui8TxBits = ui8Bits;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pn53x_wrap_frame(const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtFrame, ui32* puiFrameBits)
|
||||
{
|
||||
byte btFrame;
|
||||
byte btData;
|
||||
ui32 uiBitPos;
|
||||
ui32 uiDataPos = 0;
|
||||
ui32 uiBitsLeft = uiTxBits;
|
||||
|
||||
// Make sure we should frame at least something
|
||||
if (uiBitsLeft == 0) return false;
|
||||
|
||||
// Handle a short response (1byte) as a special case
|
||||
if (uiBitsLeft < 9)
|
||||
{
|
||||
*pbtFrame = *pbtTx;
|
||||
*puiFrameBits = uiTxBits;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We start by calculating the frame length in bits
|
||||
*puiFrameBits = uiTxBits + (uiTxBits/8);
|
||||
|
||||
// Parse the data bytes and add the parity bits
|
||||
// This is really a sensitive process, mirror the frame bytes and append parity bits
|
||||
// buffer = mirror(frame-byte) + parity + mirror(frame-byte) + parity + ...
|
||||
// split "buffer" up in segments of 8 bits again and mirror them
|
||||
// air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + ..
|
||||
while(true)
|
||||
{
|
||||
// Reset the temporary frame byte;
|
||||
btFrame = 0;
|
||||
|
||||
for (uiBitPos=0; uiBitPos<8; uiBitPos++)
|
||||
{
|
||||
// Copy as much data that fits in the frame byte
|
||||
btData = mirror(pbtTx[uiDataPos]);
|
||||
btFrame |= (btData >> uiBitPos);
|
||||
// Save this frame byte
|
||||
*pbtFrame = mirror(btFrame);
|
||||
// Set the remaining bits of the date in the new frame byte and append the parity bit
|
||||
btFrame = (btData << (8-uiBitPos));
|
||||
btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7-uiBitPos));
|
||||
// Backup the frame bits we have so far
|
||||
pbtFrame++;
|
||||
*pbtFrame = mirror(btFrame);
|
||||
// Increase the data (without parity bit) position
|
||||
uiDataPos++;
|
||||
// Test if we are done
|
||||
if (uiBitsLeft < 9) return true;
|
||||
uiBitsLeft -= 8;
|
||||
}
|
||||
// Every 8 data bytes we lose one frame byte to the parities
|
||||
pbtFrame++;
|
||||
}
|
||||
}
|
||||
|
||||
bool pn53x_unwrap_frame(const byte* pbtFrame, const ui32 uiFrameBits, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
|
||||
{
|
||||
byte btFrame;
|
||||
byte btData;
|
||||
ui8 uiBitPos;
|
||||
ui32 uiDataPos = 0;
|
||||
byte* pbtFramePos = (byte*) pbtFrame;
|
||||
ui32 uiBitsLeft = uiFrameBits;
|
||||
|
||||
// Make sure we should frame at least something
|
||||
if (uiBitsLeft == 0) return false;
|
||||
|
||||
// Handle a short response (1byte) as a special case
|
||||
if (uiBitsLeft < 9)
|
||||
{
|
||||
*pbtRx = *pbtFrame;
|
||||
*puiRxBits = uiFrameBits;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate the data length in bits
|
||||
*puiRxBits = uiFrameBits - (uiFrameBits/9);
|
||||
|
||||
// Parse the frame bytes, remove the parity bits and store them in the parity array
|
||||
// This process is the reverse of WrapFrame(), look there for more info
|
||||
while(true)
|
||||
{
|
||||
for (uiBitPos=0; uiBitPos<8; uiBitPos++)
|
||||
{
|
||||
btFrame = mirror(pbtFramePos[uiDataPos]);
|
||||
btData = (btFrame << uiBitPos);
|
||||
btFrame = mirror(pbtFramePos[uiDataPos+1]);
|
||||
btData |= (btFrame >> (8-uiBitPos));
|
||||
pbtRx[uiDataPos] = mirror(btData);
|
||||
if(pbtRxPar != null) pbtRxPar[uiDataPos] = ((btFrame >> (7-uiBitPos)) & 0x01);
|
||||
// Increase the data (without parity bit) position
|
||||
uiDataPos++;
|
||||
// Test if we are done
|
||||
if (uiBitsLeft < 9) return true;
|
||||
uiBitsLeft -= 9;
|
||||
}
|
||||
// Every 8 data bytes we lose one frame byte to the parities
|
||||
pbtFramePos++;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info* nfc_connect()
|
||||
{
|
||||
dev_info* pdi;
|
||||
ui32 uiDev;
|
||||
byte abtFw[4];
|
||||
ui32 uiFwLen = sizeof(abtFw);
|
||||
|
||||
// Search through the device list for an available device
|
||||
for (uiDev=0; uiDev<sizeof(dev_callbacks_list)/sizeof(dev_callbacks_list[0]); uiDev++)
|
||||
{
|
||||
// Try to claim the device
|
||||
pdi = dev_callbacks_list[uiDev].connect(0);
|
||||
|
||||
// Test if the connection was successful
|
||||
if (pdi != INVALID_DEVICE_INFO)
|
||||
{
|
||||
// Great we have claimed a device
|
||||
pdi->pdc = &(dev_callbacks_list[uiDev]);
|
||||
pdi->pdc->transceive(pdi->ds,pncmd_get_register,4,null,null);
|
||||
|
||||
// Try to retrieve PN53x chip revision
|
||||
if (!pdi->pdc->transceive(pdi->ds,pncmd_get_firmware_version,2,abtFw,&uiFwLen))
|
||||
{
|
||||
// Failed to get firmware revision??, whatever...let's disconnect and clean up and return err
|
||||
pdi->pdc->disconnect(pdi);
|
||||
return INVALID_DEVICE_INFO;
|
||||
}
|
||||
|
||||
// Add the firmware revision to the device name, PN531 gives 2 bytes info, but PN532 gives 4
|
||||
switch(pdi->ct)
|
||||
{
|
||||
case CT_PN531: sprintf(pdi->acName,"%s - PN531 v%d.%d",pdi->acName,abtFw[0],abtFw[1]); break;
|
||||
case CT_PN532: sprintf(pdi->acName,"%s - PN532 v%d.%d (0x%02x)",pdi->acName,abtFw[1],abtFw[2],abtFw[3]); break;
|
||||
case CT_PN533: sprintf(pdi->acName,"%s - PN533 v%d.%d (0x%02x)",pdi->acName,abtFw[1],abtFw[2],abtFw[3]); break;
|
||||
}
|
||||
|
||||
// Reset the ending transmission bits register, it is unknown what the last tranmission used there
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_BIT_FRAMING,SYMBOL_TX_LAST_BITS,0x00)) return INVALID_DEVICE_INFO;
|
||||
|
||||
// Make sure we reset the CRC and parity to chip handling.
|
||||
if (!nfc_configure(pdi,DCO_HANDLE_CRC,true)) return INVALID_DEVICE_INFO;
|
||||
if (!nfc_configure(pdi,DCO_HANDLE_PARITY,true)) return INVALID_DEVICE_INFO;
|
||||
|
||||
// Deactivate the CRYPTO1 chiper, it may could cause problems when still active
|
||||
if (!nfc_configure(pdi,DCO_ACTIVATE_CRYPTO1,false)) return INVALID_DEVICE_INFO;
|
||||
|
||||
return pdi;
|
||||
}
|
||||
}
|
||||
|
||||
// To bad, no reader is ready to be claimed
|
||||
return INVALID_DEVICE_INFO;
|
||||
}
|
||||
|
||||
void nfc_disconnect(dev_info* pdi)
|
||||
{
|
||||
// Disconnect, clean up and release the device
|
||||
pdi->pdc->disconnect(pdi);
|
||||
}
|
||||
|
||||
bool nfc_configure(dev_info* pdi, const dev_config_option dco, const bool bEnable)
|
||||
{
|
||||
byte btValue;
|
||||
|
||||
// Make sure we are dealing with a active device
|
||||
if (!pdi->bActive) return false;
|
||||
|
||||
switch(dco)
|
||||
{
|
||||
case DCO_HANDLE_CRC:
|
||||
// Enable or disable automatic receiving/sending of CRC bytes
|
||||
// TX and RX are both represented by the symbol 0x80
|
||||
btValue = (bEnable) ? 0x80 : 0x00;
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_TX_MODE,SYMBOL_TX_CRC_ENABLE,btValue)) return false;
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_CRC_ENABLE,btValue)) return false;
|
||||
pdi->bCrc = bEnable;
|
||||
break;
|
||||
|
||||
case DCO_HANDLE_PARITY:
|
||||
// Handle parity bit by PN53X chip or parse it as data bit
|
||||
btValue = (bEnable) ? 0x00 : SYMBOL_PARITY_DISABLE;
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_MANUAL_RCV,SYMBOL_PARITY_DISABLE,btValue)) return false;
|
||||
pdi->bPar = bEnable;
|
||||
break;
|
||||
|
||||
case DCO_ACTIVATE_FIELD:
|
||||
pncmd_rf_configure_field[3] = (bEnable) ? 1 : 0;
|
||||
if (!pdi->pdc->transceive(pdi->ds,pncmd_rf_configure_field,4,null,null)) return false;
|
||||
break;
|
||||
|
||||
case DCO_ACTIVATE_CRYPTO1:
|
||||
btValue = (bEnable) ? SYMBOL_MF_CRYPTO1_ON : 0x00;
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_STATUS2,SYMBOL_MF_CRYPTO1_ON,btValue)) return false;
|
||||
break;
|
||||
|
||||
case DCO_INFINITE_SELECT:
|
||||
// Retry format: 0x00 means only 1 try, 0xff means infinite
|
||||
pncmd_rf_configure_retry_select[3] = (bEnable) ? 0xff : 0x00; // MxRtyATR, default: active = 0xff, passive = 0x02
|
||||
pncmd_rf_configure_retry_select[4] = (bEnable) ? 0xff : 0x00; // MxRtyPSL, default: 0x01
|
||||
pncmd_rf_configure_retry_select[5] = (bEnable) ? 0xff : 0x00; // MxRtyPassiveActivation, default: 0xff
|
||||
if(!pdi->pdc->transceive(pdi->ds,pncmd_rf_configure_retry_select,6,null,null)) return false;
|
||||
break;
|
||||
|
||||
case DCO_ACCEPT_INVALID_FRAMES:
|
||||
btValue = (bEnable) ? SYMBOL_RX_NO_ERROR : 0x00;
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_NO_ERROR,btValue)) return false;
|
||||
break;
|
||||
|
||||
case DCO_ACCEPT_MULTIPLE_FRAMES:
|
||||
btValue = (bEnable) ? SYMBOL_RX_MULTIPLE : 0x00;
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_MULTIPLE,btValue)) return false;
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// When we reach this, the configuration is completed and succesful
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_reader_init(const dev_info* pdi)
|
||||
{
|
||||
// Make sure we are dealing with a active device
|
||||
if (!pdi->bActive) return false;
|
||||
|
||||
// Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards)
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_TX_AUTO,SYMBOL_FORCE_100_ASK,0x40)) return false;
|
||||
|
||||
// Configure the PN53X to be an Initiator or Reader/Writer
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_CONTROL,SYMBOL_INITIATOR,0x10)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_reader_select(const dev_info* pdi, const init_modulation im, const byte* pbtInitData, const ui32 uiInitDataLen, tag_info* pti)
|
||||
{
|
||||
// Make sure we are dealing with a active device
|
||||
if (!pdi->bActive) return false;
|
||||
|
||||
pncmd_reader_list_passive[2] = 1; // MaxTg, we only want to select 1 tag at the time
|
||||
pncmd_reader_list_passive[3] = im; // BrTy, the type of init modulation used for polling a passive tag
|
||||
|
||||
// Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID).
|
||||
if (pbtInitData) memcpy(pncmd_reader_list_passive+4,pbtInitData,uiInitDataLen);
|
||||
|
||||
// Try to find a tag, call the tranceive callback function of the current device
|
||||
uiRxLen = MAX_FRAME_LEN;
|
||||
if (!pdi->pdc->transceive(pdi->ds,pncmd_reader_list_passive,4+uiInitDataLen,abtRx,&uiRxLen)) return false;
|
||||
|
||||
// Make sure one tag has been found, the PN53X returns 0x00 if none was available
|
||||
if (abtRx[0] != 1) return false;
|
||||
|
||||
// Is a tag info struct available
|
||||
if (pti)
|
||||
{
|
||||
// Fill the tag info struct with the values corresponding to this init modulation
|
||||
switch(im)
|
||||
{
|
||||
case IM_ISO14443A_106:
|
||||
// Somehow they switched the lower and upper ATQA bytes around for the PN531 chipset
|
||||
if (pdi->ct == CT_PN531)
|
||||
{
|
||||
pti->tia.abtAtqa[0] = abtRx[3];
|
||||
pti->tia.abtAtqa[1] = abtRx[2];
|
||||
} else {
|
||||
memcpy(pti->tia.abtAtqa,abtRx+2,2);
|
||||
}
|
||||
pti->tia.btSak = abtRx[4];
|
||||
// Copy the NFCID1
|
||||
pti->tia.uiUidLen = abtRx[5];
|
||||
memcpy(pti->tia.abtUid,abtRx+6,pti->tia.uiUidLen);
|
||||
// Did we received an optional ATS (Smardcard ATR)
|
||||
if (uiRxLen > pti->tia.uiUidLen+6)
|
||||
{
|
||||
pti->tia.uiAtsLen = abtRx[pti->tia.uiUidLen+6];
|
||||
memcpy(pti->tia.abtAts,abtRx+pti->tia.uiUidLen+6,pti->tia.uiAtsLen);
|
||||
} else {
|
||||
pti->tia.uiAtsLen = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case IM_FELICA_212:
|
||||
case IM_FELICA_424:
|
||||
// Store the mandatory info
|
||||
pti->tif.uiLen = abtRx[2];
|
||||
pti->tif.btResCode = abtRx[3];
|
||||
// Copy the NFCID2t
|
||||
memcpy(pti->tif.abtId,abtRx+4,8);
|
||||
// Copy the felica padding
|
||||
memcpy(pti->tif.abtPad,abtRx+12,8);
|
||||
// Test if the System code (SYST_CODE) is available
|
||||
if (uiRxLen > 20)
|
||||
{
|
||||
memcpy(pti->tif.abtSysCode,abtRx+20,2);
|
||||
}
|
||||
break;
|
||||
|
||||
case IM_ISO14443B_106:
|
||||
// Store the mandatory info
|
||||
memcpy(pti->tib.abtAtqb,abtRx+2,12);
|
||||
// Ignore the 0x1D byte, and just store the 4 byte id
|
||||
memcpy(pti->tib.abtId,abtRx+15,4);
|
||||
pti->tib.btParam1 = abtRx[19];
|
||||
pti->tib.btParam2 = abtRx[20];
|
||||
pti->tib.btParam3 = abtRx[21];
|
||||
pti->tib.btParam4 = abtRx[22];
|
||||
// Test if the Higher layer (INF) is available
|
||||
if (uiRxLen > 22)
|
||||
{
|
||||
pti->tib.uiInfLen = abtRx[23];
|
||||
memcpy(pti->tib.abtInf,abtRx+24,pti->tib.uiInfLen);
|
||||
} else {
|
||||
pti->tib.uiInfLen = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case IM_JEWEL_106:
|
||||
// Store the mandatory info
|
||||
memcpy(pti->tij.btSensRes,abtRx+2,2);
|
||||
memcpy(pti->tij.btId,abtRx+4,4);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Should not be possible, so whatever...
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_reader_deselect(const dev_info* pdi)
|
||||
{
|
||||
return (pdi->pdc->transceive(pdi->ds,pncmd_reader_deselect,3,null,null));
|
||||
}
|
||||
|
||||
bool nfc_reader_transceive_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
|
||||
{
|
||||
ui32 uiFrameBits = 0;
|
||||
ui32 uiFrameBytes = 0;
|
||||
ui8 ui8Bits = 0;
|
||||
|
||||
// Check if we should prepare the parity bits ourself
|
||||
if (!pdi->bPar)
|
||||
{
|
||||
// Convert data with parity to a frame
|
||||
pn53x_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_exchange_raw_data+2,&uiFrameBits);
|
||||
} else {
|
||||
uiFrameBits = uiTxBits;
|
||||
}
|
||||
|
||||
// Retrieve the leading bits
|
||||
ui8Bits = uiFrameBits%8;
|
||||
|
||||
// Get the amount of frame bytes + optional (1 byte if there are leading bits)
|
||||
uiFrameBytes = (uiFrameBits/8)+((ui8Bits==0)?0:1);
|
||||
|
||||
// When the parity is handled before us, we just copy the data
|
||||
if (pdi->bPar) memcpy(pncmd_exchange_raw_data+2,pbtTx,uiFrameBytes);
|
||||
|
||||
// Set the amount of transmission bits in the PN53X chip register
|
||||
if (!pn53x_set_tx_bits(pdi,ui8Bits)) return false;
|
||||
|
||||
// Send the frame to the PN53X chip and get the answer
|
||||
// We have to give the amount of bytes + (the two command bytes 0xD4, 0x42)
|
||||
if (!pn53x_transceive(pdi,pncmd_exchange_raw_data,uiFrameBytes+2)) return false;
|
||||
|
||||
// Get the last bit-count that is stored in the received byte
|
||||
ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
|
||||
|
||||
// Recover the real frame length in bits
|
||||
uiFrameBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
|
||||
|
||||
// Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive()
|
||||
// Check if we should recover the parity bits ourself
|
||||
if (!pdi->bPar)
|
||||
{
|
||||
// Unwrap the response frame
|
||||
pn53x_unwrap_frame(abtRx+1,uiFrameBits,pbtRx,puiRxBits,pbtRxPar);
|
||||
} else {
|
||||
// Save the received bits
|
||||
*puiRxBits = uiFrameBits;
|
||||
// Copy the received bytes
|
||||
memcpy(pbtRx,abtRx+1,uiRxLen-1);
|
||||
}
|
||||
|
||||
// Everything went successful
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_reader_transceive_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
|
||||
{
|
||||
// We can not just send bytes without parity if while the PN53X expects we handled them
|
||||
if (!pdi->bPar) return false;
|
||||
|
||||
// Copy the data into the command frame
|
||||
memcpy(pncmd_exchange_raw_data+2,pbtTx,uiTxLen);
|
||||
|
||||
// To transfer command frames bytes we can not have any leading bits, reset this to zero
|
||||
if (!pn53x_set_tx_bits(pdi,0)) return false;
|
||||
|
||||
// Send the frame to the PN53X chip and get the answer
|
||||
// We have to give the amount of bytes + (the two command bytes 0xD4, 0x42)
|
||||
if (!pn53x_transceive(pdi,pncmd_exchange_raw_data,uiTxLen+2)) return false;
|
||||
|
||||
// Save the received byte count
|
||||
*puiRxLen = uiRxLen-1;
|
||||
|
||||
// Copy the received bytes
|
||||
memcpy(pbtRx,abtRx+1,*puiRxLen);
|
||||
|
||||
// Everything went successful
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_reader_mifare_cmd(const dev_info* pdi, const mifare_cmd mc, const ui8 ui8Block, mifare_param* pmp)
|
||||
{
|
||||
ui32 uiParamLen;
|
||||
|
||||
// Make sure we are dealing with a active device
|
||||
if (!pdi->bActive) return false;
|
||||
|
||||
pncmd_reader_exchange_data[2] = 0x01; // Use first target/card
|
||||
pncmd_reader_exchange_data[3] = mc; // The MIFARE Classic command
|
||||
pncmd_reader_exchange_data[4] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
||||
|
||||
switch (mc)
|
||||
{
|
||||
// Read and store command have no parameter
|
||||
case MC_READ:
|
||||
case MC_STORE:
|
||||
uiParamLen = 0;
|
||||
break;
|
||||
|
||||
// Authenticate command
|
||||
case MC_AUTH_A:
|
||||
case MC_AUTH_B:
|
||||
uiParamLen = sizeof(mifare_param_auth);
|
||||
break;
|
||||
|
||||
// Data command
|
||||
case MC_WRITE:
|
||||
uiParamLen = sizeof(mifare_param_data);
|
||||
break;
|
||||
|
||||
// Value command
|
||||
case MC_DECREMENT:
|
||||
case MC_INCREMENT:
|
||||
case MC_TRANSFER:
|
||||
uiParamLen = sizeof(mifare_param_value);
|
||||
break;
|
||||
|
||||
// Please fix your code, you never should reach this statement
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
// When available, copy the parameter bytes
|
||||
if (uiParamLen) memcpy(pncmd_reader_exchange_data+5,(byte*)pmp,uiParamLen);
|
||||
|
||||
// Fire the mifare command
|
||||
if (!pn53x_transceive(pdi,pncmd_reader_exchange_data,5+uiParamLen)) return false;
|
||||
|
||||
// When we have executed a read command, copy the received bytes into the param
|
||||
if (mc == MC_READ) memcpy(pmp->mpd.abtData,abtRx+1,16);
|
||||
|
||||
// Command succesfully executed
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_target_init(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits)
|
||||
{
|
||||
ui8 ui8Bits;
|
||||
|
||||
// Save the current configuration settings
|
||||
bool bCrc = pdi->bCrc;
|
||||
bool bPar = pdi->bPar;
|
||||
|
||||
// Clear the target init struct, reset to all zeros
|
||||
memset(pncmd_target_init+2,0x00,37);
|
||||
|
||||
// Set ATQA (SENS_RES)
|
||||
pncmd_target_init[3] = 0x04;
|
||||
pncmd_target_init[4] = 0x00;
|
||||
|
||||
// Set SAK (SEL_RES)
|
||||
pncmd_target_init[8] = 0x20;
|
||||
|
||||
// Set UID
|
||||
pncmd_target_init[5] = 0x00;
|
||||
pncmd_target_init[6] = 0xb0;
|
||||
pncmd_target_init[7] = 0x0b;
|
||||
|
||||
// Make sure the CRC & parity are handled by the device, this is needed for target_init to work properly
|
||||
if (!bCrc) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,true);
|
||||
if (!bPar) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,true);
|
||||
|
||||
// Let the PN53X be activated by the RF level detector from power down mode
|
||||
if (!pn53x_set_reg(pdi,REG_CIU_TX_AUTO, SYMBOL_INITIAL_RF_ON,0x04)) return false;
|
||||
|
||||
// Request the initialization as a target, we can not use pn53x_transceive() because
|
||||
// abtRx[0] contains the emulation mode (baudrate, 14443-4?, DEP and framing type)
|
||||
uiRxLen = MAX_FRAME_LEN;
|
||||
if (!pdi->pdc->transceive(pdi->ds,pncmd_target_init,39,abtRx,&uiRxLen)) return false;
|
||||
|
||||
// Get the last bit-count that is stored in the received byte
|
||||
ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
|
||||
|
||||
// We are sure the parity is handled by the PN53X chip, so we handle it this way
|
||||
*puiRxBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
|
||||
// Copy the received bytes
|
||||
memcpy(pbtRx,abtRx+1,uiRxLen-1);
|
||||
|
||||
// Restore the CRC & parity setting to the original value (if needed)
|
||||
if (!bCrc) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,false);
|
||||
if (!bPar) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_target_receive_bits(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar)
|
||||
{
|
||||
ui32 uiFrameBits;
|
||||
ui8 ui8Bits;
|
||||
|
||||
// Try to gather a received frame from the reader
|
||||
if (!pn53x_transceive(pdi,pncmd_target_receive,2)) return false;
|
||||
|
||||
// Get the last bit-count that is stored in the received byte
|
||||
ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS;
|
||||
|
||||
// Recover the real frame length in bits
|
||||
uiFrameBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits;
|
||||
|
||||
// Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive()
|
||||
// Check if we should recover the parity bits ourself
|
||||
if (!pdi->bPar)
|
||||
{
|
||||
// Unwrap the response frame
|
||||
pn53x_unwrap_frame(abtRx+1,uiFrameBits,pbtRx,puiRxBits,pbtRxPar);
|
||||
} else {
|
||||
// Save the received bits
|
||||
*puiRxBits = uiFrameBits;
|
||||
// Copy the received bytes
|
||||
memcpy(pbtRx,abtRx+1,uiRxLen-1);
|
||||
}
|
||||
// Everyting seems ok, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_target_receive_bytes(const dev_info* pdi, byte* pbtRx, ui32* puiRxLen)
|
||||
{
|
||||
// Try to gather a received frame from the reader
|
||||
if (!pn53x_transceive(pdi,pncmd_target_receive,2)) return false;
|
||||
|
||||
// Save the received byte count
|
||||
*puiRxLen = uiRxLen-1;
|
||||
|
||||
// Copy the received bytes
|
||||
memcpy(pbtRx,abtRx+1,*puiRxLen);
|
||||
|
||||
// Everyting seems ok, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nfc_target_send_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar)
|
||||
{
|
||||
ui32 uiFrameBits = 0;
|
||||
ui32 uiFrameBytes = 0;
|
||||
ui8 ui8Bits = 0;
|
||||
|
||||
// Check if we should prepare the parity bits ourself
|
||||
if (!pdi->bPar)
|
||||
{
|
||||
// Convert data with parity to a frame
|
||||
pn53x_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_target_send+2,&uiFrameBits);
|
||||
} else {
|
||||
uiFrameBits = uiTxBits;
|
||||
}
|
||||
|
||||
// Retrieve the leading bits
|
||||
ui8Bits = uiFrameBits%8;
|
||||
|
||||
// Get the amount of frame bytes + optional (1 byte if there are leading bits)
|
||||
uiFrameBytes = (uiFrameBits/8)+((ui8Bits==0)?0:1);
|
||||
|
||||
// When the parity is handled before us, we just copy the data
|
||||
if (pdi->bPar) memcpy(pncmd_target_send+2,pbtTx,uiFrameBytes);
|
||||
|
||||
// Set the amount of transmission bits in the PN53X chip register
|
||||
if (!pn53x_set_tx_bits(pdi,ui8Bits)) return false;
|
||||
|
||||
// Try to send the bits to the reader
|
||||
if (!pn53x_transceive(pdi,pncmd_target_send,uiFrameBytes+2)) return false;
|
||||
|
||||
// Everyting seems ok, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool nfc_target_send_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen)
|
||||
{
|
||||
// We can not just send bytes without parity if while the PN53X expects we handled them
|
||||
if (!pdi->bPar) return false;
|
||||
|
||||
// Copy the data into the command frame
|
||||
memcpy(pncmd_target_send+2,pbtTx,uiTxLen);
|
||||
|
||||
// Try to send the bits to the reader
|
||||
if (!pn53x_transceive(pdi,pncmd_target_send,uiTxLen+2)) return false;
|
||||
|
||||
// Everyting seems ok, return true
|
||||
return true;
|
||||
}
|
||||
47
src/libnfc.h
Normal file
47
src/libnfc.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_H_
|
||||
#define _LIBNFC_H_
|
||||
|
||||
#include "defines.h"
|
||||
#include "types.h"
|
||||
#include "bitutils.h"
|
||||
#include "devices.h"
|
||||
|
||||
dev_info* nfc_connect();
|
||||
void nfc_disconnect(dev_info* pdi);
|
||||
bool nfc_configure(dev_info* pdi, const dev_config_option dco, const bool bEnable);
|
||||
|
||||
bool nfc_reader_init(const dev_info* pdi);
|
||||
bool nfc_reader_select(const dev_info* pdi, const init_modulation im, const byte* pbtInitData, const ui32 uiInitDataLen, tag_info* pti);
|
||||
bool nfc_reader_deselect(const dev_info* pdi);
|
||||
bool nfc_reader_transceive_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar);
|
||||
bool nfc_reader_transceive_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
|
||||
bool nfc_reader_mifare_cmd(const dev_info* pdi, const mifare_cmd mc, const ui8 ui8Block, mifare_param* pmp);
|
||||
|
||||
bool nfc_target_init(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits);
|
||||
bool nfc_target_receive_bits(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar);
|
||||
bool nfc_target_receive_bytes(const dev_info* pdi, byte* pbtRx, ui32* puiRxLen);
|
||||
bool nfc_target_send_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar);
|
||||
bool nfc_target_send_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen);
|
||||
|
||||
#endif // _LIBNFC_H_
|
||||
|
||||
96
src/list.c
Normal file
96
src/list.c
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libnfc.h"
|
||||
|
||||
static dev_info* pdi;
|
||||
static byte abtFelica[5] = { 0x00, 0xff, 0xff, 0x00, 0x00 };
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
tag_info ti;
|
||||
|
||||
// Try to open the NFC reader
|
||||
pdi = nfc_connect();
|
||||
|
||||
if (pdi == INVALID_DEVICE_INFO)
|
||||
{
|
||||
printf("Error connecting NFC reader\n");
|
||||
return 1;
|
||||
}
|
||||
nfc_reader_init(pdi);
|
||||
|
||||
// Drop the field for a while
|
||||
nfc_configure(pdi,DCO_ACTIVATE_FIELD,false);
|
||||
|
||||
// Let the reader only try once to find a tag
|
||||
nfc_configure(pdi,DCO_INFINITE_SELECT,false);
|
||||
|
||||
// Configure the CRC and Parity settings
|
||||
nfc_configure(pdi,DCO_HANDLE_CRC,true);
|
||||
nfc_configure(pdi,DCO_HANDLE_PARITY,true);
|
||||
|
||||
// Enable field so more power consuming cards can power themselves up
|
||||
nfc_configure(pdi,DCO_ACTIVATE_FIELD,true);
|
||||
|
||||
printf("\nConnected to NFC reader: %s\n\n",pdi->acName);
|
||||
|
||||
// Poll for a ISO14443A (MIFARE) tag
|
||||
if (nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
|
||||
{
|
||||
printf("The following (NFC) ISO14443A tag was found:\n\n");
|
||||
printf(" ATQA (SENS_RES): "); print_hex(ti.tia.abtAtqa,2);
|
||||
printf(" UID (NFCID%c): ",(ti.tia.abtUid[0]==0x08?'3':'1')); print_hex(ti.tia.abtUid,ti.tia.uiUidLen);
|
||||
printf(" SAK (SEL_RES): "); print_hex(&ti.tia.btSak,1);
|
||||
if (ti.tia.uiAtsLen)
|
||||
{
|
||||
printf(" ATS (ATR): ");
|
||||
print_hex(ti.tia.abtAts,ti.tia.uiAtsLen);
|
||||
}
|
||||
}
|
||||
|
||||
// Poll for a Felica tag
|
||||
if (nfc_reader_select(pdi,IM_FELICA_212,abtFelica,5,&ti) || nfc_reader_select(pdi,IM_FELICA_424,abtFelica,5,&ti))
|
||||
{
|
||||
printf("The following (NFC) Felica tag was found:\n\n");
|
||||
printf("%18s","ID (NFCID2): "); print_hex(ti.tif.abtId,8);
|
||||
printf("%18s","Parameter (PAD): "); print_hex(ti.tif.abtPad,8);
|
||||
}
|
||||
|
||||
// Poll for a ISO14443B tag
|
||||
if (nfc_reader_select(pdi,IM_ISO14443B_106,null,null,&ti))
|
||||
{
|
||||
// No test results yet
|
||||
printf("iso14443b\n");
|
||||
}
|
||||
|
||||
// Poll for a Jewel tag
|
||||
if (nfc_reader_select(pdi,IM_JEWEL_106,null,null,&ti))
|
||||
{
|
||||
// No test results yet
|
||||
printf("jewel\n");
|
||||
}
|
||||
|
||||
nfc_disconnect(pdi);
|
||||
return 1;
|
||||
}
|
||||
374
src/mftool.c
Normal file
374
src/mftool.c
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "libnfc.h"
|
||||
#include "mifaretag.h"
|
||||
|
||||
static dev_info* pdi;
|
||||
static tag_info ti;
|
||||
static mifare_param mp;
|
||||
static mifare_tag mtKeys;
|
||||
static mifare_tag mtDump;
|
||||
static bool bUseKeyA;
|
||||
static ui32 uiBlocks;
|
||||
|
||||
bool is_first_block(ui32 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(ui32 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);
|
||||
}
|
||||
|
||||
ui32 get_trailer_block(ui32 uiFirstBlock)
|
||||
{
|
||||
// Test if we are in the small or big sectors
|
||||
if (uiFirstBlock<128) return uiFirstBlock+3; else return uiFirstBlock+15;
|
||||
}
|
||||
|
||||
bool read_card()
|
||||
{
|
||||
i32 iBlock;
|
||||
mifare_cmd mc;
|
||||
bool bFailure = false;
|
||||
|
||||
printf("Reading out %d blocks |",uiBlocks+1);
|
||||
|
||||
// Read the card from end to begin
|
||||
for (iBlock=uiBlocks; iBlock>=0; iBlock--)
|
||||
{
|
||||
// Authenticate everytime we reach a trailer block
|
||||
if (is_trailer_block(iBlock))
|
||||
{
|
||||
// Show if the readout went well
|
||||
if (bFailure)
|
||||
{
|
||||
printf("x");
|
||||
// When a failure occured we need to redo the anti-collision
|
||||
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
|
||||
{
|
||||
printf("!\nError: tag was removed\n");
|
||||
return 1;
|
||||
}
|
||||
bFailure = false;
|
||||
} else {
|
||||
// Skip this the first time, bFailure it means nothing (yet)
|
||||
if (iBlock != uiBlocks)
|
||||
{
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
// Set the authentication information (uid)
|
||||
memcpy(mp.mpa.abtUid,ti.tia.abtUid,4);
|
||||
|
||||
// Determin if we should use the a or the b key
|
||||
if (bUseKeyA)
|
||||
{
|
||||
mc = MC_AUTH_A;
|
||||
memcpy(mp.mpa.abtKey,mtKeys.amb[iBlock].mbt.abtKeyA,6);
|
||||
} else {
|
||||
mc = MC_AUTH_B;
|
||||
memcpy(mp.mpa.abtKey,mtKeys.amb[iBlock].mbt.abtKeyB,6);
|
||||
}
|
||||
|
||||
// Try to authenticate for the current sector
|
||||
if (!nfc_reader_mifare_cmd(pdi,MC_AUTH_A,iBlock,&mp))
|
||||
{
|
||||
printf("!\nError: authentication failed for block %02x\n",iBlock);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to read out the trailer
|
||||
if (nfc_reader_mifare_cmd(pdi,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_reader_mifare_cmd(pdi,MC_READ,iBlock,&mp))
|
||||
{
|
||||
memcpy(mtDump.amb[iBlock].mbd.abtData,mp.mpd.abtData,16);
|
||||
} else {
|
||||
bFailure = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%c|\n",(bFailure)?'x':'.');
|
||||
fflush(stdout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_card()
|
||||
{
|
||||
ui32 uiBlock;
|
||||
ui32 uiTrailerBlock;
|
||||
bool bFailure = false;
|
||||
mifare_cmd mc;
|
||||
|
||||
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))
|
||||
{
|
||||
// Show if the readout went well
|
||||
if (bFailure)
|
||||
{
|
||||
printf("x");
|
||||
// When a failure occured we need to redo the anti-collision
|
||||
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
|
||||
{
|
||||
printf("!\nError: tag was removed\n");
|
||||
return false;
|
||||
}
|
||||
bFailure = false;
|
||||
} else {
|
||||
// Skip this the first time, bFailure it means nothing (yet)
|
||||
if (uiBlock != 0)
|
||||
{
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
// Locate the trailer (with the keys) used for this sector
|
||||
uiTrailerBlock = get_trailer_block(uiBlock);
|
||||
|
||||
// Set the authentication information (uid)
|
||||
memcpy(mp.mpa.abtUid,ti.tia.abtUid,4);
|
||||
|
||||
// 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_reader_mifare_cmd(pdi,mc,uiBlock,&mp))
|
||||
{
|
||||
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
|
||||
nfc_reader_mifare_cmd(pdi,MC_WRITE,uiBlock,&mp);
|
||||
|
||||
} 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_reader_mifare_cmd(pdi,MC_WRITE,uiBlock,&mp)) bFailure = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%c|\n",(bFailure)?'x':'.');
|
||||
fflush(stdout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
bool b4K;
|
||||
bool bReadAction;
|
||||
byte* pbtUID;
|
||||
FILE* pfKeys;
|
||||
FILE* pfDump;
|
||||
|
||||
if (argc < 5)
|
||||
{
|
||||
printf("\n");
|
||||
printf("mftool <r|w> <a|b> <keys.mfd> <dump.mfd>\n");
|
||||
printf("\n");
|
||||
printf("<r|w> - Perform (read from) or (write to) card\n");
|
||||
printf("<a|b> - Use A or B keys to for action\n");
|
||||
printf("<keys.mfd> - Mifare-dump that contain the keys\n");
|
||||
printf("<dump.mfd> - Used to write (card to file) or (file to card)\n");
|
||||
printf("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\nChecking arguments and settings\n");
|
||||
|
||||
bReadAction = (tolower(*(argv[1])) == 'r');
|
||||
bUseKeyA = (tolower(*(argv[2])) == 'a');
|
||||
|
||||
pfKeys = fopen(argv[3],"rb");
|
||||
if (pfKeys == null)
|
||||
{
|
||||
printf("Could not open file: %s\n",argv[3]);
|
||||
return 1;
|
||||
}
|
||||
if (fread(&mtKeys,1,sizeof(mtKeys),pfKeys) != sizeof(mtKeys))
|
||||
{
|
||||
printf("Could not read from keys file: %s\n",argv[3]);
|
||||
fclose(pfKeys);
|
||||
return 1;
|
||||
}
|
||||
fclose(pfKeys);
|
||||
|
||||
if (bReadAction)
|
||||
{
|
||||
memset(&mtDump,0x00,sizeof(mtDump));
|
||||
} else {
|
||||
pfDump = fopen(argv[4],"rb");
|
||||
|
||||
if (pfDump == null)
|
||||
{
|
||||
printf("Could not open dump file: %s\n",argv[4]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fread(&mtDump,1,sizeof(mtDump),pfDump) != sizeof(mtDump))
|
||||
{
|
||||
printf("Could not read from dump file: %s\n",argv[4]);
|
||||
fclose(pfDump);
|
||||
return 1;
|
||||
}
|
||||
fclose(pfDump);
|
||||
}
|
||||
printf("Succesful opened MIFARE the required files\n");
|
||||
|
||||
// Try to open the NFC reader
|
||||
pdi = nfc_connect();
|
||||
if (pdi == INVALID_DEVICE_INFO)
|
||||
{
|
||||
printf("Error connecting NFC reader\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
nfc_reader_init(pdi);
|
||||
|
||||
// Drop the field for a while
|
||||
nfc_configure(pdi,DCO_ACTIVATE_FIELD,false);
|
||||
|
||||
// Let the reader only try once to find a tag
|
||||
nfc_configure(pdi,DCO_INFINITE_SELECT,false);
|
||||
nfc_configure(pdi,DCO_HANDLE_CRC,true);
|
||||
nfc_configure(pdi,DCO_HANDLE_PARITY,true);
|
||||
|
||||
// Enable field so more power consuming cards can power themselves up
|
||||
nfc_configure(pdi,DCO_ACTIVATE_FIELD,true);
|
||||
|
||||
printf("Connected to NFC reader: %s\n",pdi->acName);
|
||||
|
||||
// Try to find a MIFARE Classic tag
|
||||
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
|
||||
{
|
||||
printf("Error: no tag was found\n");
|
||||
nfc_disconnect(pdi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Test if we are dealing with a MIFARE compatible tag
|
||||
if ((ti.tia.btSak & 0x08) == 0)
|
||||
{
|
||||
printf("Error: tag is not a MIFARE Classic card\n");
|
||||
nfc_disconnect(pdi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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(ti.tia.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 = ti.tia.abtUid;
|
||||
b4K = (ti.tia.abtAtqa[1] == 0x02);
|
||||
printf("Found MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
|
||||
|
||||
uiBlocks = (b4K)?0xff:0x3f;
|
||||
|
||||
if (bReadAction)
|
||||
{
|
||||
if (read_card())
|
||||
{
|
||||
printf("Writing data to file: %s\n",argv[4]);
|
||||
fflush(stdout);
|
||||
pfDump = fopen(argv[4],"wb");
|
||||
if (pfKeys == null)
|
||||
{
|
||||
printf("Could not open file: %s\n",argv[4]);
|
||||
return 1;
|
||||
}
|
||||
if (fwrite(&mtDump,1,sizeof(mtDump),pfDump) != sizeof(mtDump))
|
||||
{
|
||||
printf("Could not write to file: %s\n",argv[4]);
|
||||
return 1;
|
||||
}
|
||||
fclose(pfDump);
|
||||
printf("Done, all bytes dumped to file!\n");
|
||||
}
|
||||
} else {
|
||||
if (write_card())
|
||||
{
|
||||
printf("Done, all data is written to the card!\n");
|
||||
}
|
||||
}
|
||||
|
||||
nfc_disconnect(pdi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
54
src/mifaretag.h
Normal file
54
src/mifaretag.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_MIFARE_TAG_H_
|
||||
#define _LIBNFC_MIFARE_TAG_H_
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
typedef struct {
|
||||
byte abtUID[4];
|
||||
byte btBCC;
|
||||
byte btUnknown;
|
||||
byte abtATQA[2];
|
||||
byte abtUnknown[8];
|
||||
} mifare_block_manufacturer;
|
||||
|
||||
typedef struct {
|
||||
byte abtData[16];
|
||||
} mifare_block_data;
|
||||
|
||||
typedef struct {
|
||||
byte abtKeyA[6];
|
||||
byte abtAccessBits[4];
|
||||
byte 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_
|
||||
99
src/relay.c
Normal file
99
src/relay.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libnfc.h"
|
||||
|
||||
static byte abtReaderRx[MAX_FRAME_LEN];
|
||||
static byte abtReaderRxPar[MAX_FRAME_LEN];
|
||||
static ui32 uiReaderRxBits;
|
||||
static byte abtTagRx[MAX_FRAME_LEN];
|
||||
static byte abtTagRxPar[MAX_FRAME_LEN];
|
||||
static ui32 uiTagRxBits;
|
||||
static dev_info* pdiReader;
|
||||
static dev_info* pdiTag;
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
// Try to open the NFC emulator device
|
||||
pdiTag = nfc_connect();
|
||||
if (pdiTag == INVALID_DEVICE_INFO)
|
||||
{
|
||||
printf("Error connecting NFC emulator device\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("[+] Connected to the NFC emulator device\n");
|
||||
printf("[+] Try to break out the auto-simulation, 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 \"anticol\" tool\n");
|
||||
nfc_target_init(pdiTag,abtReaderRx,&uiReaderRxBits);
|
||||
printf("[+] Configuring emulator settings\n");
|
||||
nfc_configure(pdiTag,DCO_HANDLE_CRC,false);
|
||||
nfc_configure(pdiTag,DCO_HANDLE_PARITY,false);
|
||||
nfc_configure(pdiTag,DCO_ACCEPT_INVALID_FRAMES,true);
|
||||
printf("[+] Thank you, the emulated tag is initialized\n");
|
||||
|
||||
// Try to open the NFC reader
|
||||
pdiReader = INVALID_DEVICE_INFO;
|
||||
while (pdiReader == INVALID_DEVICE_INFO) pdiReader = nfc_connect();
|
||||
printf("[+] Configuring NFC reader settings\n");
|
||||
nfc_configure(pdiReader,DCO_HANDLE_CRC,false);
|
||||
nfc_configure(pdiReader,DCO_HANDLE_PARITY,false);
|
||||
nfc_configure(pdiReader,DCO_ACCEPT_INVALID_FRAMES,true);
|
||||
printf("[+] Done, relaying frames now!\n\n");
|
||||
|
||||
while(true)
|
||||
{
|
||||
// Test if we received a frame from the reader
|
||||
if (nfc_target_receive_bits(pdiTag,abtReaderRx,&uiReaderRxBits,abtReaderRxPar))
|
||||
{
|
||||
// Drop down the field before sending a REQA command and start a new session
|
||||
if (uiReaderRxBits == 7 && abtReaderRx[0] == 0x26)
|
||||
{
|
||||
// Drop down field for a very short time (original tag will reboot)
|
||||
nfc_configure(pdiReader,DCO_ACTIVATE_FIELD,false);
|
||||
printf("\n");
|
||||
nfc_configure(pdiReader,DCO_ACTIVATE_FIELD,true);
|
||||
}
|
||||
|
||||
// Print the reader frame to the screen
|
||||
printf("R: ");
|
||||
print_hex_par(abtReaderRx,uiReaderRxBits,abtReaderRxPar);
|
||||
|
||||
// Forward the frame to the original tag
|
||||
if (nfc_reader_transceive_bits(pdiReader,abtReaderRx,uiReaderRxBits,abtReaderRxPar,abtTagRx,&uiTagRxBits,abtTagRxPar))
|
||||
{
|
||||
// Redirect the answer back to the reader
|
||||
nfc_target_send_bits(pdiTag,abtTagRx,uiTagRxBits,abtTagRxPar);
|
||||
|
||||
// Print the tag frame to the screen
|
||||
printf("T: ");
|
||||
print_hex_par(abtTagRx,uiTagRxBits,abtTagRxPar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nfc_disconnect(pdiTag);
|
||||
nfc_disconnect(pdiReader);
|
||||
}
|
||||
159
src/types.h
Normal file
159
src/types.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
|
||||
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 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 General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_TYPES_H_
|
||||
#define _LIBNFC_TYPES_H_
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
// Compiler directive, set struct alignment to 1 byte for compatibility
|
||||
#pragma pack(1)
|
||||
|
||||
typedef enum {
|
||||
false = 0x00,
|
||||
true = 0x01
|
||||
} bool;
|
||||
|
||||
typedef enum {
|
||||
CT_PN531 = 0x10,
|
||||
CT_PN532 = 0x20,
|
||||
CT_PN533 = 0x30,
|
||||
} chip_type;
|
||||
|
||||
struct dev_callbacks; // Prototype the callback struct
|
||||
|
||||
typedef struct {
|
||||
const struct dev_callbacks* pdc; // Callback functions for handling device specific wrapping
|
||||
char acName[DEVICE_NAME_LENGTH]; // Device name string, including device wrapper firmware
|
||||
chip_type ct; // PN53X chip type, this is useful for some "bug" work-arounds
|
||||
dev_spec ds; // Pointer to the device connection specification
|
||||
bool bActive; // This represents if the PN53X device was initialized succesful
|
||||
bool bCrc; // Is the crc automaticly added, checked and removed from the frames
|
||||
bool bPar; // Does the PN53x chip handles parity bits, all parities are handled as data
|
||||
ui8 ui8TxBits; // The last tx bits setting, we need to reset this if it does not apply anymore
|
||||
} dev_info;
|
||||
|
||||
struct dev_callbacks {
|
||||
const char* acDriver; // Driver description
|
||||
dev_info* (*connect)(const ui32 uiIndex);
|
||||
bool (*transceive)(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
|
||||
void (*disconnect)(dev_info* pdi);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
DCO_HANDLE_CRC = 0x00,
|
||||
DCO_HANDLE_PARITY = 0x01,
|
||||
DCO_ACTIVATE_FIELD = 0x10,
|
||||
DCO_ACTIVATE_CRYPTO1 = 0x11,
|
||||
DCO_INFINITE_SELECT = 0x20,
|
||||
DCO_ACCEPT_INVALID_FRAMES = 0x30,
|
||||
DCO_ACCEPT_MULTIPLE_FRAMES = 0x31
|
||||
}dev_config_option;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// nfc_reader_list_passive - using InListPassiveTarget
|
||||
|
||||
typedef enum {
|
||||
IM_ISO14443A_106 = 0x00,
|
||||
IM_FELICA_212 = 0x01,
|
||||
IM_FELICA_424 = 0x02,
|
||||
IM_ISO14443B_106 = 0x03,
|
||||
IM_JEWEL_106 = 0x04
|
||||
}init_modulation;
|
||||
|
||||
typedef struct {
|
||||
byte abtAtqa[2];
|
||||
byte btSak;
|
||||
ui32 uiUidLen;
|
||||
byte abtUid[10];
|
||||
ui32 uiAtsLen;
|
||||
byte abtAts[36];
|
||||
}tag_info_iso14443a;
|
||||
|
||||
typedef struct {
|
||||
ui32 uiLen;
|
||||
byte btResCode;
|
||||
byte abtId[8];
|
||||
byte abtPad[8];
|
||||
byte abtSysCode[2];
|
||||
}tag_info_felica;
|
||||
|
||||
typedef struct {
|
||||
byte abtAtqb[12];
|
||||
byte abtId[4];
|
||||
byte btParam1;
|
||||
byte btParam2;
|
||||
byte btParam3;
|
||||
byte btParam4;
|
||||
byte btCid;
|
||||
ui32 uiInfLen;
|
||||
byte abtInf[64];
|
||||
}tag_info_iso14443b;
|
||||
|
||||
typedef struct {
|
||||
byte btSensRes[2];
|
||||
byte btId[4];
|
||||
}tag_info_jewel;
|
||||
|
||||
typedef union {
|
||||
tag_info_iso14443a tia;
|
||||
tag_info_felica tif;
|
||||
tag_info_iso14443b tib;
|
||||
tag_info_jewel tij;
|
||||
}tag_info;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// InDataExchange, MIFARE Classic card
|
||||
|
||||
typedef enum {
|
||||
MC_AUTH_A = 0x60,
|
||||
MC_AUTH_B = 0x61,
|
||||
MC_READ = 0x30,
|
||||
MC_WRITE = 0xA0,
|
||||
MC_TRANSFER = 0xB0,
|
||||
MC_DECREMENT = 0xC0,
|
||||
MC_INCREMENT = 0xC1,
|
||||
MC_STORE = 0xC2,
|
||||
}mifare_cmd;
|
||||
|
||||
// MIFARE Classic command params
|
||||
typedef struct {
|
||||
byte abtKey[6];
|
||||
byte abtUid[4];
|
||||
}mifare_param_auth;
|
||||
|
||||
typedef struct {
|
||||
byte abtData[16];
|
||||
}mifare_param_data;
|
||||
|
||||
typedef struct {
|
||||
byte abtValue[4];
|
||||
}mifare_param_value;
|
||||
|
||||
typedef union {
|
||||
mifare_param_auth mpa;
|
||||
mifare_param_data mpd;
|
||||
mifare_param_value mpv;
|
||||
}mifare_param;
|
||||
|
||||
// Reset struct alignment to default
|
||||
#pragma pack()
|
||||
|
||||
#endif // _LIBNFC_TYPES_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue