Sync nfc-utils.* and mifare.* with current libnfc devel version

This commit is contained in:
romuald@libnfc.org 2012-09-23 10:34:32 +00:00
parent 1b6d022668
commit 1026af5d3f
4 changed files with 146 additions and 752 deletions

View File

@ -1,13 +1,13 @@
/*- /*-
* Public platform independent Near Field Communication (NFC) library examples * Public platform independent Near Field Communication (NFC) library examples
* *
* Copyright (C) 2009, Roel Verdult * Copyright (C) 2009, Roel Verdult
* Copyright (C) 2010, Romuald Conty, Romain Tartière * Copyright (C) 2010, Romuald Conty, Romain Tartière
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice, * 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright * 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
@ -23,11 +23,14 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
* *
* Note that this license only applies on the examples, NFC library itself is under LGPL * Note that this license only applies on the examples, NFC library itself is under LGPL
* *
*/ */
/**
* @file mifare.c
* @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc
*/
#include "mifare.h" #include "mifare.h"
#include <string.h> #include <string.h>
@ -42,85 +45,88 @@
* The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number. * The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number.
* @note There are three different types of information (Authenticate, Data and Value). * @note There are three different types of information (Authenticate, Data and Value).
* *
* First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID. * First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID.
* They are both used to initialize the internal cipher-state of the PN53X chip (http://libnfc.org/hardware/pn53x-chip). * They are both used to initialize the internal cipher-state of the PN53X chip (http://libnfc.org/hardware/pn53x-chip).
* After a successful authentication it will be possible to execute other commands (e.g. Read/Write). * After a successful authentication it will be possible to execute other commands (e.g. Read/Write).
* The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process. * The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process.
*/ */
bool bool
nfc_initiator_mifare_cmd (nfc_device_t * pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param * pmp) nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp)
{ {
byte_t abtRx[265]; uint8_t abtRx[265];
size_t szRx = sizeof(abtRx);
size_t szParamLen; size_t szParamLen;
byte_t abtCmd[265]; uint8_t abtCmd[265];
bool bEasyFraming; //bool bEasyFraming;
abtCmd[0] = mc; // The MIFARE Classic command abtCmd[0] = mc; // The MIFARE Classic command
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff) abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
switch (mc) { switch (mc) {
// Read and store command have no parameter // Read and store command have no parameter
case MC_READ: case MC_READ:
case MC_STORE: case MC_STORE:
szParamLen = 0; szParamLen = 0;
break; break;
// Authenticate command // Authenticate command
case MC_AUTH_A: case MC_AUTH_A:
case MC_AUTH_B: case MC_AUTH_B:
szParamLen = sizeof (mifare_param_auth); szParamLen = sizeof(struct mifare_param_auth);
break; break;
// Data command // Data command
case MC_WRITE: case MC_WRITE:
szParamLen = sizeof (mifare_param_data); szParamLen = sizeof(struct mifare_param_data);
break; break;
// Value command // Value command
case MC_DECREMENT: case MC_DECREMENT:
case MC_INCREMENT: case MC_INCREMENT:
case MC_TRANSFER: case MC_TRANSFER:
szParamLen = sizeof (mifare_param_value); szParamLen = sizeof(struct mifare_param_value);
break; break;
// Please fix your code, you never should reach this statement // Please fix your code, you never should reach this statement
default: default:
return false; return false;
break; break;
} }
// When available, copy the parameter bytes // When available, copy the parameter bytes
if (szParamLen) if (szParamLen)
memcpy (abtCmd + 2, (byte_t *) pmp, szParamLen); memcpy(abtCmd + 2, (uint8_t *) pmp, szParamLen);
bEasyFraming = pnd->bEasyFraming; // FIXME: Save and restore bEasyFraming
if (!nfc_configure (pnd, NDO_EASY_FRAMING, true)) { // bEasyFraming = nfc_device_get_property_bool (pnd, NP_EASY_FRAMING, &bEasyFraming);
nfc_perror (pnd, "nfc_configure"); if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool");
return false; return false;
} }
// Fire the mifare command // Fire the mifare command
if (!nfc_initiator_transceive_bytes (pnd, abtCmd, 2 + szParamLen, abtRx, &szRx, NULL)) { int res;
if (pnd->iLastError == EINVRXFRAM) { if ((res = nfc_initiator_transceive_bytes(pnd, abtCmd, 2 + szParamLen, abtRx, sizeof(abtRx), -1)) < 0) {
// "Invalid received frame" AKA EINVRXFRAM, usual means we are if (res == NFC_ERFTRANS) {
// "Invalid received frame", usual means we are
// authenticated on a sector but the requested MIFARE cmd (read, write) // authenticated on a sector but the requested MIFARE cmd (read, write)
// is not permitted by current acces bytes; // is not permitted by current acces bytes;
// So there is nothing to do here. // So there is nothing to do here.
} else { } else {
nfc_perror (pnd, "nfc_initiator_transceive_bytes"); nfc_perror(pnd, "nfc_initiator_transceive_bytes");
} }
nfc_configure (pnd, NDO_EASY_FRAMING, bEasyFraming); // XXX nfc_device_set_property_bool (pnd, NP_EASY_FRAMING, bEasyFraming);
return false; return false;
} }
if (!nfc_configure (pnd, NDO_EASY_FRAMING, bEasyFraming)) { /* XXX
nfc_perror (pnd, "nfc_configure"); if (nfc_device_set_property_bool (pnd, NP_EASY_FRAMING, bEasyFraming) < 0) {
nfc_perror (pnd, "nfc_device_set_property_bool");
return false; return false;
} }
*/
// When we have executed a read command, copy the received bytes into the param // When we have executed a read command, copy the received bytes into the param
if (mc == MC_READ) { if (mc == MC_READ) {
if (szRx == 16) { if (res == 16) {
memcpy (pmp->mpd.abtData, abtRx, 16); memcpy(pmp->mpd.abtData, abtRx, 16);
} else { } else {
return false; return false;
} }

View File

@ -1,13 +1,13 @@
/*- /*-
* Public platform independent Near Field Communication (NFC) library examples * Public platform independent Near Field Communication (NFC) library examples
* *
* Copyright (C) 2009, Roel Verdult * Copyright (C) 2009, Roel Verdult
* Copyright (C) 2010, Romuald Conty, Romain Tartière * Copyright (C) 2010, Romuald Conty, Romain Tartière
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice, * 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright * 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
@ -23,13 +23,13 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
* *
* Note that this license only applies on the examples, NFC library itself is under LGPL * Note that this license only applies on the examples, NFC library itself is under LGPL
* *
*/ */
/** /**
* @file mifaretag.h * @file mifare.h
* @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc * @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc
*/ */
@ -38,7 +38,7 @@
# include <nfc/nfc-types.h> # include <nfc/nfc-types.h>
// Compiler directive, set struct alignment to 1 byte_t for compatibility // Compiler directive, set struct alignment to 1 uint8_t for compatibility
# pragma pack(1) # pragma pack(1)
typedef enum { typedef enum {
@ -53,50 +53,50 @@ typedef enum {
} mifare_cmd; } mifare_cmd;
// MIFARE command params // MIFARE command params
typedef struct { struct mifare_param_auth {
byte_t abtKey[6]; uint8_t abtKey[6];
byte_t abtUid[4]; uint8_t abtAuthUid[4];
} mifare_param_auth; };
typedef struct { struct mifare_param_data {
byte_t abtData[16]; uint8_t abtData[16];
} mifare_param_data; };
typedef struct { struct mifare_param_value {
byte_t abtValue[4]; uint8_t abtValue[4];
} mifare_param_value; };
typedef union { typedef union {
mifare_param_auth mpa; struct mifare_param_auth mpa;
mifare_param_data mpd; struct mifare_param_data mpd;
mifare_param_value mpv; struct mifare_param_value mpv;
} mifare_param; } mifare_param;
// Reset struct alignment to default // Reset struct alignment to default
# pragma pack() # pragma pack()
bool nfc_initiator_mifare_cmd (nfc_device_t * pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param * pmp); bool nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp);
// Compiler directive, set struct alignment to 1 byte_t for compatibility // Compiler directive, set struct alignment to 1 uint8_t for compatibility
# pragma pack(1) # pragma pack(1)
// MIFARE Classic // MIFARE Classic
typedef struct { typedef struct {
byte_t abtUID[4]; uint8_t abtUID[4];
byte_t btBCC; uint8_t btBCC;
byte_t btUnknown; uint8_t btUnknown;
byte_t abtATQA[2]; uint8_t abtATQA[2];
byte_t abtUnknown[8]; uint8_t abtUnknown[8];
} mifare_classic_block_manufacturer; } mifare_classic_block_manufacturer;
typedef struct { typedef struct {
byte_t abtData[16]; uint8_t abtData[16];
} mifare_classic_block_data; } mifare_classic_block_data;
typedef struct { typedef struct {
byte_t abtKeyA[6]; uint8_t abtKeyA[6];
byte_t abtAccessBits[4]; uint8_t abtAccessBits[4];
byte_t abtKeyB[6]; uint8_t abtKeyB[6];
} mifare_classic_block_trailer; } mifare_classic_block_trailer;
typedef union { typedef union {
@ -111,17 +111,17 @@ typedef struct {
// MIFARE Ultralight // MIFARE Ultralight
typedef struct { typedef struct {
byte_t sn0[3]; uint8_t sn0[3];
byte_t btBCC0; uint8_t btBCC0;
byte_t sn1[4]; uint8_t sn1[4];
byte_t btBCC1; uint8_t btBCC1;
byte_t internal; uint8_t internal;
byte_t lock[2]; uint8_t lock[2];
byte_t otp[4]; uint8_t otp[4];
} mifareul_block_manufacturer; } mifareul_block_manufacturer;
typedef struct { typedef struct {
byte_t abtData[16]; uint8_t abtData[16];
} mifareul_block_data; } mifareul_block_data;
typedef union { typedef union {

View File

@ -1,13 +1,14 @@
/*- /*-
* Public platform independent Near Field Communication (NFC) library examples * Public platform independent Near Field Communication (NFC) library examples
* *
* Copyright (C) 2009, Roel Verdult * Copyright (C) 2009, Roel Verdult
* Copyright (C) 2010, Romuald Conty, Romain Tartière * Copyright (C) 2010-2011, Romain Tartière
* * Copyright (C) 2009-2012, Romuald Conty
*
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice, * 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright * 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
@ -23,97 +24,82 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
* *
* Note that this license only applies on the examples, NFC library itself is under LGPL * Note that this license only applies on the examples, NFC library itself is under LGPL
* *
*/ */
/**
* @file nfc-utils.c
* @brief Provide some examples shared functions like print, parity calculation, options parsing.
*/
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include <err.h> #include <err.h>
#include "nfc-utils.h" #include "nfc-utils.h"
static const byte_t OddParity[256] = { uint8_t
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, oddparity(const uint8_t bt)
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
};
byte_t
oddparity (const byte_t bt)
{ {
return OddParity[bt]; // cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
return (0x9669 >> ((bt ^(bt >> 4)) & 0xF)) & 1;
} }
void void
oddparity_bytes_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar) oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar)
{ {
size_t szByteNr; size_t szByteNr;
// Calculate the parity bits for the command // Calculate the parity bits for the command
for (szByteNr = 0; szByteNr < szLen; szByteNr++) { for (szByteNr = 0; szByteNr < szLen; szByteNr++) {
pbtPar[szByteNr] = OddParity[pbtData[szByteNr]]; pbtPar[szByteNr] = oddparity(pbtData[szByteNr]);
} }
} }
void void
print_hex (const byte_t * pbtData, const size_t szBytes) print_hex(const uint8_t *pbtData, const size_t szBytes)
{ {
size_t szPos; size_t szPos;
for (szPos = 0; szPos < szBytes; szPos++) { for (szPos = 0; szPos < szBytes; szPos++) {
printf ("%02x ", pbtData[szPos]); printf("%02x ", pbtData[szPos]);
} }
printf ("\n"); printf("\n");
} }
void void
print_hex_bits (const byte_t * pbtData, const size_t szBits) print_hex_bits(const uint8_t *pbtData, const size_t szBits)
{ {
uint8_t uRemainder; uint8_t uRemainder;
size_t szPos; size_t szPos;
size_t szBytes = szBits / 8; size_t szBytes = szBits / 8;
for (szPos = 0; szPos < szBytes; szPos++) { for (szPos = 0; szPos < szBytes; szPos++) {
printf ("%02x ", pbtData[szPos]); printf("%02x ", pbtData[szPos]);
} }
uRemainder = szBits % 8; uRemainder = szBits % 8;
// Print the rest bits // Print the rest bits
if (uRemainder != 0) { if (uRemainder != 0) {
if (uRemainder < 5) if (uRemainder < 5)
printf ("%01x (%d bits)", pbtData[szBytes], uRemainder); printf("%01x (%d bits)", pbtData[szBytes], uRemainder);
else else
printf ("%02x (%d bits)", pbtData[szBytes], uRemainder); printf("%02x (%d bits)", pbtData[szBytes], uRemainder);
} }
printf ("\n"); printf("\n");
} }
void void
print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar) print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar)
{ {
uint8_t uRemainder; uint8_t uRemainder;
size_t szPos; size_t szPos;
size_t szBytes = szBits / 8; size_t szBytes = szBits / 8;
for (szPos = 0; szPos < szBytes; szPos++) { for (szPos = 0; szPos < szBytes; szPos++) {
printf ("%02x", pbtData[szPos]); printf("%02x", pbtData[szPos]);
if (OddParity[pbtData[szPos]] != pbtDataPar[szPos]) { if (oddparity(pbtData[szPos]) != pbtDataPar[szPos]) {
printf ("! "); printf("! ");
} else { } else {
printf (" "); printf(" ");
} }
} }
@ -121,614 +107,18 @@ print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDa
// Print the rest bits, these cannot have parity bit // Print the rest bits, these cannot have parity bit
if (uRemainder != 0) { if (uRemainder != 0) {
if (uRemainder < 5) if (uRemainder < 5)
printf ("%01x (%d bits)", pbtData[szBytes], uRemainder); printf("%01x (%d bits)", pbtData[szBytes], uRemainder);
else else
printf ("%02x (%d bits)", pbtData[szBytes], uRemainder); printf("%02x (%d bits)", pbtData[szBytes], uRemainder);
}
printf ("\n");
}
#define SAK_UID_NOT_COMPLETE 0x04
#define SAK_ISO14443_4_COMPLIANT 0x20
#define SAK_ISO18092_COMPLIANT 0x40
void
print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose)
{
printf (" ATQA (SENS_RES): ");
print_hex (nai.abtAtqa, 2);
if (verbose) {
printf("* UID size: ");
switch ((nai.abtAtqa[1] & 0xc0)>>6) {
case 0:
printf("single\n");
break;
case 1:
printf("double\n");
break;
case 2:
printf("triple\n");
break;
case 3:
printf("RFU\n");
break;
}
printf("* bit frame anticollision ");
switch (nai.abtAtqa[1] & 0x1f) {
case 0x01:
case 0x02:
case 0x04:
case 0x08:
case 0x10:
printf("supported\n");
break;
default:
printf("not supported\n");
break;
}
}
printf (" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
print_hex (nai.abtUid, nai.szUidLen);
if (verbose) {
if (nai.abtUid[0] == 0x08) {
printf ("* Random UID\n");
}
}
printf (" SAK (SEL_RES): ");
print_hex (&nai.btSak, 1);
if (verbose) {
if (nai.btSak & SAK_UID_NOT_COMPLETE) {
printf ("* Warning! Cascade bit set: UID not complete\n");
}
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
printf ("* Compliant with ISO/IEC 14443-4\n");
} else {
printf ("* Not compliant with ISO/IEC 14443-4\n");
}
if (nai.btSak & SAK_ISO18092_COMPLIANT) {
printf ("* Compliant with ISO/IEC 18092\n");
} else {
printf ("* Not compliant with ISO/IEC 18092\n");
}
}
if (nai.szAtsLen) {
printf (" ATS: ");
print_hex (nai.abtAts, nai.szAtsLen);
}
if (nai.szAtsLen && verbose) {
// Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
printf ("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
size_t offset = 1;
if (nai.abtAts[0] & 0x10) { // TA(1) present
byte_t TA = nai.abtAts[offset];
offset++;
printf ("* Bit Rate Capability:\n");
if (TA == 0) {
printf (" * PICC supports only 106 kbits/s in both directions\n");
}
if (TA & 1<<7) {
printf (" * Same bitrate in both directions mandatory\n");
}
if (TA & 1<<4) {
printf (" * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
}
if (TA & 1<<5) {
printf (" * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
}
if (TA & 1<<6) {
printf (" * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
}
if (TA & 1<<0) {
printf (" * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
}
if (TA & 1<<1) {
printf (" * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
}
if (TA & 1<<2) {
printf (" * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
}
if (TA & 1<<3) {
printf (" * ERROR unknown value\n");
}
}
if (nai.abtAts[0] & 0x20) { // TB(1) present
byte_t TB= nai.abtAts[offset];
offset++;
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((TB & 0xf0) >> 4))/13560.0);
if ((TB & 0x0f) == 0) {
printf ("* No Start-up Frame Guard Time required\n");
} else {
printf ("* Start-up Frame Guard Time: %.4g ms\n",256.0*16.0*(1<<(TB & 0x0f))/13560.0);
}
}
if (nai.abtAts[0] & 0x40) { // TC(1) present
byte_t TC = nai.abtAts[offset];
offset++;
if (TC & 0x1) {
printf("* Node ADdress supported\n");
} else {
printf("* Node ADdress not supported\n");
}
if (TC & 0x2) {
printf("* Card IDentifier supported\n");
} else {
printf("* Card IDentifier not supported\n");
}
}
if (nai.szAtsLen > offset) {
printf ("* Historical bytes Tk: " );
print_hex (nai.abtAts + offset, (nai.szAtsLen - offset));
byte_t CIB = nai.abtAts[offset];
offset++;
if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
printf(" * Proprietary format\n");
if (CIB == 0xc1) {
printf(" * Tag byte: Mifare or virtual cards of various types\n");
byte_t L = nai.abtAts[offset];
offset++;
if (L != (nai.szAtsLen - offset)) {
printf(" * Warning: Type Identification Coding length (%i)", L);
printf(" not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
}
if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
byte_t CTC = nai.abtAts[offset];
offset++;
printf(" * Chip Type: ");
switch (CTC & 0xf0) {
case 0x00:
printf("(Multiple) Virtual Cards\n");
break;
case 0x10:
printf("Mifare DESFire\n");
break;
case 0x20:
printf("Mifare Plus\n");
break;
default:
printf("RFU\n");
break;
}
printf(" * Memory size: ");
switch (CTC & 0x0f) {
case 0x00:
printf("<1 kbyte\n");
break;
case 0x01:
printf("1 kbyte\n");
break;
case 0x02:
printf("2 kbyte\n");
break;
case 0x03:
printf("4 kbyte\n");
break;
case 0x04:
printf("8 kbyte\n");
break;
case 0x0f:
printf("Unspecified\n");
break;
default:
printf("RFU\n");
break;
}
}
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
byte_t CVC = nai.abtAts[offset];
offset++;
printf(" * Chip Status: ");
switch (CVC & 0xf0) {
case 0x00:
printf("Engineering sample\n");
break;
case 0x20:
printf("Released\n");
break;
default:
printf("RFU\n");
break;
}
printf(" * Chip Generation: ");
switch (CVC & 0x0f) {
case 0x00:
printf("Generation 1\n");
break;
case 0x01:
printf("Generation 2\n");
break;
case 0x02:
printf("Generation 3\n");
break;
case 0x0f:
printf("Unspecified\n");
break;
default:
printf("RFU\n");
break;
}
}
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
byte_t VCS = nai.abtAts[offset];
offset++;
printf(" * Specifics (Virtual Card Selection):\n");
if ((VCS & 0x09) == 0x00) {
printf(" * Only VCSL supported\n");
} else if ((VCS & 0x09) == 0x01) {
printf(" * VCS, VCSL and SVC supported\n");
}
if ((VCS & 0x0e) == 0x00) {
printf(" * SL1, SL2(?), SL3 supported\n");
} else if ((VCS & 0x0e) == 0x02) {
printf(" * SL3 only card\n");
} else if ((VCS & 0x0f) == 0x0e) {
printf(" * No VCS command supported\n");
} else if ((VCS & 0x0f) == 0x0f) {
printf(" * Unspecified\n");
} else {
printf(" * RFU\n");
}
}
}
} else {
if (CIB == 0x00) {
printf(" * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n");
printf(" followed by a mandatory status indicator (the last three bytes, not in TLV)\n");
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
}
if (CIB == 0x10) {
printf(" * DIR data reference: %02x\n", nai.abtAts[offset]);
}
if (CIB == 0x80) {
if (nai.szAtsLen == offset) {
printf(" * No COMPACT-TLV objects found, no status found\n");
} else {
printf(" * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n");
printf(" the last data object may carry a status indicator of one, two or three bytes.\n");
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
}
}
}
}
}
if (verbose) {
printf("Fingerprinting based on ATQA & SAK values:\n");
uint32_t atqasak = 0;
atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff)<<16);
atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff)<<8);
atqasak += ((uint32_t)nai.btSak & 0xff);
bool found_possible_match = false;
switch (atqasak) {
case 0x000218:
printf("* Mifare Classic 4K\n");
found_possible_match = true;
break;
case 0x000408:
printf("* Mifare Classic 1K\n");
printf("* Mifare Plus (4-byte UID) 2K SL1\n");
found_possible_match = true;
break;
case 0x000409:
printf("* Mifare MINI\n");
found_possible_match = true;
break;
case 0x000410:
printf("* Mifare Plus (4-byte UID) 2K SL2\n");
found_possible_match = true;
break;
case 0x000411:
printf("* Mifare Plus (4-byte UID) 4K SL2\n");
found_possible_match = true;
break;
case 0x000418:
printf("* Mifare Plus (4-byte UID) 4K SL1\n");
found_possible_match = true;
break;
case 0x000420:
printf("* Mifare Plus (4-byte UID) 2K/4K SL3\n");
found_possible_match = true;
break;
case 0x004400:
printf("* Mifare Ultralight\n");
printf("* Mifare UltralightC\n");
found_possible_match = true;
break;
case 0x004208:
case 0x004408:
printf("* Mifare Plus (7-byte UID) 2K SL1\n");
found_possible_match = true;
break;
case 0x004218:
case 0x004418:
printf("* Mifare Plus (7-byte UID) 4K SL1\n");
found_possible_match = true;
break;
case 0x004210:
case 0x004410:
printf("* Mifare Plus (7-byte UID) 2K SL2\n");
found_possible_match = true;
break;
case 0x004211:
case 0x004411:
printf("* Mifare Plus (7-byte UID) 4K SL2\n");
found_possible_match = true;
break;
case 0x004220:
case 0x004420:
printf("* Mifare Plus (7-byte UID) 2K/4K SL3\n");
found_possible_match = true;
break;
case 0x034420:
printf("* Mifare DESFire / Desfire EV1\n");
found_possible_match = true;
break;
}
// Other matches not described in
// AN MIFARE Type Identification Procedure
// but seen in the field:
switch (atqasak) {
case 0x000488:
printf("* Mifare Classic 1K Infineon\n");
found_possible_match = true;
break;
case 0x000298:
printf("* Gemplus MPCOS\n");
found_possible_match = true;
break;
case 0x030428:
printf("* JCOP31\n");
found_possible_match = true;
break;
case 0x004820:
printf("* JCOP31 v2.4.1\n");
printf("* JCOP31 v2.2\n");
found_possible_match = true;
break;
case 0x000428:
printf("* JCOP31 v2.3.1\n");
found_possible_match = true;
break;
case 0x000453:
printf("* Fudan FM1208SH01\n");
found_possible_match = true;
break;
case 0x000820:
printf("* Fudan FM1208\n");
found_possible_match = true;
break;
case 0x000238:
printf("* MFC 4K emulated by Nokia 6212 Classic\n");
found_possible_match = true;
break;
case 0x000838:
printf("* MFC 4K emulated by Nokia 6131 NFC\n");
found_possible_match = true;
break;
}
if ((nai.abtAtqa[0] & 0xf0) == 0) {
switch (nai.abtAtqa[1]) {
case 0x02:
printf("* SmartMX with Mifare 4K emulation\n");
found_possible_match = true;
break;
case 0x04:
printf("* SmartMX with Mifare 1K emulation\n");
found_possible_match = true;
break;
case 0x48:
printf("* SmartMX with 7-byte UID\n");
found_possible_match = true;
break;
}
}
if (! found_possible_match) {
printf("* Unknown card, sorry\n");
}
} }
printf("\n");
} }
void void
print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose) print_nfc_target(const nfc_target nt, bool verbose)
{ {
(void) verbose; char *s;
printf (" ID (NFCID2): "); str_nfc_target(&s, nt, verbose);
print_hex (nfi.abtId, 8); printf("%s", s);
printf (" Parameter (PAD): "); free(s);
print_hex (nfi.abtPad, 8);
printf (" System Code (SC): ");
print_hex (nfi.abtSysCode, 2);
} }
void
print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose)
{
(void) verbose;
printf (" ATQA (SENS_RES): ");
print_hex (nji.btSensRes, 2);
printf (" 4-LSB JEWELID: ");
print_hex (nji.btId, 4);
}
#define PI_ISO14443_4_SUPPORTED 0x01
#define PI_NAD_SUPPORTED 0x01
#define PI_CID_SUPPORTED 0x02
void
print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose)
{
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
printf (" PUPI: ");
print_hex (nbi.abtPupi, 4);
printf (" Application Data: ");
print_hex (nbi.abtApplicationData, 4);
printf (" Protocol Info: ");
print_hex (nbi.abtProtocolInfo, 3);
if (verbose) {
printf ("* Bit Rate Capability:\n");
if (nbi.abtProtocolInfo[0] == 0) {
printf (" * PICC supports only 106 kbits/s in both directions\n");
}
if (nbi.abtProtocolInfo[0] & 1<<7) {
printf (" * Same bitrate in both directions mandatory\n");
}
if (nbi.abtProtocolInfo[0] & 1<<4) {
printf (" * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<5) {
printf (" * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<6) {
printf (" * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<0) {
printf (" * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<1) {
printf (" * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<2) {
printf (" * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n");
}
if (nbi.abtProtocolInfo[0] & 1<<3) {
printf (" * ERROR unknown value\n");
}
if( (nbi.abtProtocolInfo[1] & 0xf0) <= 0x80 ) {
printf ("* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]);
}
if((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) {
printf ("* Protocol types supported: ISO/IEC 14443-4\n");
}
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((nbi.abtProtocolInfo[2] & 0xf0) >> 4))/13560.0);
if((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED|PI_CID_SUPPORTED)) != 0) {
printf ("* Frame options supported: ");
if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) printf ("NAD ");
if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) printf ("CID ");
printf("\n");
}
}
}
void
print_nfc_iso14443bi_info (const nfc_iso14443bi_info_t nii, bool verbose)
{
printf (" DIV: ");
print_hex (nii.abtDIV, 4);
if (verbose) {
int version = (nii.btVerLog & 0x1e)>>1;
printf (" Software Version: ");
if (version == 15) {
printf ("Undefined\n");
} else {
printf ("%i\n", version);
}
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x80)){
printf (" Wait Enable: yes");
}
}
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x40)) {
printf (" ATS: ");
print_hex (nii.abtAtr, nii.szAtrLen);
}
}
void
print_nfc_iso14443b2sr_info (const nfc_iso14443b2sr_info_t nsi, bool verbose)
{
(void) verbose;
printf (" UID: ");
print_hex (nsi.abtUID, 8);
}
void
print_nfc_iso14443b2ct_info (const nfc_iso14443b2ct_info_t nci, bool verbose)
{
(void) verbose;
uint32_t uid;
uid = (nci.abtUID[3] << 24) + (nci.abtUID[2] << 16) + (nci.abtUID[1] << 8) + nci.abtUID[0];
printf (" UID: ");
print_hex (nci.abtUID, sizeof(nci.abtUID));
printf (" UID (decimal): %010u\n", uid);
printf (" Product Code: %02X\n", nci.btProdCode);
printf (" Fab Code: %02X\n", nci.btFabCode);
}
void
print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose)
{
(void) verbose;
printf (" NFCID3: ");
print_hex (ndi.abtNFCID3, 10);
printf (" BS: %02x\n", ndi.btBS);
printf (" BR: %02x\n", ndi.btBR);
printf (" TO: %02x\n", ndi.btTO);
printf (" PP: %02x\n", ndi.btPP);
if (ndi.szGB) {
printf ("General Bytes: ");
print_hex (ndi.abtGB, ndi.szGB);
}
}
const char *
str_nfc_baud_rate (const nfc_baud_rate_t nbr)
{
switch(nbr) {
case NBR_UNDEFINED:
return "undefined baud rate";
break;
case NBR_106:
return "106 kbps";
break;
case NBR_212:
return "212 kbps";
break;
case NBR_424:
return "424 kbps";
break;
case NBR_847:
return "847 kbps";
break;
}
return "";
}
void
print_nfc_target (const nfc_target_t nt, bool verbose)
{
switch(nt.nm.nmt) {
case NMT_ISO14443A:
printf ("ISO/IEC 14443A (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443a_info (nt.nti.nai, verbose);
break;
case NMT_JEWEL:
printf ("Innovision Jewel (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_jewel_info (nt.nti.nji, verbose);
break;
case NMT_FELICA:
printf ("FeliCa (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_felica_info (nt.nti.nfi, verbose);
break;
case NMT_ISO14443B:
printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443b_info (nt.nti.nbi, verbose);
break;
case NMT_ISO14443BI:
printf ("ISO/IEC 14443-4B' (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443bi_info (nt.nti.nii, verbose);
break;
case NMT_ISO14443B2SR:
printf ("ISO/IEC 14443-2B ST SRx (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443b2sr_info (nt.nti.nsi, verbose);
break;
case NMT_ISO14443B2CT:
printf ("ISO/IEC 14443-2B ASK CTx (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443b2ct_info (nt.nti.nci, verbose);
break;
case NMT_DEP:
printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_dep_info (nt.nti.ndi, verbose);
break;
}
}

View File

@ -1,13 +1,13 @@
/*- /*-
* Public platform independent Near Field Communication (NFC) library examples * Public platform independent Near Field Communication (NFC) library examples
* *
* Copyright (C) 2009, Roel Verdult * Copyright (C) 2009, Roel Verdult
* Copyright (C) 2010, Romuald Conty, Romain Tartière * Copyright (C) 2010, Romuald Conty, Romain Tartière
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice, * 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright * 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
@ -23,7 +23,7 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
* *
* Note that this license only applies on the examples, NFC library itself is under LGPL * Note that this license only applies on the examples, NFC library itself is under LGPL
* *
*/ */
@ -79,22 +79,20 @@
# define ERR(...) warnx ("ERROR: " __VA_ARGS__ ) # define ERR(...) warnx ("ERROR: " __VA_ARGS__ )
#endif #endif
byte_t oddparity (const byte_t bt); #ifndef MIN
void oddparity_byte_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar); #define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
void print_hex (const byte_t * pbtData, const size_t szLen); uint8_t oddparity(const uint8_t bt);
void print_hex_bits (const byte_t * pbtData, const size_t szBits); void oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar);
void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar);
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose); void print_hex(const uint8_t *pbtData, const size_t szLen);
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose); void print_hex_bits(const uint8_t *pbtData, const size_t szBits);
void print_nfc_iso14443bi_info (const nfc_iso14443bi_info_t nii, bool verbose); void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar);
void print_nfc_iso14443b2sr_info (const nfc_iso14443b2sr_info_t nsi, bool verbose);
void print_nfc_iso14443b2ct_info (const nfc_iso14443b2ct_info_t nci, bool verbose);
void print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose);
void print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose);
void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose);
void print_nfc_target (const nfc_target_t nt, bool verbose); void print_nfc_target(const nfc_target nt, bool verbose);
#endif #endif