mirror of
https://github.com/nfc-tools/mfcuk.git
synced 2025-12-23 18:50:06 +00:00
- Renamed project and binary to mfcuk (instead of mfcuk_keyrecovery_darkside)
- Fixed fingerprint related bugs - Moved Template data to correct path relative to where mfcuk binary is built
This commit is contained in:
parent
7390ac0b34
commit
6fde5d8a91
6
AUTHORS
6
AUTHORS
@ -1 +1,7 @@
|
|||||||
|
= Author
|
||||||
Andrei Costin <zveriu@gmail.com>, http://andreicostin.com
|
Andrei Costin <zveriu@gmail.com>, http://andreicostin.com
|
||||||
|
|
||||||
|
= Contributors
|
||||||
|
|
||||||
|
Romuald Conty <romuald@libnfc.org> - porting to libnfc 1.3.x, 1.4.x, 1.5.x
|
||||||
|
Nethemba Core Team <mifare@nethemba.com> - core AC, AM, configure and packaging
|
||||||
|
|||||||
9
README
9
README
@ -1,6 +1,15 @@
|
|||||||
README
|
README
|
||||||
======
|
======
|
||||||
|
|
||||||
|
Compiling:
|
||||||
|
automake
|
||||||
|
autoconf
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
|
||||||
|
Running (most basic):
|
||||||
|
./mfcuk -C -R 0:A -v 2
|
||||||
|
|
||||||
PACKAGE
|
PACKAGE
|
||||||
-------
|
-------
|
||||||
MiFare Classic Universal toolKit (MFCUK)
|
MiFare Classic Universal toolKit (MFCUK)
|
||||||
|
|||||||
55
configure.ac
55
configure.ac
@ -1,4 +1,4 @@
|
|||||||
AC_INIT([mfcuk], [0.3.2], [zveriu@gmail.com])
|
AC_INIT([mfcuk], [0.3.3], [zveriu@gmail.com])
|
||||||
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
|
||||||
@ -6,68 +6,27 @@ AC_PROG_CC
|
|||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
|
||||||
|
AC_CONFIG_SRCDIR([src/mfcuk.c])
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE
|
AM_INIT_AUTOMAKE
|
||||||
|
|
||||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||||
|
|
||||||
# Checks for libnfc.
|
# Checks for pkg-config modules.
|
||||||
WITH_NFC=0
|
|
||||||
## Search libnfc with command line option (default prefix: auto)
|
|
||||||
LIBNFC_PREFIX="auto"
|
|
||||||
AC_ARG_WITH(libnfc,[--with-libnfc=DIR location of the libnfc],
|
|
||||||
[if test "$withval" != no; then
|
|
||||||
if test "$withval" != yes; then
|
|
||||||
LIBNFC_PREFIX=$withval
|
|
||||||
fi
|
|
||||||
fi])
|
|
||||||
if test x"$LIBNFC_PREFIX" != "xauto"; then
|
|
||||||
LIBNFC_CFLAGS="-L$LIBNFC_PREFIX/lib/ -I$LIBNFC_PREFIX/include/"
|
|
||||||
LIBNFC_LIBS="-lnfc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Search using pkg-config
|
|
||||||
AC_PATH_PROG(PKG_CONFIG, pkg-config, [AC_MSG_WARN([pkg-config not found.])])
|
|
||||||
if test x"$WITH_NFC" = "x0"; then
|
|
||||||
if test x"$PKG_CONFIG" != "x"; then
|
|
||||||
LIBNFC_REQUIRED_VERSION=1.5.1
|
LIBNFC_REQUIRED_VERSION=1.5.1
|
||||||
PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [WITH_NFC=1], [WITH_NFC=0])
|
PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
|
||||||
fi
|
|
||||||
fi
|
|
||||||
CFLAGS="$CFLAGS $LIBNFC_CFLAGS"
|
|
||||||
AC_CHECK_HEADERS([nfc/nfc.h],[WITH_NFC=1], AC_MSG_ERROR([A version of libnfc greater than or equal to $LIBNFC_REQUIRED_VERSION is required]))
|
|
||||||
|
|
||||||
if test x"$WITH_NFC" = "x0"; then
|
PKG_CONFIG_REQUIRES="libnfc"
|
||||||
AC_MSG_ERROR([A version of libnfc greater than or equal to $LIBNFC_REQUIRED_VERSION is required.])
|
AC_SUBST([PKG_CONFIG_REQUIRES])
|
||||||
fi
|
|
||||||
|
|
||||||
# Checks for programs.
|
|
||||||
AC_PROG_CC
|
|
||||||
|
|
||||||
# Checks for libraries.
|
|
||||||
AC_CHECK_LIB([nfc], [nfc_version])
|
|
||||||
|
|
||||||
# Checks for header files.
|
|
||||||
AC_CHECK_HEADERS([byteswap.h])
|
|
||||||
AC_CHECK_HEADERS([endian.h sys/endian.h CoreFoundation/CoreFoundation.h])
|
|
||||||
AC_CHECK_HEADERS([stdint.h stdlib.h string.h sys/time.h unistd.h])
|
|
||||||
|
|
||||||
AC_DEFINE(_XOPEN_SOURCE, 600, [Enable POSIX extensions if present])
|
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_HEADER_STDBOOL
|
AC_HEADER_STDBOOL
|
||||||
AC_TYPE_SIZE_T
|
|
||||||
AC_TYPE_UINT16_T
|
|
||||||
AC_TYPE_UINT32_T
|
AC_TYPE_UINT32_T
|
||||||
AC_TYPE_UINT64_T
|
AC_TYPE_UINT64_T
|
||||||
AC_TYPE_UINT8_T
|
|
||||||
|
|
||||||
# Checks for library functions.
|
# Checks for library functions.
|
||||||
AC_FUNC_MALLOC
|
AC_FUNC_MALLOC
|
||||||
AC_FUNC_REALLOC
|
AC_FUNC_REALLOC
|
||||||
AC_CHECK_FUNCS([memset strchr])
|
|
||||||
|
|
||||||
# Help us to write great code ;-)
|
|
||||||
CFLAGS="$CFLAGS -Wall -pedantic -Wextra -std=c99"
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
src/Makefile])
|
src/Makefile])
|
||||||
|
|||||||
@ -1,26 +1,9 @@
|
|||||||
bin_PROGRAMS = mfcuk_keyrecovery_darkside
|
AM_CFLAGS = @LIBNFC_CFLAGS@
|
||||||
|
AM_LDFLAGS = @LIBNFC_LIBS@
|
||||||
|
|
||||||
noinst_HEADERS = \
|
bin_PROGRAMS = mfcuk
|
||||||
crapto1.h \
|
|
||||||
mfcuk_finger.h \
|
|
||||||
mfcuk_keyrecovery_darkside.h \
|
|
||||||
mfcuk_mifare.h \
|
|
||||||
mfcuk_utils.h \
|
|
||||||
mifare.h \
|
|
||||||
nfc-utils.h \
|
|
||||||
xgetopt.h
|
|
||||||
|
|
||||||
# set the include path found by configure
|
noinst_HEADERS = crapto1.h mifare.h nfc-utils.h mfcuk_mifare.h mfcuk_finger.h mfcuk_utils.h xgetopt.h mfcuk.h
|
||||||
mfcuk_keyrecovery_darkside_SOURCES = \
|
mfcuk_SOURCES = crapto1.c crypto1.c mifare.c nfc-utils.c mfcuk_mifare.c mfcuk_finger.c mfcuk_utils.c xgetopt.c mfcuk.c
|
||||||
crapto1.c \
|
|
||||||
crypto1.c \
|
|
||||||
mfcuk_finger.c \
|
|
||||||
mfcuk_keyrecovery_darkside.c \
|
|
||||||
mfcuk_mifare.c \
|
|
||||||
mfcuk_utils.c \
|
|
||||||
mifare.c \
|
|
||||||
nfc-utils.c
|
|
||||||
|
|
||||||
mfcuk_keyrecovery_darkside_LDADD = -lnfc -lusb -lpcsclite
|
# dist_man_MANS = mfcuk.1
|
||||||
|
|
||||||
# dist_man_MANS = mfcuk_keyrecovery_darkside.1
|
|
||||||
|
|||||||
@ -57,7 +57,7 @@ static void quicksort(uint32_t* const start, uint32_t* const stop)
|
|||||||
/** binsearch
|
/** binsearch
|
||||||
* Binary search for the first occurence of *stop's MSB in sorted [start,stop]
|
* Binary search for the first occurence of *stop's MSB in sorted [start,stop]
|
||||||
*/
|
*/
|
||||||
static /*inline*/ uint32_t*
|
static inline uint32_t*
|
||||||
binsearch(uint32_t *start, uint32_t *stop)
|
binsearch(uint32_t *start, uint32_t *stop)
|
||||||
{
|
{
|
||||||
uint32_t mid, val = *stop & 0xff000000;
|
uint32_t mid, val = *stop & 0xff000000;
|
||||||
@ -73,7 +73,7 @@ binsearch(uint32_t *start, uint32_t *stop)
|
|||||||
/** update_contribution
|
/** update_contribution
|
||||||
* helper, calculates the partial linear feedback contributions and puts in MSB
|
* helper, calculates the partial linear feedback contributions and puts in MSB
|
||||||
*/
|
*/
|
||||||
static /*inline*/ void
|
static inline void
|
||||||
update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2)
|
update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2)
|
||||||
{
|
{
|
||||||
uint32_t p = *item >> 25;
|
uint32_t p = *item >> 25;
|
||||||
@ -86,7 +86,7 @@ update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2)
|
|||||||
/** extend_table
|
/** extend_table
|
||||||
* using a bit of the keystream extend the table of possible lfsr states
|
* using a bit of the keystream extend the table of possible lfsr states
|
||||||
*/
|
*/
|
||||||
static /*inline*/ void
|
static inline void
|
||||||
extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in)
|
extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in)
|
||||||
{
|
{
|
||||||
in <<= 24;
|
in <<= 24;
|
||||||
@ -108,7 +108,7 @@ extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in
|
|||||||
/** extend_table_simple
|
/** extend_table_simple
|
||||||
* using a bit of the keystream extend the table of possible lfsr states
|
* using a bit of the keystream extend the table of possible lfsr states
|
||||||
*/
|
*/
|
||||||
static /*inline*/ void
|
static inline void
|
||||||
extend_table_simple(uint32_t *tbl, uint32_t **end, int bit)
|
extend_table_simple(uint32_t *tbl, uint32_t **end, int bit)
|
||||||
{
|
{
|
||||||
for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1)
|
for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1)
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
MA 02110-1301, US$
|
MA 02110-1301, US$
|
||||||
|
|
||||||
Copyright (C) 2008-2008 bla <blapost@gmail.com>
|
Copyright (C) 2008-2009 bla <blapost@gmail.com>
|
||||||
*/
|
*/
|
||||||
#ifndef CRAPTO1_INCLUDED
|
#ifndef CRAPTO1_INCLUDED
|
||||||
#define CRAPTO1_INCLUDED
|
#define CRAPTO1_INCLUDED
|
||||||
@ -35,12 +35,8 @@ uint32_t prng_successor(uint32_t x, uint32_t n);
|
|||||||
|
|
||||||
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in);
|
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in);
|
||||||
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3);
|
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3);
|
||||||
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd);
|
|
||||||
struct Crypto1State* lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]);
|
|
||||||
|
|
||||||
uint8_t lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb);
|
void lfsr_rollback(struct Crypto1State* s, uint32_t in, int fb);
|
||||||
uint8_t lfsr_rollback_byte(struct Crypto1State* s, uint32_t in, int fb);
|
|
||||||
uint32_t lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb);
|
|
||||||
int nonce_distance(uint32_t from, uint32_t to);
|
int nonce_distance(uint32_t from, uint32_t to);
|
||||||
#define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\
|
#define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\
|
||||||
uint32_t __n = 0,__M = 0, N = 0;\
|
uint32_t __n = 0,__M = 0, N = 0;\
|
||||||
@ -57,7 +53,7 @@ int nonce_distance(uint32_t from, uint32_t to);
|
|||||||
#define LF_POLY_EVEN (0x870804)
|
#define LF_POLY_EVEN (0x870804)
|
||||||
#define BIT(x, n) ((x) >> (n) & 1)
|
#define BIT(x, n) ((x) >> (n) & 1)
|
||||||
#define BEBIT(x, n) BIT(x, (n) ^ 24)
|
#define BEBIT(x, n) BIT(x, (n) ^ 24)
|
||||||
static /*inline*/ int parity(uint32_t x)
|
static inline int parity(uint32_t x)
|
||||||
{
|
{
|
||||||
#if !defined __i386__ || !defined __GNUC__
|
#if !defined __i386__ || !defined __GNUC__
|
||||||
x ^= x >> 16;
|
x ^= x >> 16;
|
||||||
@ -75,7 +71,7 @@ static /*inline*/ int parity(uint32_t x)
|
|||||||
return x;
|
return x;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
static /*inline*/ int filter(uint32_t const x)
|
static inline int filter(uint32_t const x)
|
||||||
{
|
{
|
||||||
uint32_t f;
|
uint32_t f;
|
||||||
|
|
||||||
|
|||||||
@ -132,7 +132,31 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_BYTESWAP_H)
|
#if defined(HAVE_BYTESWAP_H)
|
||||||
|
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
|
|
||||||
|
#elif __GNUC__ * 100 + __GNUC_MINOR__ >= 430
|
||||||
|
|
||||||
|
#warning "NO byteswap.h found! But since GCC >= 4.30, using __builtin_bswapXX() alternatives..."
|
||||||
|
#define bswap_16 __builtin_bswap16
|
||||||
|
#define bswap_32 __builtin_bswap32
|
||||||
|
#define bswap_64 __builtin_bswap64
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#warning "NO byteswap.h found! Using untested alternatives..."
|
||||||
|
|
||||||
|
static inline unsigned short bswap_16(unsigned short x) {
|
||||||
|
return (x>>8) | (x<<8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int bswap_32(unsigned int x) {
|
||||||
|
return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long long bswap_64(unsigned long long x) {
|
||||||
|
return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -171,7 +195,7 @@
|
|||||||
#include "mfcuk_mifare.h"
|
#include "mfcuk_mifare.h"
|
||||||
#include "mfcuk_utils.h"
|
#include "mfcuk_utils.h"
|
||||||
#include "mfcuk_finger.h"
|
#include "mfcuk_finger.h"
|
||||||
#include "mfcuk_keyrecovery_darkside.h"
|
#include "mfcuk.h"
|
||||||
|
|
||||||
#define MAX_FRAME_LEN 264
|
#define MAX_FRAME_LEN 264
|
||||||
|
|
||||||
@ -1293,7 +1317,7 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
// // Input extended dump file of type mifare_classic_tag_ext, Options i and I are autoexclusive
|
// Input extended dump file of type mifare_classic_tag_ext, Options i and I are autoexclusive
|
||||||
if (!bfOpts['i'] && !bfOpts['I'])
|
if (!bfOpts['i'] && !bfOpts['I'])
|
||||||
{
|
{
|
||||||
if ( !mfcuk_load_tag_dump_ext(optarg, &(dump_loaded_tag)) )
|
if ( !mfcuk_load_tag_dump_ext(optarg, &(dump_loaded_tag)) )
|
||||||
@ -1308,7 +1332,7 @@ int main(int argc, char* argv[])
|
|||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'O':
|
case 'O':
|
||||||
// // Output simple/extended dump file, Options o and O are autoexclusive
|
// Output simple/extended dump file, Options o and O are autoexclusive
|
||||||
if (!bfOpts['o'] && !bfOpts['O'])
|
if (!bfOpts['o'] && !bfOpts['O'])
|
||||||
{
|
{
|
||||||
strncpy( strOutputFilename, optarg, sizeof(strOutputFilename) );
|
strncpy( strOutputFilename, optarg, sizeof(strOutputFilename) );
|
||||||
@ -42,7 +42,7 @@ mfcuk_finger_tmpl_entry mfcuk_finger_db[] =
|
|||||||
{
|
{
|
||||||
{ "./data/tmpls_fingerprints/mfcuk_tmpl_skgt.mfd", "Sofia SKGT", mfcuk_finger_default_comparator, mfcuk_finger_skgt_decoder, NULL },
|
{ "./data/tmpls_fingerprints/mfcuk_tmpl_skgt.mfd", "Sofia SKGT", mfcuk_finger_default_comparator, mfcuk_finger_skgt_decoder, NULL },
|
||||||
{ "./data/tmpls_fingerprints/mfcuk_tmpl_ratb.mfd", "Bucharest RATB", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL },
|
{ "./data/tmpls_fingerprints/mfcuk_tmpl_ratb.mfd", "Bucharest RATB", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL },
|
||||||
{ "./data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd", "London OYSTER", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL }
|
{ "./data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd", "London OYSTER", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
int mfcuk_finger_db_entries = sizeof(mfcuk_finger_db)/sizeof(mfcuk_finger_db[0]);
|
int mfcuk_finger_db_entries = sizeof(mfcuk_finger_db)/sizeof(mfcuk_finger_db[0]);
|
||||||
@ -172,13 +172,13 @@ int mfcuk_finger_load()
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
if (mfcuk_finger_db[i].tmpl_data == NULL)
|
if (mfcuk_finger_db[i].tmpl_data == NULL)
|
||||||
{
|
{
|
||||||
if ( (tmpl_new = (mfcuk_finger_template *) malloc(sizeof(mfcuk_finger_template))) == NULL)
|
if ( (tmpl_new = (mfcuk_finger_template *) malloc(sizeof(mfcuk_finger_template))) == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "WARN: cannot allocate memory to template record %d\n", i);
|
fprintf(stderr, "WARN: cannot allocate memory to template record %d\n", i);
|
||||||
|
fclose(fp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,8 +188,13 @@ int mfcuk_finger_load()
|
|||||||
mfcuk_finger_db[i].tmpl_data = tmpl_new;
|
mfcuk_finger_db[i].tmpl_data = tmpl_new;
|
||||||
template_loaded_count++;
|
template_loaded_count++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
fp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return template_loaded_count;
|
return template_loaded_count;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,12 +100,14 @@ nfc_initiator_mifare_cmd (nfc_device_t * pnd, const mifare_cmd mc, const uint8_t
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Fire the mifare command
|
// Fire the mifare command
|
||||||
if (!nfc_initiator_transceive_bytes (pnd, abtCmd, 2 + szParamLen, abtRx, &szRx, NULL)) {
|
if (!nfc_initiator_transceive_bytes (pnd, abtCmd, 2 + szParamLen, abtRx, &szRx)) {
|
||||||
if (pnd->iLastError == EINVRXFRAM) {
|
if (pnd->iLastError == EINVRXFRAM) {
|
||||||
// "Invalid received frame" AKA EINVRXFRAM, usual means we are
|
// "Invalid received frame" AKA EINVRXFRAM, 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 if (pnd->iLastError == EMFAUTH) {
|
||||||
|
// In MFOC, we have to hide authentication errors :)
|
||||||
} else {
|
} else {
|
||||||
nfc_perror (pnd, "nfc_initiator_transceive_bytes");
|
nfc_perror (pnd, "nfc_initiator_transceive_bytes");
|
||||||
}
|
}
|
||||||
|
|||||||
48
src/mifare.h
48
src/mifare.h
@ -1,22 +1,34 @@
|
|||||||
|
/*-
|
||||||
|
* Public platform independent Near Field Communication (NFC) library examples
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, Roel Verdult
|
||||||
|
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* 1) Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public platform independent Near Field Communication (NFC) library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2009, Roel Verdult, 2010, Romuald Conty
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU Lesser General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @file mifaretag.h
|
* @file mifaretag.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
|
||||||
*/
|
*/
|
||||||
|
|||||||
579
src/nfc-utils.c
579
src/nfc-utils.c
@ -1,4 +1,35 @@
|
|||||||
|
/*-
|
||||||
|
* Public platform independent Near Field Communication (NFC) library examples
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, Roel Verdult
|
||||||
|
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* 1) Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <nfc/nfc.h>
|
#include <nfc/nfc.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
#include "nfc-utils.h"
|
#include "nfc-utils.h"
|
||||||
|
|
||||||
@ -21,47 +52,47 @@ static const byte_t OddParity[256] = {
|
|||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
byte_t oddparity(const byte_t bt)
|
byte_t
|
||||||
|
oddparity (const byte_t bt)
|
||||||
{
|
{
|
||||||
return OddParity[bt];
|
return OddParity[bt];
|
||||||
}
|
}
|
||||||
|
|
||||||
void oddparity_bytes_ts(const byte_t* pbtData, const size_t szLen, byte_t* pbtPar)
|
void
|
||||||
|
oddparity_bytes_ts (const byte_t * pbtData, const size_t szLen, byte_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 print_hex(const byte_t* pbtData, const size_t szBytes)
|
void
|
||||||
|
print_hex (const byte_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 print_hex_bits(const byte_t* pbtData, const size_t szBits)
|
void
|
||||||
|
print_hex_bits (const byte_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
|
||||||
@ -70,17 +101,16 @@ void print_hex_bits(const byte_t* pbtData, const size_t szBits)
|
|||||||
printf ("\n");
|
printf ("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbtDataPar)
|
void
|
||||||
|
print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_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 (" ");
|
||||||
@ -89,8 +119,7 @@ void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbt
|
|||||||
|
|
||||||
uRemainder = szBits % 8;
|
uRemainder = szBits % 8;
|
||||||
// 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
|
||||||
@ -99,38 +128,433 @@ void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbt
|
|||||||
printf ("\n");
|
printf ("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SAK_UID_NOT_COMPLETE 0x04
|
||||||
#define SAK_ISO14443_4_COMPLIANT 0x20
|
#define SAK_ISO14443_4_COMPLIANT 0x20
|
||||||
#define SAK_ISO18092_COMPLIANT 0x40
|
#define SAK_ISO18092_COMPLIANT 0x40
|
||||||
|
|
||||||
void print_nfc_iso14443a_info(const nfc_iso14443a_info_t nai)
|
void
|
||||||
|
print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose)
|
||||||
{
|
{
|
||||||
printf(" ATQA (SENS_RES): "); print_hex(nai.abtAtqa,2);
|
printf (" ATQA (SENS_RES): ");
|
||||||
printf(" UID (NFCID%c): ",(nai.abtUid[0]==0x08?'3':'1')); print_hex(nai.abtUid, nai.szUidLen);
|
print_hex (nai.abtAtqa, 2);
|
||||||
printf(" SAK (SEL_RES): "); print_hex(&nai.btSak,1);
|
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) {
|
if (nai.szAtsLen) {
|
||||||
printf(" ATS (ATR): ");
|
printf (" ATS: ");
|
||||||
print_hex (nai.abtAts, nai.szAtsLen);
|
print_hex (nai.abtAts, nai.szAtsLen);
|
||||||
}
|
}
|
||||||
if ( (nai.btSak & SAK_ISO14443_4_COMPLIANT) || (nai.btSak & SAK_ISO18092_COMPLIANT) ) {
|
if (nai.szAtsLen && verbose) {
|
||||||
printf(" Compliant with: ");
|
// Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
|
||||||
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) printf("ISO/IEC 14443-4 ");
|
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||||
if (nai.btSak & SAK_ISO18092_COMPLIANT) printf("ISO/IEC 18092");
|
printf ("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
|
||||||
printf("\n");
|
|
||||||
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void print_nfc_felica_info(const nfc_felica_info_t nfi)
|
if (nai.abtAts[0] & 0x20) { // TB(1) present
|
||||||
{
|
byte_t TB= nai.abtAts[offset];
|
||||||
printf(" ID (NFCID2): "); print_hex(nfi.abtId,8);
|
offset++;
|
||||||
printf(" Parameter (PAD): "); print_hex(nfi.abtPad,8);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_nfc_iso14443b_info(const nfc_iso14443b_info_t nbi)
|
// Other matches not described in
|
||||||
|
// AN MIFARE Type Identification Procedure
|
||||||
|
// but seen in the field:
|
||||||
|
switch (atqasak) {
|
||||||
|
case 0x000488:
|
||||||
|
printf("* Mifare Classic 1K Infineon\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x000298:
|
||||||
|
printf("* Gemplus MPCOS\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x030428:
|
||||||
|
printf("* JCOP31\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x004820:
|
||||||
|
printf("* JCOP31 v2.4.1\n");
|
||||||
|
printf("* JCOP31 v2.2\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x000428:
|
||||||
|
printf("* JCOP31 v2.3.1\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x000453:
|
||||||
|
printf("* Fudan FM1208SH01\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x000820:
|
||||||
|
printf("* Fudan FM1208\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x000238:
|
||||||
|
printf("* MFC 4K emulated by Nokia 6212 Classic\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x000838:
|
||||||
|
printf("* MFC 4K emulated by Nokia 6131 NFC\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((nai.abtAtqa[0] & 0xf0) == 0) {
|
||||||
|
switch (nai.abtAtqa[1]) {
|
||||||
|
case 0x02:
|
||||||
|
printf("* SmartMX with Mifare 4K emulation\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
printf("* SmartMX with Mifare 1K emulation\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
case 0x48:
|
||||||
|
printf("* SmartMX with 7-byte UID\n");
|
||||||
|
found_possible_match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! found_possible_match) {
|
||||||
|
printf("* Unknown card, sorry\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose)
|
||||||
{
|
{
|
||||||
|
(void) verbose;
|
||||||
|
printf (" ID (NFCID2): ");
|
||||||
|
print_hex (nfi.abtId, 8);
|
||||||
|
printf (" Parameter (PAD): ");
|
||||||
|
print_hex (nfi.abtPad, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose)
|
||||||
|
{
|
||||||
|
(void) verbose;
|
||||||
|
printf (" ATQA (SENS_RES): ");
|
||||||
|
print_hex (nji.btSensRes, 2);
|
||||||
|
printf (" 4-LSB JEWELID: ");
|
||||||
|
print_hex (nji.btId, 4);
|
||||||
|
}
|
||||||
|
|
||||||
#define PI_ISO14443_4_SUPPORTED 0x01
|
#define PI_ISO14443_4_SUPPORTED 0x01
|
||||||
#define PI_NAD_SUPPORTED 0x01
|
#define PI_NAD_SUPPORTED 0x01
|
||||||
#define PI_CID_SUPPORTED 0x02
|
#define PI_CID_SUPPORTED 0x02
|
||||||
//copied from libnfc r963
|
void
|
||||||
bool verbose = true;
|
print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose)
|
||||||
|
{
|
||||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||||
printf (" PUPI: ");
|
printf (" PUPI: ");
|
||||||
print_hex (nbi.abtPupi, 4);
|
print_hex (nbi.abtPupi, 4);
|
||||||
@ -183,11 +607,28 @@ void print_nfc_iso14443b_info(const nfc_iso14443b_info_t nbi)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose)
|
||||||
|
{
|
||||||
|
(void) verbose;
|
||||||
|
printf (" NFCID3: ");
|
||||||
|
print_hex (ndi.abtNFCID3, 10);
|
||||||
|
printf (" BS: %02x\n", ndi.btBS);
|
||||||
|
printf (" BR: %02x\n", ndi.btBR);
|
||||||
|
printf (" TO: %02x\n", ndi.btTO);
|
||||||
|
printf (" PP: %02x\n", ndi.btPP);
|
||||||
|
if (ndi.szGB) {
|
||||||
|
printf ("General Bytes: ");
|
||||||
|
print_hex (ndi.abtGB, ndi.szGB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tries to parse arguments to find device descriptions.
|
* @brief Tries to parse arguments to find device descriptions.
|
||||||
* @return Returns the list of found device descriptions.
|
* @return Returns the list of found device descriptions.
|
||||||
*/
|
*/
|
||||||
nfc_device_desc_t* parse_device_desc(int argc, const char *argv[], size_t* szFound)
|
nfc_device_desc_t *
|
||||||
|
parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose)
|
||||||
{
|
{
|
||||||
nfc_device_desc_t *pndd = 0;
|
nfc_device_desc_t *pndd = 0;
|
||||||
int arg;
|
int arg;
|
||||||
@ -197,7 +638,7 @@ nfc_device_desc_t* parse_device_desc(int argc, const char *argv[], size_t* szFou
|
|||||||
for (arg = 1; arg < argc; arg++) {
|
for (arg = 1; arg < argc; arg++) {
|
||||||
|
|
||||||
if (0 == strcmp (argv[arg], "--device")) {
|
if (0 == strcmp (argv[arg], "--device")) {
|
||||||
|
// FIXME: this device selection by command line options is terrible & does not support USB/PCSC drivers
|
||||||
if (argc > arg + 1) {
|
if (argc > arg + 1) {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
|
||||||
@ -210,17 +651,71 @@ nfc_device_desc_t* parse_device_desc(int argc, const char *argv[], size_t* szFou
|
|||||||
strcpy (pndd->pcDriver, strtok (buffer, ":"));
|
strcpy (pndd->pcDriver, strtok (buffer, ":"));
|
||||||
|
|
||||||
// Port.
|
// Port.
|
||||||
strcpy(pndd->acPort, strtok(NULL, ":"));
|
pndd->pcPort = (char *) malloc (256);
|
||||||
|
strcpy (pndd->pcPort, strtok (NULL, ":"));
|
||||||
|
|
||||||
// Speed.
|
// Speed.
|
||||||
sscanf (strtok (NULL, ":"), "%u", &pndd->uiSpeed);
|
sscanf (strtok (NULL, ":"), "%u", &pndd->uiSpeed);
|
||||||
|
|
||||||
*szFound = 1;
|
*szFound = 1;
|
||||||
|
} else {
|
||||||
|
errx (1, "usage: %s [--device driver:port:speed]", argv[0]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if ((0 == strcmp (argv[arg], "-v")) || (0 == strcmp (argv[arg], "--verbose"))) {
|
||||||
|
*verbose = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pndd;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
str_nfc_baud_rate (const nfc_baud_rate_t nbr)
|
||||||
|
{
|
||||||
|
switch(nbr) {
|
||||||
|
case NBR_UNDEFINED:
|
||||||
|
return "undefined baud rate";
|
||||||
|
break;
|
||||||
|
case NBR_106:
|
||||||
|
return "106 kbps";
|
||||||
|
break;
|
||||||
|
case NBR_212:
|
||||||
|
return "212 kbps";
|
||||||
|
break;
|
||||||
|
case NBR_424:
|
||||||
|
return "424 kbps";
|
||||||
|
break;
|
||||||
|
case NBR_847:
|
||||||
|
return "847 kbps";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_nfc_target (const nfc_target_t nt, bool verbose)
|
||||||
|
{
|
||||||
|
switch(nt.nm.nmt) {
|
||||||
|
case NMT_ISO14443A:
|
||||||
|
printf ("ISO/IEC 14443A (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||||
|
print_nfc_iso14443a_info (nt.nti.nai, verbose);
|
||||||
|
break;
|
||||||
|
case NMT_JEWEL:
|
||||||
|
printf ("Innovision Jewel (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||||
|
print_nfc_jewel_info (nt.nti.nji, verbose);
|
||||||
|
break;
|
||||||
|
case NMT_FELICA:
|
||||||
|
printf ("FeliCa (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||||
|
print_nfc_felica_info (nt.nti.nfi, verbose);
|
||||||
|
break;
|
||||||
|
case NMT_ISO14443B:
|
||||||
|
printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||||
|
print_nfc_iso14443b_info (nt.nti.nbi, verbose);
|
||||||
|
break;
|
||||||
|
case NMT_DEP:
|
||||||
|
printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||||
|
print_nfc_dep_info (nt.nti.ndi, verbose);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pndd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
100
src/nfc-utils.h
100
src/nfc-utils.h
@ -1,22 +1,34 @@
|
|||||||
|
/*-
|
||||||
|
* Public platform independent Near Field Communication (NFC) library examples
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009, Roel Verdult
|
||||||
|
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* 1) Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public platform independent Near Field Communication (NFC) library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010, Romuald Conty
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU Lesser General Public License as published by the
|
|
||||||
* Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @file nfc-utils.h
|
* @file nfc-utils.h
|
||||||
* @brief Provide some examples shared functions like print, parity calculation, options parsing.
|
* @brief Provide some examples shared functions like print, parity calculation, options parsing.
|
||||||
*/
|
*/
|
||||||
@ -26,6 +38,46 @@
|
|||||||
|
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
|
# include <err.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro DBG
|
||||||
|
* @brief Print a message of standard output only in DEBUG mode
|
||||||
|
*/
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define DBG(...) do { \
|
||||||
|
warnx ("DBG %s:%d", __FILE__, __LINE__); \
|
||||||
|
warnx (" " __VA_ARGS__ ); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define DBG(...) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro WARN
|
||||||
|
* @brief Print a warn message
|
||||||
|
*/
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define WARN(...) do { \
|
||||||
|
warnx ("WARNING %s:%d", __FILE__, __LINE__); \
|
||||||
|
warnx (" " __VA_ARGS__ ); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define WARN(...) warnx ("WARNING: " __VA_ARGS__ )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @macro ERR
|
||||||
|
* @brief Print a error message
|
||||||
|
*/
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define ERR(...) do { \
|
||||||
|
warnx ("ERROR %s:%d", __FILE__, __LINE__); \
|
||||||
|
warnx (" " __VA_ARGS__ ); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define ERR(...) warnx ("ERROR: " __VA_ARGS__ )
|
||||||
|
#endif
|
||||||
|
|
||||||
byte_t oddparity (const byte_t bt);
|
byte_t oddparity (const byte_t bt);
|
||||||
void oddparity_byte_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar);
|
void oddparity_byte_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar);
|
||||||
@ -34,10 +86,14 @@ void print_hex(const byte_t* pbtData, const size_t szLen);
|
|||||||
void print_hex_bits (const byte_t * pbtData, const size_t szBits);
|
void print_hex_bits (const byte_t * pbtData, const size_t szBits);
|
||||||
void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar);
|
void print_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);
|
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose);
|
||||||
void print_nfc_iso14443b_info(const nfc_iso14443b_info_t nbi);
|
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose);
|
||||||
void print_nfc_felica_info(const nfc_felica_info_t nfi);
|
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);
|
||||||
|
|
||||||
nfc_device_desc_t* parse_device_desc(int argc, const char *argv[], size_t* szFound);
|
void print_nfc_target (const nfc_target_t nt, bool verbose);
|
||||||
|
|
||||||
|
nfc_device_desc_t *parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user