34 Commits

Author SHA1 Message Date
j8048188
b333a7925a Fix typos in usage examples 2018-07-14 12:31:54 +02:00
Marcos Vives Del Sol
30df7f5a28 Fix configure warnings about missing stuff 2018-05-09 16:11:51 +02:00
Marcos Vives Del Sol
a8a605e1b4 Removed xor swaps to fix GCC warnings 2018-05-09 16:11:51 +02:00
Marcos Vives Del Sol
92f7413beb Improve system-dependent compilation 2018-05-09 16:11:51 +02:00
Marcos Vives Del Sol
1fb6a02359 Added .gitignore 2018-05-09 16:11:51 +02:00
Julius Putra Tanu Setiaji
e04aaa8a96 Update compilation instruction
According to #35
2018-05-09 16:02:44 +02:00
Romuald Conty
f67b812be6 Merge pull request #52 from unlimitedsola/patch-1
Fix typo
2018-01-07 23:50:25 +01:00
Sola
4f1a01f7fe Update README 2017-11-25 15:27:14 +08:00
romuald@libnfc.org
5acc9f40a0 Attempt to fix key recovering
This patch may fix the keys recovering problem explained in Issue 21.
2014-01-10 01:00:19 +00:00
romuald@libnfc.org
444dd2a765 Bump version 2013-06-12 13:13:35 +00:00
romuald@libnfc.org
445b281277 Sync nfc-utils.[hc] with devel libnfc files 2013-04-04 21:50:18 +00:00
romuald@libnfc.org
d43410c0cb Supress clang warning: implicit declaration of function 'lfsr_common_prefix' is invalid in C99 2013-04-04 21:41:50 +00:00
romuald@libnfc.org
afd7fdb295 Bump version 2013-01-30 15:03:00 +00:00
romuald@libnfc.org
58a8d3af88 Sync crapto1.* with MFOC
Fixes issue 18
Fixes issue 19
2013-01-30 14:56:33 +00:00
romuald@libnfc.org
df22a2ce1b Sync nfc-utils.* and mifare.* with libnfc 2013-01-30 14:55:25 +00:00
romuald@libnfc.org
776b0d3f79 Applies make style 2013-01-30 14:54:27 +00:00
romuald@libnfc.org
22fa583429 Adds make style 2013-01-30 14:54:03 +00:00
romuald@libnfc.org
8521f43051 Updates source code to use libnfc 1.7.0
This commit also fix some warnings.
2013-01-20 17:21:45 +00:00
romuald@libnfc.org
41a5a300ef Fix target selection 2012-09-28 08:42:39 +00:00
romuald@libnfc.org
03da52138f Fixes Issue 11. (thanks to maxx.h2) 2012-09-26 20:03:56 +00:00
romuald@libnfc.org
1d35e85a3b Suppress some warnings (discards ‘const’ qualifier from pointer target type): functions that manipulate filename does not overwrite it 2012-09-26 19:53:58 +00:00
romuald@libnfc.org
0de043935d Fix dirty prototypes: crapto1 3.2 version now exposes these functions. 2012-09-26 19:48:20 +00:00
romuald@libnfc.org
eddd55c6fc Suppress warning: function declaration isn’t a prototype, old-style function definition 2012-09-26 19:44:22 +00:00
romuald@libnfc.org
24964bb77a Suppress warning: function declaration isn’t a prototype 2012-09-26 19:39:32 +00:00
romuald@libnfc.org
925ea523e7 Remove some unused functions 2012-09-26 19:33:28 +00:00
romuald@libnfc.org
4a8cd8914e Upgrade code to use libnfc 1.6.x 2012-09-26 19:32:43 +00:00
romuald@libnfc.org
6865db5ad0 Remove some unused variables 2012-09-26 19:28:45 +00:00
romuald@libnfc.org
9d83e8a254 Update autotools files to use libnfc >= 1.6.0 2012-09-26 19:15:46 +00:00
romuald@libnfc.org
bb64564cad Sync crapto1 files with official crapto1 3.2 2012-09-26 19:14:01 +00:00
romuald@libnfc.org
7fe60310b0 Fix always true comparisons: pm3_log_multisect_decrypted (uint8_t) is always >= 0 and is always <= 256 2012-09-26 15:38:35 +00:00
romuald@libnfc.org
6c8b6190cb Removes some remaining ^M chars. 2012-09-23 10:44:23 +00:00
romuald@libnfc.org
91e4c89302 Enhance usage information. 2012-09-23 10:35:37 +00:00
romuald@libnfc.org
1026af5d3f Sync nfc-utils.* and mifare.* with current libnfc devel version 2012-09-23 10:34:32 +00:00
romuald@libnfc.org
1b6d022668 Convert all remaining dos files to unix format. 2012-09-23 10:29:36 +00:00
22 changed files with 3269 additions and 4117 deletions

20
.gitignore vendored Normal file
View File

@@ -0,0 +1,20 @@
.svn
*.o
*~
aclocal.m4
autom4te.cache/*
compile
config.h
config.h.in
config.log
config.status
configure
depcomp
install-sh
Makefile
Makefile.in
missing
src/.deps/
src/mfcuk.exe
src/mfcuk
stamp-h1

View File

@@ -1,4 +1,10 @@
SUBDIRS = src SUBDIRS = src
#pkgconfigdir = $(libdir)/pkgconfig style:
#pkgconfig_DATA = libnfc.pc find . -name "*.[ch]" -exec perl -pi -e 's/[ \t]+$$//' {} \;
find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \
--indent=spaces=2 --indent-switches --indent-preprocessor \
--keep-one-line-blocks --max-instatement-indent=60 \
--brackets=linux --pad-oper --unpad-paren --pad-header \
--align-pointer=name {} \;

5
README
View File

@@ -2,8 +2,7 @@ README
====== ======
Compiling: Compiling:
automake autoreconf -is
autoconf
./configure ./configure
make make
@@ -24,7 +23,7 @@ LICENSE
GPL. See MFCUK_LICENSE for more information. GPL. See MFCUK_LICENSE for more information.
BIBLIOGRPAHY (no specific order) BIBLIOGRAPHY (no specific order)
--------------------------------- ---------------------------------
1. [WPMCC09] - "Wirelessly Pickpocketing a Mifare Classic Card" 1. [WPMCC09] - "Wirelessly Pickpocketing a Mifare Classic Card"
2. [ESO08] - "2008-esorics.pdf" 2. [ESO08] - "2008-esorics.pdf"

View File

@@ -1,25 +1,22 @@
AC_INIT([mfcuk], [0.3.3], [zveriu@gmail.com]) AC_INIT([mfcuk], [0.3.8], [zveriu@gmail.com])
AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE
AC_PROG_CC AC_PROG_CC
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/mfcuk.c])
AM_INIT_AUTOMAKE
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
# Checks for pkg-config modules. # Checks for pkg-config modules.
LIBNFC_REQUIRED_VERSION=1.5.1 LIBNFC_REQUIRED_VERSION=1.7.0
PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])]) PKG_CHECK_MODULES([libnfc], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
PKG_CONFIG_REQUIRES="libnfc" PKG_CONFIG_REQUIRES="libnfc"
AC_SUBST([PKG_CONFIG_REQUIRES]) AC_SUBST([PKG_CONFIG_REQUIRES])
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
AC_HEADER_STDBOOL AC_HEADER_STDBOOL
AC_TYPE_SIZE_T AC_TYPE_SIZE_T
AC_TYPE_UINT16_T AC_TYPE_UINT16_T
@@ -30,12 +27,20 @@ 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])
AC_CHECK_FUNCS([memset strchr strtoul])
# Checks for endianness convertion # Checks for endianness convertion
AC_CHECK_HEADERS([endian.h sys/endian.h CoreFoundation/CoreFoundation.h]) AC_CHECK_HEADERS([endian.h sys/endian.h CoreFoundation/CoreFoundation.h])
if test $ac_cv_header_endian_h = "no" -a $ac_cv_header_sys_endian_h = "no" -a $ac_cv_header_CoreFoundation_CoreFoundation_h = "no"; then
AC_MSG_ERROR(["Can't locate usable header file for endianness convertions."]);
fi
AC_CHECK_HEADERS([byteswap.h]) AC_CHECK_HEADERS([byteswap.h])
AC_CHECK_HEADERS([unistd.h])
AM_CONDITIONAL([HAVE_UNISTD], [test $ac_cv_header_unistd_h = "yes"])
AC_DEFINE([_XOPEN_SOURCE], [600], [Define to 500 if Single Unix conformance is wanted, 600 for sixth revision.]) AC_DEFINE([_XOPEN_SOURCE], [600], [Define to 500 if Single Unix conformance is wanted, 600 for sixth revision.])
# Help us to write great code ;-) # Help us to write great code ;-)

View File

@@ -1,9 +1,15 @@
AM_CFLAGS = @LIBNFC_CFLAGS@ AM_CFLAGS = @libnfc_CFLAGS@
AM_LDFLAGS = @LIBNFC_LIBS@
bin_PROGRAMS = mfcuk bin_PROGRAMS = mfcuk
noinst_HEADERS = crapto1.h mifare.h nfc-utils.h mfcuk_mifare.h mfcuk_finger.h mfcuk_utils.h xgetopt.h mfcuk.h noinst_HEADERS = crapto1.h mifare.h nfc-utils.h mfcuk_mifare.h mfcuk_finger.h mfcuk_utils.h mfcuk.h xgetopt.h
mfcuk_SOURCES = crapto1.c crypto1.c mifare.c nfc-utils.c mfcuk_mifare.c mfcuk_finger.c mfcuk_utils.c xgetopt.c mfcuk.c
mfcuk_SOURCES = crapto1.c crypto1.c mifare.c nfc-utils.c mfcuk_mifare.c mfcuk_finger.c mfcuk_utils.c mfcuk.c
mfcuk_LDADD = @libnfc_LIBS@
# If system does not have unistd.h, use our own getopt function from xgetopt.c
if ! HAVE_UNISTD
mfcuk_SOURCES += xgetopt.c
endif
# dist_man_MANS = mfcuk.1 # dist_man_MANS = mfcuk.1

View File

@@ -22,52 +22,58 @@
#if !defined LOWMEM && defined __GNUC__ #if !defined LOWMEM && defined __GNUC__
static uint8_t filterlut[1 << 20]; static uint8_t filterlut[1 << 20];
static void __attribute__((constructor)) fill_lut() static void __attribute__((constructor)) fill_lut(void)
{ {
uint32_t i; uint32_t i;
for(i = 0; i < 1 << 20; ++i) for (i = 0; i < 1 << 20; ++i)
filterlut[i] = filter(i); filterlut[i] = filter(i);
} }
#define filter(x) (filterlut[(x) & 0xfffff]) #define filter(x) (filterlut[(x) & 0xfffff])
#endif #endif
static void quicksort(uint32_t* const start, uint32_t* const stop) static void quicksort(uint32_t *const start, uint32_t *const stop)
{ {
uint32_t *it = start + 1, *rit = stop; uint32_t *it = start + 1, *rit = stop;
if(it > rit) if (it > rit)
return; return;
while(it < rit) while (it < rit)
if(*it <= *start) if (*it <= *start)
++it; ++it;
else if(*rit > *start) else if (*rit > *start)
--rit; --rit;
else else {
*it ^= (*it ^= *rit, *rit ^= *it); uint32_t x = *it;
*it = *rit;
*rit = x;
}
if(*rit >= *start) if (*rit >= *start)
--rit; --rit;
if(rit != start) if (rit != start) {
*rit ^= (*rit ^= *start, *start ^= *rit); uint32_t x = *it;
*it = *rit;
*rit = x;
}
quicksort(start, rit - 1); quicksort(start, rit - 1);
quicksort(rit + 1, stop); quicksort(rit + 1, 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;
while(start != stop) while (start != stop)
if(start[mid = (stop - start) >> 1] > val) if (start[mid = (stop - start) >> 1] > val)
stop = &start[mid]; stop = &start[mid];
else else
start += mid + 1; start += mid + 1;
return start; return start;
} }
/** update_contribution /** update_contribution
@@ -76,11 +82,11 @@ binsearch(uint32_t *start, uint32_t *stop)
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;
p = p << 1 | parity(*item & mask1); p = p << 1 | parity(*item & mask1);
p = p << 1 | parity(*item & mask2); p = p << 1 | parity(*item & mask2);
*item = p << 24 | (*item & 0xffffff); *item = p << 24 | (*item & 0xffffff);
} }
/** extend_table /** extend_table
@@ -89,21 +95,21 @@ update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2)
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;
for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1)
if(filter(*tbl) ^ filter(*tbl | 1)) { if (filter(*tbl) ^ filter(*tbl | 1)) {
*tbl |= filter(*tbl) ^ bit; *tbl |= filter(*tbl) ^ bit;
update_contribution(tbl, m1, m2); update_contribution(tbl, m1, m2);
*tbl ^= in; *tbl ^= in;
} else if(filter(*tbl) == bit) { } else if (filter(*tbl) == bit) {
*++*end = tbl[1]; *++*end = tbl[1];
tbl[1] = tbl[0] | 1; tbl[1] = tbl[0] | 1;
update_contribution(tbl, m1, m2); update_contribution(tbl, m1, m2);
*tbl++ ^= in; *tbl++ ^= in;
update_contribution(tbl, m1, m2); update_contribution(tbl, m1, m2);
*tbl ^= in; *tbl ^= in;
} else } else
*tbl-- = *(*end)--; *tbl-- = *(*end)--;
} }
/** 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
@@ -111,244 +117,251 @@ extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in
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)
if(filter(*tbl) ^ filter(*tbl | 1)) { if (filter(*tbl) ^ filter(*tbl | 1)) {
*tbl |= filter(*tbl) ^ bit; *tbl |= filter(*tbl) ^ bit;
} else if(filter(*tbl) == bit) { } else if (filter(*tbl) == bit) {
*++*end = *++tbl; *++*end = *++tbl;
*tbl = tbl[-1] | 1; *tbl = tbl[-1] | 1;
} else } else
*tbl-- = *(*end)--; *tbl-- = *(*end)--;
} }
/** recover /** recover
* recursively narrow down the search space, 4 bits of keystream at a time * recursively narrow down the search space, 4 bits of keystream at a time
*/ */
static struct Crypto1State* static struct Crypto1State *
recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks,
uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem, uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem,
struct Crypto1State *sl, uint32_t in) struct Crypto1State *sl, uint32_t in) {
{ uint32_t *o, *e, i;
uint32_t *o, *e, i;
if(rem == -1) { if (rem == -1) {
for(e = e_head; e <= e_tail; ++e) { for (e = e_head; e <= e_tail; ++e) {
*e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4); *e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4);
for(o = o_head; o <= o_tail; ++o, ++sl) { for (o = o_head; o <= o_tail; ++o, ++sl) {
sl->even = *o; sl->even = *o;
sl->odd = *e ^ parity(*o & LF_POLY_ODD); sl->odd = *e ^ parity(*o & LF_POLY_ODD);
sl[1].odd = sl[1].even = 0; sl[1].odd = sl[1].even = 0;
} }
} }
return sl; return sl;
} }
for(i = 0; i < 4 && rem--; i++) { for (i = 0; i < 4 && rem--; i++) {
extend_table(o_head, &o_tail, (oks >>= 1) & 1, extend_table(o_head, &o_tail, (oks >>= 1) & 1,
LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0);
if(o_head > o_tail) if (o_head > o_tail)
return sl; return sl;
extend_table(e_head, &e_tail, (eks >>= 1) & 1, extend_table(e_head, &e_tail, (eks >>= 1) & 1,
LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, (in >>= 2) & 3); LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, (in >>= 2) & 3);
if(e_head > e_tail) if (e_head > e_tail)
return sl; return sl;
} }
quicksort(o_head, o_tail); quicksort(o_head, o_tail);
quicksort(e_head, e_tail); quicksort(e_head, e_tail);
while(o_tail >= o_head && e_tail >= e_head) while (o_tail >= o_head && e_tail >= e_head)
if(((*o_tail ^ *e_tail) >> 24) == 0) { if (((*o_tail ^ *e_tail) >> 24) == 0) {
o_tail = binsearch(o_head, o = o_tail); o_tail = binsearch(o_head, o = o_tail);
e_tail = binsearch(e_head, e = e_tail); e_tail = binsearch(e_head, e = e_tail);
sl = recover(o_tail--, o, oks, sl = recover(o_tail--, o, oks,
e_tail--, e, eks, rem, sl, in); e_tail--, e, eks, rem, sl, in);
} } else if (*o_tail > *e_tail)
else if(*o_tail > *e_tail) o_tail = binsearch(o_head, o_tail) - 1;
o_tail = binsearch(o_head, o_tail) - 1; else
else e_tail = binsearch(e_head, e_tail) - 1;
e_tail = binsearch(e_head, e_tail) - 1;
return sl; return sl;
} }
/** lfsr_recovery /** lfsr_recovery
* recover the state of the lfsr given 32 bits of the keystream * recover the state of the lfsr given 32 bits of the keystream
* additionally you can use the in parameter to specify the value * additionally you can use the in parameter to specify the value
* that was fed into the lfsr at the time the keystream was generated * that was fed into the lfsr at the time the keystream was generated
*/ */
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in) struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in) {
{ struct Crypto1State *statelist;
struct Crypto1State *statelist; uint32_t *odd_head = 0, *odd_tail = 0, oks = 0;
uint32_t *odd_head = 0, *odd_tail = 0, oks = 0; uint32_t *even_head = 0, *even_tail = 0, eks = 0;
uint32_t *even_head = 0, *even_tail = 0, eks = 0; int i;
int i;
for(i = 31; i >= 0; i -= 2) for (i = 31; i >= 0; i -= 2)
oks = oks << 1 | BEBIT(ks2, i); oks = oks << 1 | BEBIT(ks2, i);
for(i = 30; i >= 0; i -= 2) for (i = 30; i >= 0; i -= 2)
eks = eks << 1 | BEBIT(ks2, i); eks = eks << 1 | BEBIT(ks2, i);
odd_head = odd_tail = malloc(sizeof(uint32_t) << 21); odd_head = odd_tail = malloc(sizeof(uint32_t) << 21);
even_head = even_tail = malloc(sizeof(uint32_t) << 21); even_head = even_tail = malloc(sizeof(uint32_t) << 21);
statelist = malloc(sizeof(struct Crypto1State) << 18); statelist = malloc(sizeof(struct Crypto1State) << 18);
if(!odd_tail-- || !even_tail-- || !statelist) if (!odd_tail-- || !even_tail-- || !statelist)
goto out; goto out;
statelist->odd = statelist->even = 0; statelist->odd = statelist->even = 0;
for(i = 1 << 20; i >= 0; --i) { for (i = 1 << 20; i >= 0; --i) {
if(filter(i) == (oks & 1)) if (filter(i) == (oks & 1))
*++odd_tail = i; *++odd_tail = i;
if(filter(i) == (eks & 1)) if (filter(i) == (eks & 1))
*++even_tail = i; *++even_tail = i;
} }
for(i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1); extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1);
extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1); extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1);
} }
in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00);
recover(odd_head, odd_tail, oks, recover(odd_head, odd_tail, oks,
even_head, even_tail, eks, 11, statelist, in << 1); even_head, even_tail, eks, 11, statelist, in << 1);
out: out:
free(odd_head); free(odd_head);
free(even_head); free(even_head);
return statelist; return statelist;
} }
static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214, static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214,
0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83, 0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83,
0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA}; 0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA
};
static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60, static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60,
0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8, 0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8,
0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20, 0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20,
0x7EC7EE90, 0x7F63F748, 0x79117020}; 0x7EC7EE90, 0x7F63F748, 0x79117020
};
static const uint32_t T1[] = { static const uint32_t T1[] = {
0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66, 0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66,
0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B, 0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B,
0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615, 0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615,
0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C}; 0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C
};
static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0, static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0,
0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268, 0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268,
0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0, 0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0,
0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0, 0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0,
0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950, 0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950,
0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0}; 0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0
};
static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD}; static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD};
static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0}; static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0};
/** Reverse 64 bits of keystream into possible cipher states /** Reverse 64 bits of keystream into possible cipher states
* Variation mentioned in the paper. Somewhat optimized version * Variation mentioned in the paper. Somewhat optimized version
*/ */
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3) struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3) {
{ struct Crypto1State *statelist, *sl;
struct Crypto1State *statelist, *sl; uint8_t oks[32], eks[32], hi[32];
uint8_t oks[32], eks[32], hi[32]; uint32_t low = 0, win = 0;
uint32_t low = 0, win = 0; uint32_t *tail, table[1 << 16];
uint32_t *tail, table[1 << 16]; int i, j;
int i, j;
sl = statelist = malloc(sizeof(struct Crypto1State) << 4); sl = statelist = malloc(sizeof(struct Crypto1State) << 4);
if(!sl) if (!sl)
return 0; return 0;
sl->odd = sl->even = 0; sl->odd = sl->even = 0;
for(i = 30; i >= 0; i -= 2) { for (i = 30; i >= 0; i -= 2) {
oks[i >> 1] = BIT(ks2, i ^ 24); oks[i >> 1] = BIT(ks2, i ^ 24);
oks[16 + (i >> 1)] = BIT(ks3, i ^ 24); oks[16 + (i >> 1)] = BIT(ks3, i ^ 24);
} }
for(i = 31; i >= 0; i -= 2) { for (i = 31; i >= 0; i -= 2) {
eks[i >> 1] = BIT(ks2, i ^ 24); eks[i >> 1] = BIT(ks2, i ^ 24);
eks[16 + (i >> 1)] = BIT(ks3, i ^ 24); eks[16 + (i >> 1)] = BIT(ks3, i ^ 24);
} }
for(i = 0xfffff; i >= 0; --i) { for (i = 0xfffff; i >= 0; --i) {
if (filter(i) != oks[0]) if (filter(i) != oks[0])
continue; continue;
*(tail = table) = i; *(tail = table) = i;
for(j = 1; tail >= table && j < 29; ++j) for (j = 1; tail >= table && j < 29; ++j)
extend_table_simple(table, &tail, oks[j]); extend_table_simple(table, &tail, oks[j]);
if(tail < table) if (tail < table)
continue; continue;
for(j = 0; j < 19; ++j) for (j = 0; j < 19; ++j)
low = low << 1 | parity(i & S1[j]); low = low << 1 | parity(i & S1[j]);
for(j = 0; j < 32; ++j) for (j = 0; j < 32; ++j)
hi[j] = parity(i & T1[j]); hi[j] = parity(i & T1[j]);
for(; tail >= table; --tail) { for (; tail >= table; --tail) {
for(j = 0; j < 3; ++j) { for (j = 0; j < 3; ++j) {
*tail = *tail << 1; *tail = *tail << 1;
*tail |= parity((i & C1[j]) ^ (*tail & C2[j])); *tail |= parity((i & C1[j]) ^(*tail & C2[j]));
if(filter(*tail) != oks[29 + j]) if (filter(*tail) != oks[29 + j])
goto continue2; goto continue2;
} }
for(j = 0; j < 19; ++j) for (j = 0; j < 19; ++j)
win = win << 1 | parity(*tail & S2[j]); win = win << 1 | parity(*tail & S2[j]);
win ^= low; win ^= low;
for(j = 0; j < 32; ++j) { for (j = 0; j < 32; ++j) {
win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]); win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]);
if(filter(win) != eks[j]) if (filter(win) != eks[j])
goto continue2; goto continue2;
} }
*tail = *tail << 1 | parity(LF_POLY_EVEN & *tail); *tail = *tail << 1 | parity(LF_POLY_EVEN & *tail);
sl->odd = *tail ^ parity(LF_POLY_ODD & win); sl->odd = *tail ^ parity(LF_POLY_ODD & win);
sl->even = win; sl->even = win;
++sl; ++sl;
sl->odd = sl->even = 0; sl->odd = sl->even = 0;
continue2:; continue2:
} ;
} }
return statelist; }
return statelist;
} }
uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb);
uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb);
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd);
/** lfsr_rollback_bit /** lfsr_rollback_bit
* Rollback the shift register in order to get previous states * Rollback the shift register in order to get previous states
*/ */
uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb)
{ {
int out; int out;
uint8_t ret; uint8_t ret;
s->odd &= 0xffffff; s->odd &= 0xffffff;
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); uint32_t x = s->odd;
s->odd = s->even;
s->even = x;
out = s->even & 1; out = s->even & 1;
out ^= LF_POLY_EVEN & (s->even >>= 1); out ^= LF_POLY_EVEN & (s->even >>= 1);
out ^= LF_POLY_ODD & s->odd; out ^= LF_POLY_ODD & s->odd;
out ^= !!in; out ^= !!in;
out ^= (ret = filter(s->odd)) & !!fb; out ^= (ret = filter(s->odd)) & !!fb;
s->even |= parity(out) << 23; s->even |= parity(out) << 23;
return ret; return ret;
} }
/** lfsr_rollback_byte /** lfsr_rollback_byte
* Rollback the shift register in order to get previous states * Rollback the shift register in order to get previous states
*/ */
uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb)
{ {
int i; int i;
uint8_t ret = 0; uint8_t ret = 0;
for (i = 7; i >= 0; --i) for (i = 7; i >= 0; --i)
ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i; ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i;
return ret; return ret;
} }
/** lfsr_rollback_word /** lfsr_rollback_word
* Rollback the shift register in order to get previous states * Rollback the shift register in order to get previous states
*/ */
uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb)
{ {
int i; int i;
uint32_t ret = 0; uint32_t ret = 0;
for (i = 31; i >= 0; --i) for (i = 31; i >= 0; --i)
ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24);
return ret; return ret;
} }
/** nonce_distance /** nonce_distance
@@ -357,23 +370,24 @@ uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb)
static uint16_t *dist = 0; static uint16_t *dist = 0;
int nonce_distance(uint32_t from, uint32_t to) int nonce_distance(uint32_t from, uint32_t to)
{ {
uint16_t x, i; uint16_t x, i;
if(!dist) { if (!dist) {
dist = malloc(2 << 16); dist = malloc(2 << 16);
if(!dist) if (!dist)
return -1; return -1;
for (x = i = 1; i; ++i) { for (x = i = 1; i; ++i) {
dist[(x & 0xff) << 8 | x >> 8] = i; dist[(x & 0xff) << 8 | x >> 8] = i;
x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15;
} }
} }
return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535; return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535;
} }
static uint32_t fastfwd[2][8] = { static uint32_t fastfwd[2][8] = {
{ 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB}, { 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB},
{ 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980}}; { 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980}
};
/** lfsr_prefix_ks /** lfsr_prefix_ks
@@ -387,60 +401,59 @@ static uint32_t fastfwd[2][8] = {
*/ */
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd)
{ {
uint32_t c, entry, *candidates = malloc(4 << 21); uint32_t c, entry, *candidates = malloc(4 << 21);
int i, size = (1 << 21) - 1; int i, size = (1 << 21) - 1;
if(!candidates) if (!candidates)
return 0; return 0;
for(i = 0; i <= size; ++i) for (i = 0; i <= size; ++i)
candidates[i] = i; candidates[i] = i;
for(c = 0; c < 8; ++c) for (c = 0; c < 8; ++c)
for(i = 0;i <= size; ++i) { for (i = 0; i <= size; ++i) {
entry = candidates[i] ^ fastfwd[isodd][c]; entry = candidates[i] ^ fastfwd[isodd][c];
if(filter(entry >> 1) != BIT(ks[c], isodd) || if (filter(entry >> 1) != BIT(ks[c], isodd) ||
filter(entry) != BIT(ks[c], isodd + 2)) filter(entry) != BIT(ks[c], isodd + 2))
candidates[i--] = candidates[size--]; candidates[i--] = candidates[size--];
} }
candidates[size + 1] = -1; candidates[size + 1] = -1;
return candidates; return candidates;
} }
/** check_pfx_parity /** check_pfx_parity
* helper function which eliminates possible secret states using parity bits * helper function which eliminates possible secret states using parity bits
*/ */
static struct Crypto1State* static struct Crypto1State *
check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],
uint32_t odd, uint32_t even, struct Crypto1State* sl) uint32_t odd, uint32_t even, struct Crypto1State *sl) {
{ uint32_t ks1, nr, ks2, rr, ks3, c, good = 1;
uint32_t ks1, nr, ks2, rr, ks3, c, good = 1;
for(c = 0; good && c < 8; ++c) { for (c = 0; good && c < 8; ++c) {
sl->odd = odd ^ fastfwd[1][c]; sl->odd = odd ^ fastfwd[1][c];
sl->even = even ^ fastfwd[0][c]; sl->even = even ^ fastfwd[0][c];
lfsr_rollback_bit(sl, 0, 0); lfsr_rollback_bit(sl, 0, 0);
lfsr_rollback_bit(sl, 0, 0); lfsr_rollback_bit(sl, 0, 0);
ks3 = lfsr_rollback_bit(sl, 0, 0); ks3 = lfsr_rollback_bit(sl, 0, 0);
ks2 = lfsr_rollback_word(sl, 0, 0); ks2 = lfsr_rollback_word(sl, 0, 0);
ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1); ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1);
nr = ks1 ^ (prefix | c << 5); nr = ks1 ^(prefix | c << 5);
rr = ks2 ^ rresp; rr = ks2 ^ rresp;
good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24);
good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16);
good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8);
good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0);
good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3; good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3;
} }
return sl + good; return sl + good;
} }
@@ -453,35 +466,34 @@ check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],
* It returns a zero terminated list of possible cipher states after the * It returns a zero terminated list of possible cipher states after the
* tag nonce was fed in * tag nonce was fed in
*/ */
struct Crypto1State* struct Crypto1State *
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) {
{ struct Crypto1State *statelist, *s;
struct Crypto1State *statelist, *s; uint32_t *odd, *even, *o, *e, top;
uint32_t *odd, *even, *o, *e, top;
odd = lfsr_prefix_ks(ks, 1); odd = lfsr_prefix_ks(ks, 1);
even = lfsr_prefix_ks(ks, 0); even = lfsr_prefix_ks(ks, 0);
s = statelist = malloc((sizeof *statelist) << 20); s = statelist = malloc((sizeof *statelist) << 20);
if(!s || !odd || !even) { if (!s || !odd || !even) {
free(odd); free(odd);
free(even); free(even);
free(statelist); free(statelist);
return 0; return 0;
} }
for(o = odd; *o + 1; ++o) for (o = odd; *o + 1; ++o)
for(e = even; *e + 1; ++e) for (e = even; *e + 1; ++e)
for(top = 0; top < 64; ++top) { for (top = 0; top < 64; ++top) {
*o += 1 << 21; *o += 1 << 21;
*e += (!(top & 7) + 1) << 21; *e += (!(top & 7) + 1) << 21;
s = check_pfx_parity(pfx, rr, par, *o, *e, s); s = check_pfx_parity(pfx, rr, par, *o, *e, s);
} }
s->odd = s->even = 0; s->odd = s->even = 0;
free(odd); free(odd);
free(even); free(even);
return statelist; return statelist;
} }

View File

@@ -24,66 +24,66 @@
extern "C" { extern "C" {
#endif #endif
struct Crypto1State {uint32_t odd, even;}; struct Crypto1State {uint32_t odd, even;};
struct Crypto1State* crypto1_create(uint64_t); struct Crypto1State *crypto1_create(uint64_t);
void crypto1_destroy(struct Crypto1State*); void crypto1_destroy(struct Crypto1State *);
void crypto1_get_lfsr(struct Crypto1State*, uint64_t*); void crypto1_get_lfsr(struct Crypto1State *, uint64_t *);
uint8_t crypto1_bit(struct Crypto1State*, uint8_t, int); uint8_t crypto1_bit(struct Crypto1State *, uint8_t, int);
uint8_t crypto1_byte(struct Crypto1State*, uint8_t, int); uint8_t crypto1_byte(struct Crypto1State *, uint8_t, int);
uint32_t crypto1_word(struct Crypto1State*, uint32_t, int); uint32_t crypto1_word(struct Crypto1State *, uint32_t, int);
uint32_t prng_successor(uint32_t x, uint32_t n); uint32_t prng_successor(uint32_t x, uint32_t n);
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in); struct Crypto1State *lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]);
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3); struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in);
struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3);
void lfsr_rollback(struct Crypto1State* s, uint32_t in, int fb); void lfsr_rollback(struct Crypto1State *s, uint32_t in, int fb);
int nonce_distance(uint32_t from, uint32_t to); uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb);
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;\
int __i;\ int __i;\
for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\ for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\
for(__i = FSIZE - 1; __i >= 0; __i--)\ for(__i = FSIZE - 1; __i >= 0; __i--)\
if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\ if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\
break;\ break;\
else if(__i)\ else if(__i)\
__M = prng_successor(__M, (__i == 7) ? 48 : 8);\ __M = prng_successor(__M, (__i == 7) ? 48 : 8);\
else else
#define LF_POLY_ODD (0x29CE5C) #define LF_POLY_ODD (0x29CE5C)
#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;
x ^= x >> 8; x ^= x >> 8;
x ^= x >> 4; x ^= x >> 4;
return BIT(0x6996, x & 0xf); return BIT(0x6996, x & 0xf);
#else #else
__asm__( __asm__("movl %1, %%eax\n"
"movl %1, %%eax\n" "mov %%ax, %%cx\n"
"mov %%ax, %%cx\n" "shrl $0x10, %%eax\n"
"shrl $0x10, %%eax\n" "xor %%ax, %%cx\n"
"xor %%ax, %%cx\n" "xor %%ch, %%cl\n"
"xor %%ch, %%cl\n" "setpo %%al\n"
"setpo %%al\n" "movzx %%al, %0\n": "=r"(x) : "r"(x): "eax", "ecx");
"movzx %%al, %0\n": "=r"(x) : "r"(x): "eax","ecx" 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;
f = 0xf22c0 >> (x & 0xf) & 16; f = 0xf22c0 >> (x & 0xf) & 16;
f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8; f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8;
f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4; f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4;
f |= 0x1e458 >> (x >> 12 & 0xf) & 2; f |= 0x1e458 >> (x >> 12 & 0xf) & 2;
f |= 0x0d938 >> (x >> 16 & 0xf) & 1; f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
return BIT(0xEC57E80A, f); return BIT(0xEC57E80A, f);
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -21,63 +21,64 @@
#include <stdlib.h> #include <stdlib.h>
#define SWAPENDIAN(x)\ #define SWAPENDIAN(x)\
(x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16)
struct Crypto1State * crypto1_create(uint64_t key) struct Crypto1State *crypto1_create(uint64_t key) {
{ struct Crypto1State *s = malloc(sizeof(*s));
struct Crypto1State *s = malloc(sizeof(*s)); int i;
int i;
for(i = 47;s && i > 0; i -= 2) { for (i = 47; s && i > 0; i -= 2) {
s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7); s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7);
s->even = s->even << 1 | BIT(key, i ^ 7); s->even = s->even << 1 | BIT(key, i ^ 7);
} }
return s; return s;
} }
void crypto1_destroy(struct Crypto1State *state) void crypto1_destroy(struct Crypto1State *state)
{ {
free(state); free(state);
} }
void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr) void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr)
{ {
int i; int i;
for(*lfsr = 0, i = 23; i >= 0; --i) { for (*lfsr = 0, i = 23; i >= 0; --i) {
*lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3); *lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3);
*lfsr = *lfsr << 1 | BIT(state->even, i ^ 3); *lfsr = *lfsr << 1 | BIT(state->even, i ^ 3);
} }
} }
uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
{ {
uint32_t feedin; uint32_t feedin;
uint8_t ret = filter(s->odd); uint8_t ret = filter(s->odd);
feedin = ret & !!is_encrypted; feedin = ret & !!is_encrypted;
feedin ^= !!in; feedin ^= !!in;
feedin ^= LF_POLY_ODD & s->odd; feedin ^= LF_POLY_ODD & s->odd;
feedin ^= LF_POLY_EVEN & s->even; feedin ^= LF_POLY_EVEN & s->even;
s->even = s->even << 1 | parity(feedin); s->even = s->even << 1 | parity(feedin);
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); uint32_t x = s->odd;
s->odd = s->even;
s->even = x;
return ret; return ret;
} }
uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted)
{ {
uint8_t i, ret = 0; uint8_t i, ret = 0;
for (i = 0; i < 8; ++i) for (i = 0; i < 8; ++i)
ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i; ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i;
return ret; return ret;
} }
uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted)
{ {
uint32_t i, ret = 0; uint32_t i, ret = 0;
for (i = 0; i < 32; ++i) for (i = 0; i < 32; ++i)
ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24); ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24);
return ret; return ret;
} }
/* prng_successor /* prng_successor
@@ -85,9 +86,9 @@ uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted)
*/ */
uint32_t prng_successor(uint32_t x, uint32_t n) uint32_t prng_successor(uint32_t x, uint32_t n)
{ {
SWAPENDIAN(x); SWAPENDIAN(x);
while(n--) while (n--)
x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
return SWAPENDIAN(x); return SWAPENDIAN(x);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -92,29 +92,28 @@
#define MFCUK_DARKSIDE_START_NR 0xDEADBEEF #define MFCUK_DARKSIDE_START_NR 0xDEADBEEF
#define MFCUK_DARKSIDE_START_AR 0xFACECAFE #define MFCUK_DARKSIDE_START_AR 0xFACECAFE
typedef struct tag_nonce_entry typedef struct tag_nonce_entry {
{ uint32_t tagNonce; // Tag nonce we target for fixation
uint32_t tagNonce; // Tag nonce we target for fixation uint8_t spoofFlag; // No spoofing until we have a successful auth with this tagNonce. Once we have, we want to spoof to get the encrypted 0x5 value
byte_t spoofFlag; // No spoofing until we have a successful auth with this tagNonce. Once we have, we want to spoof to get the encrypted 0x5 value uint32_t num_of_appearances; // For statistics, how many times this tag nonce appeared for the given SLEEP_ values
uint32_t num_of_appearances; // For statistics, how many times this tag nonce appeared for the given SLEEP_ values
// STAGE1 data for "dark side" and lsfr_common_prefix() // STAGE1 data for "dark side" and lsfr_common_prefix()
uint32_t spoofNrPfx; // PARAM: used as pfx, calculated from (spoofNrEnc & 0xFFFFFF1F). BUG: weird way to denote "first 29 prefix bits" in "dark side" paper. Perhaps I see the world different uint32_t spoofNrPfx; // PARAM: used as pfx, calculated from (spoofNrEnc & 0xFFFFFF1F). BUG: weird way to denote "first 29 prefix bits" in "dark side" paper. Perhaps I see the world different
uint32_t spoofNrEnc; // {Nr} value which we will be using to make the tag respond with 4 bits uint32_t spoofNrEnc; // {Nr} value which we will be using to make the tag respond with 4 bits
uint32_t spoofArEnc; // PARAM: used as rr uint32_t spoofArEnc; // PARAM: used as rr
uint8_t spoofParBitsEnc; // parity bits we are trying to guess for the first time uint8_t spoofParBitsEnc; // parity bits we are trying to guess for the first time
uint8_t spoofNackEnc; // store here the encrypted NACK returned first time we match the parity bits uint8_t spoofNackEnc; // store here the encrypted NACK returned first time we match the parity bits
uint8_t spoofKs; // store here the keystream ks used for encryptying spoofNackEnc, specifically spoofKs = spoofNackEnc ^ 0x5 uint8_t spoofKs; // store here the keystream ks used for encryptying spoofNackEnc, specifically spoofKs = spoofNackEnc ^ 0x5
// STAGE2 data for "dark side" and lsfr_common_prefix() // STAGE2 data for "dark side" and lsfr_common_prefix()
int current_out_of_8; // starting from -1 until we find parity for chosen spoofNrEnc,spoofArEnc int current_out_of_8; // starting from -1 until we find parity for chosen spoofNrEnc,spoofArEnc
uint8_t parBitsCrntCombination[MFCUK_DARKSIDE_MAX_LEVELS]; // Loops over 32 combinations of the last 5 parity bits which generated the 4 bit NACK in STAGE1 uint8_t parBitsCrntCombination[MFCUK_DARKSIDE_MAX_LEVELS]; // Loops over 32 combinations of the last 5 parity bits which generated the 4 bit NACK in STAGE1
uint32_t nrEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // the 29 bits constant prefix, varying only 3 bits, thus 8 possible values uint32_t nrEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // the 29 bits constant prefix, varying only 3 bits, thus 8 possible values
uint32_t arEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // the same reader response as spoofArEnc; redundant but... :) uint32_t arEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // the same reader response as spoofArEnc; redundant but... :)
uint8_t ks[MFCUK_DARKSIDE_MAX_LEVELS]; // PARAM: used as ks, obtained as (ks[i] = nackEnc[i] ^ 0x5) uint8_t ks[MFCUK_DARKSIDE_MAX_LEVELS]; // PARAM: used as ks, obtained as (ks[i] = nackEnc[i] ^ 0x5)
uint8_t nackEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // store here the encrypted 4 bits values which tag responded uint8_t nackEnc[MFCUK_DARKSIDE_MAX_LEVELS]; // store here the encrypted 4 bits values which tag responded
uint8_t parBits[MFCUK_DARKSIDE_MAX_LEVELS]; // store here the values based on spoofParBitsEnc, varying only last 5 bits uint8_t parBits[MFCUK_DARKSIDE_MAX_LEVELS]; // store here the values based on spoofParBitsEnc, varying only last 5 bits
uint8_t parBitsArr[MFCUK_DARKSIDE_MAX_LEVELS][8]; // PARAM: used as par, contains value of parBits byte-bit values just splitted out one bit per byte thus second pair of braces [8] uint8_t parBitsArr[MFCUK_DARKSIDE_MAX_LEVELS][8]; // PARAM: used as par, contains value of parBits byte-bit values just splitted out one bit per byte thus second pair of braces [8]
} tag_nonce_entry_t; } tag_nonce_entry_t;
#endif // _MFCUK_KEYRECOVERY_DARKSIDE_H_ #endif // _MFCUK_KEYRECOVERY_DARKSIDE_H_

View File

@@ -38,179 +38,150 @@
#include "mfcuk_finger.h" #include "mfcuk_finger.h"
mfcuk_finger_tmpl_entry mfcuk_finger_db[] = 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]);
int mfcuk_finger_default_decoder(mifare_classic_tag *dump) int mfcuk_finger_default_decoder(mifare_classic_tag *dump)
{ {
if (!dump) if (!dump) {
{ fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n");
fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n"); return 0;
return 0; }
}
printf("UID:\t%02x%02x%02x%02x\n", dump->amb[0].mbm.abtUID[0], dump->amb[0].mbm.abtUID[1], dump->amb[0].mbm.abtUID[2], dump->amb[0].mbm.abtUID[3]); printf("UID:\t%02x%02x%02x%02x\n", dump->amb[0].mbm.abtUID[0], dump->amb[0].mbm.abtUID[1], dump->amb[0].mbm.abtUID[2], dump->amb[0].mbm.abtUID[3]);
printf("TYPE:\t%02x\n", dump->amb[0].mbm.btUnknown); printf("TYPE:\t%02x\n", dump->amb[0].mbm.btUnknown);
return 1; return 1;
} }
// Yes, I know C++ class inheritance would perfectly fit the decoders/comparators... Though C is more to my heart. Anyone to rewrite in C++? // Yes, I know C++ class inheritance would perfectly fit the decoders/comparators... Though C is more to my heart. Anyone to rewrite in C++?
int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump) int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump)
{ {
unsigned char *dump_ptr = NULL; if (!dump) {
unsigned short car_number = 0; fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n");
return 0;
}
if (!dump) printf("Bulgaria/Sofia/SKGT public transport card information decoder (info credits to Andy)\n");
{ mfcuk_finger_default_decoder(dump);
fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n");
return 0;
}
dump_ptr = (unsigned char *) dump; printf("LAST TRAVEL DATA\n");
printf("Bulgaria/Sofia/SKGT public transport card information decoder (info credits to Andy)\n"); // TODO: get proper information
mfcuk_finger_default_decoder(dump);
printf("LAST TRAVEL DATA\n"); return 1;
// TODO: get proper information
return 1;
} }
int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score) int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score)
{ {
int max_bytes = 0; int max_bytes = 0;
int i; int i;
int num_bytes_tomatch = 0; int num_bytes_tomatch = 0;
int num_bytes_matched = 0; int num_bytes_matched = 0;
if ( (!dump) || (!tmpl) || (!score) ) if ((!dump) || (!tmpl) || (!score)) {
{ return 0;
return 0; }
if (IS_MIFARE_CLASSIC_1K_TAG(dump)) {
max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_1K_MAX_BLOCKS;
} else if (IS_MIFARE_CLASSIC_4K_TAG(dump)) {
max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_4K_MAX_BLOCKS;
} else {
return 0;
}
for (i = 0; i < max_bytes; i++) {
if (((char *)(&tmpl->mask))[i] == 0x0) {
continue;
} }
if (IS_MIFARE_CLASSIC_1K_TAG(dump)) num_bytes_tomatch++;
{
max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_1K_MAX_BLOCKS;
}
else if (IS_MIFARE_CLASSIC_4K_TAG(dump))
{
max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_4K_MAX_BLOCKS;
}
else
{
return 0;
}
for (i=0; i<max_bytes; i++) if (((char *)(&tmpl->values))[i] == ((char *)dump)[i]) {
{ num_bytes_matched++;
if ( ((char *)(&tmpl->mask))[i] == 0x0 )
{
continue;
}
num_bytes_tomatch++;
if ( ((char *)(&tmpl->values))[i] == ((char *)dump)[i] )
{
num_bytes_matched++;
}
} }
}
if (num_bytes_tomatch == 0) if (num_bytes_tomatch == 0) {
{ return 0;
return 0; } else {
} *score = (float)(num_bytes_matched) / num_bytes_tomatch;
else }
{
*score = (float)(num_bytes_matched)/num_bytes_tomatch;
}
return 1; return 1;
} }
int mfcuk_finger_load() int mfcuk_finger_load(void)
{ {
int i; int i;
mifare_classic_tag mask; mifare_classic_tag mask;
mifare_classic_tag values; mifare_classic_tag values;
FILE *fp = NULL; FILE *fp = NULL;
size_t result = 0; size_t result = 0;
mfcuk_finger_template *tmpl_new = NULL; mfcuk_finger_template *tmpl_new = NULL;
int template_loaded_count = 0; int template_loaded_count = 0;
for (i = 0; i<mfcuk_finger_db_entries; i++) for (i = 0; i < mfcuk_finger_db_entries; i++) {
{ fp = fopen(mfcuk_finger_db[i].tmpl_filename, "rb");
fp = fopen(mfcuk_finger_db[i].tmpl_filename, "rb");
if (!fp) if (!fp) {
{ fprintf(stderr, "WARN: cannot open template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fprintf(stderr, "WARN: cannot open template file '%s'\n", mfcuk_finger_db[i].tmpl_filename); continue;
continue;
}
// If not read exactly 1 record, something is wrong
if ( (result = fread((void *)(&mask), sizeof(mask), 1, fp)) != 1)
{
fprintf(stderr, "WARN: cannot read MASK from template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fclose(fp);
continue;
}
// If not read exactly 1 record, something is wrong
if ( (result = fread((void *)(&values), sizeof(values), 1, fp)) != 1)
{
fprintf(stderr, "WARN: cannot read VALUES template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fclose(fp);
continue;
}
if (mfcuk_finger_db[i].tmpl_data == 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);
fclose(fp);
continue;
}
memcpy( &(tmpl_new->mask), &(mask), sizeof(mask));
memcpy( &(tmpl_new->values), &(values), sizeof(values));
mfcuk_finger_db[i].tmpl_data = tmpl_new;
template_loaded_count++;
}
if (fp)
{
fclose(fp);
fp = NULL;
}
} }
return template_loaded_count; // If not read exactly 1 record, something is wrong
if ((result = fread((void *)(&mask), sizeof(mask), 1, fp)) != 1) {
fprintf(stderr, "WARN: cannot read MASK from template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fclose(fp);
continue;
}
// If not read exactly 1 record, something is wrong
if ((result = fread((void *)(&values), sizeof(values), 1, fp)) != 1) {
fprintf(stderr, "WARN: cannot read VALUES template file '%s'\n", mfcuk_finger_db[i].tmpl_filename);
fclose(fp);
continue;
}
if (mfcuk_finger_db[i].tmpl_data == 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);
fclose(fp);
continue;
}
memcpy(&(tmpl_new->mask), &(mask), sizeof(mask));
memcpy(&(tmpl_new->values), &(values), sizeof(values));
mfcuk_finger_db[i].tmpl_data = tmpl_new;
template_loaded_count++;
}
if (fp) {
fclose(fp);
fp = NULL;
}
}
return template_loaded_count;
} }
int mfcuk_finger_unload() int mfcuk_finger_unload(void)
{ {
int i; int i;
for (i = 0; i<mfcuk_finger_db_entries; i++) for (i = 0; i < mfcuk_finger_db_entries; i++) {
{ if (mfcuk_finger_db[i].tmpl_data != NULL) {
if (mfcuk_finger_db[i].tmpl_data != NULL) free(mfcuk_finger_db[i].tmpl_data);
{ mfcuk_finger_db[i].tmpl_data = NULL;
free(mfcuk_finger_db[i].tmpl_data);
mfcuk_finger_db[i].tmpl_data = NULL;
}
} }
}
return 1; return 1;
} }

View File

@@ -45,24 +45,22 @@
#include "mfcuk_mifare.h" #include "mfcuk_mifare.h"
// Wrapping an ugly template into an externally pleasant name. To implement proper template later. // Wrapping an ugly template into an externally pleasant name. To implement proper template later.
typedef struct _mfcuk_finger_template_ typedef struct _mfcuk_finger_template_ {
{ mifare_classic_tag mask;
mifare_classic_tag mask; mifare_classic_tag values;
mifare_classic_tag values;
} mfcuk_finger_template; } mfcuk_finger_template;
// Function type definition, to be used for custom decoders/comparators // Function type definition, to be used for custom decoders/comparators
typedef int (*mfcuk_finger_comparator) (mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score); typedef int (*mfcuk_finger_comparator)(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score);
typedef int (*mfcuk_finger_decoder) (mifare_classic_tag *dump); typedef int (*mfcuk_finger_decoder)(mifare_classic_tag *dump);
// Naive implementation of a self-contained fingerprint database entry // Naive implementation of a self-contained fingerprint database entry
typedef struct _mfcuk_finger_tmpl_entry_ typedef struct _mfcuk_finger_tmpl_entry_ {
{ const char *tmpl_filename;
char *tmpl_filename; const char *tmpl_name;
char *tmpl_name; mfcuk_finger_comparator tmpl_comparison_func;
mfcuk_finger_comparator tmpl_comparison_func; mfcuk_finger_decoder tmpl_decoder_func;
mfcuk_finger_decoder tmpl_decoder_func; mfcuk_finger_template *tmpl_data;
mfcuk_finger_template *tmpl_data;
} mfcuk_finger_tmpl_entry; } mfcuk_finger_tmpl_entry;
int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score); int mfcuk_finger_default_comparator(mifare_classic_tag *dump, mfcuk_finger_template *tmpl, float *score);
@@ -70,7 +68,7 @@ int mfcuk_finger_default_decoder(mifare_classic_tag *dump);
int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump); int mfcuk_finger_skgt_decoder(mifare_classic_tag *dump);
// "Housekeeping" functions // "Housekeeping" functions
int mfcuk_finger_load(); int mfcuk_finger_load(void);
int mfcuk_finger_unload(); int mfcuk_finger_unload(void);
#endif #endif

View File

@@ -53,508 +53,411 @@
#include "mfcuk_mifare.h" #include "mfcuk_mifare.h"
// Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention! // Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention!
byte_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH] = uint8_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH] = {
{ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Place-holder for current key to verify
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Place-holder for current key to verify {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5},
{0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5},
{0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd},
{0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd}, {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a},
{0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a}, {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7},
{0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
}; };
int mfcuk_default_keys_num = sizeof(mfcuk_default_keys)/sizeof(mfcuk_default_keys[0]); int mfcuk_default_keys_num = sizeof(mfcuk_default_keys) / sizeof(mfcuk_default_keys[0]);
bool is_valid_block(byte_t bTagType, uint32_t uiBlock) bool is_valid_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( IS_MIFARE_CLASSIC_1K(bTagType) && (uiBlock < MIFARE_CLASSIC_1K_MAX_BLOCKS) ) if (IS_MIFARE_CLASSIC_1K(bTagType) && (uiBlock < MIFARE_CLASSIC_1K_MAX_BLOCKS)) {
{ return true;
return true; }
}
if ( IS_MIFARE_CLASSIC_4K(bTagType) && (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS) ) if (IS_MIFARE_CLASSIC_4K(bTagType) && (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS)) {
{ return true;
return true; }
}
return false; return false;
} }
bool is_valid_sector(byte_t bTagType, uint32_t uiSector) bool is_valid_sector(uint8_t bTagType, uint32_t uiSector)
{ {
if ( IS_MIFARE_CLASSIC_1K(bTagType) && (uiSector < MIFARE_CLASSIC_1K_MAX_SECTORS) ) if (IS_MIFARE_CLASSIC_1K(bTagType) && (uiSector < MIFARE_CLASSIC_1K_MAX_SECTORS)) {
{ return true;
return true; }
}
if ( IS_MIFARE_CLASSIC_4K(bTagType) && (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS) ) if (IS_MIFARE_CLASSIC_4K(bTagType) && (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS)) {
{ return true;
return true; }
}
return false; return false;
} }
bool is_first_block(byte_t bTagType, uint32_t uiBlock) bool is_first_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return false;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// For Mifare Classic 1K, it will enter always here
return ( (uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0 );
}
else
{
// This branch will enter only for Mifare Classic 4K big sectors
return ( (uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0 );
}
// Should not reach here, but... never know
return false; return false;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// For Mifare Classic 1K, it will enter always here
return ((uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0);
} else {
// This branch will enter only for Mifare Classic 4K big sectors
return ((uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0);
}
// Should not reach here, but... never know
return false;
} }
bool is_trailer_block(byte_t bTagType, uint32_t uiBlock) bool is_trailer_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return false;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// For Mifare Classic 1K, it will enter always here
return ( (uiBlock+1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0 );
}
else
{
// This branch will enter only for Mifare Classic 4K big sectors
return ( (uiBlock+1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0 );
}
// Should not reach here, but... never know
return false; return false;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// For Mifare Classic 1K, it will enter always here
return ((uiBlock + 1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0);
} else {
// This branch will enter only for Mifare Classic 4K big sectors
return ((uiBlock + 1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0);
}
// Should not reach here, but... never know
return false;
} }
uint32_t get_first_block(byte_t bTagType, uint32_t uiBlock) uint32_t get_first_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// Integer divide, then integer multiply
return (uiBlock/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1;
}
else
{
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2;
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// Integer divide, then integer multiply
return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1;
} else {
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2;
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
uint32_t get_trailer_block(byte_t bTagType, uint32_t uiBlock) uint32_t get_trailer_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// Integer divide, then integer multiply
return (uiBlock/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1-1);
}
else
{
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2-1);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// Integer divide, then integer multiply
return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 - 1);
} else {
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 - 1);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
bool is_big_sector(byte_t bTagType, uint32_t uiSector) bool is_big_sector(uint8_t bTagType, uint32_t uiSector)
{ {
if ( !is_valid_sector(bTagType, uiSector) ) if (!is_valid_sector(bTagType, uiSector)) {
{
return false;
}
if (uiSector >= MIFARE_CLASSIC_4K_MAX_SECTORS1)
{
return true;
}
return false; return false;
}
if (uiSector >= MIFARE_CLASSIC_4K_MAX_SECTORS1) {
return true;
}
return false;
} }
uint32_t get_first_block_for_sector(byte_t bTagType, uint32_t uiSector) uint32_t get_first_block_for_sector(uint8_t bTagType, uint32_t uiSector)
{ {
if ( !is_valid_sector(bTagType, uiSector) ) if (!is_valid_sector(bTagType, uiSector)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1)
{
// For Mifare Classic 1K, it will enter always here
return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
}
else
{
// For Mifare Classic 4K big sectors it will enter always here
uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1) {
// For Mifare Classic 1K, it will enter always here
return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
} else {
// For Mifare Classic 4K big sectors it will enter always here
uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
uint32_t get_trailer_block_for_sector(byte_t bTagType, uint32_t uiSector) uint32_t get_trailer_block_for_sector(uint8_t bTagType, uint32_t uiSector)
{ {
if ( !is_valid_sector(bTagType, uiSector) ) if (!is_valid_sector(bTagType, uiSector)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1)
{
// For Mifare Classic 1K, it will enter always here
return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1-1);
}
else
{
// For Mifare Classic 4K big sectors it will enter always here
uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2-1);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
}
if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1) {
// For Mifare Classic 1K, it will enter always here
return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 - 1);
} else {
// For Mifare Classic 4K big sectors it will enter always here
uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 - 1);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK;
} }
uint32_t get_sector_for_block(byte_t bTagType, uint32_t uiBlock) uint32_t get_sector_for_block(uint8_t bTagType, uint32_t uiBlock)
{ {
if ( !is_valid_block(bTagType, uiBlock) ) if (!is_valid_block(bTagType, uiBlock)) {
{
return MIFARE_CLASSIC_INVALID_BLOCK;
}
// Test if we are in the small or big sectors
if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1)
{
// For Mifare Classic 1K, it will enter always here
return (uiBlock/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
}
else
{
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_SECTORS1 + (tmp/MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
}
// Should not reach here, but... never know
return MIFARE_CLASSIC_INVALID_BLOCK; return MIFARE_CLASSIC_INVALID_BLOCK;
} }
bool is_first_sector(byte_t bTagType, uint32_t uiSector) // Test if we are in the small or big sectors
{ if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
// TODO: write code // For Mifare Classic 1K, it will enter always here
return false; return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
} } else {
uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
return MIFARE_CLASSIC_4K_MAX_SECTORS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
}
bool is_first_big_sector(byte_t bTagType, uint32_t uiSector) // Should not reach here, but... never know
{ return MIFARE_CLASSIC_INVALID_BLOCK;
// TODO: write code
return false;
}
bool is_first_small_sector(byte_t bTagType, uint32_t uiSector)
{
// TODO: write code
return false;
}
bool is_last_sector(byte_t bTagType, uint32_t uiSector)
{
// TODO: write code
return false;
}
bool is_last_big_sector(byte_t bTagType, uint32_t uiSector)
{
// TODO: write code
return false;
}
bool is_last_small_sector(byte_t bTagType, uint32_t uiSector)
{
// TODO: write code
return false;
} }
// Test case function for checking correct functionality of the block/sector is_ ang get_ functions // Test case function for checking correct functionality of the block/sector is_ ang get_ functions
void test_mifare_classic_blocks_sectors_functions(byte_t bTagType) void test_mifare_classic_blocks_sectors_functions(uint8_t bTagType)
{ {
uint32_t i; uint32_t i;
uint32_t max_blocks, max_sectors; uint32_t max_blocks, max_sectors;
if ( IS_MIFARE_CLASSIC_1K(bTagType) ) if (IS_MIFARE_CLASSIC_1K(bTagType)) {
{ printf("\nMIFARE CLASSIC 1K\n");
printf("\nMIFARE CLASSIC 1K\n"); max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS;
max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS; max_sectors = MIFARE_CLASSIC_1K_MAX_SECTORS;
max_sectors = MIFARE_CLASSIC_1K_MAX_SECTORS; } else if (IS_MIFARE_CLASSIC_4K(bTagType)) {
} printf("\nMIFARE CLASSIC 4K\n");
else if ( IS_MIFARE_CLASSIC_4K(bTagType) ) max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS;
{ max_sectors = MIFARE_CLASSIC_4K_MAX_SECTORS;
printf("\nMIFARE CLASSIC 4K\n"); } else {
max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS; return;
max_sectors = MIFARE_CLASSIC_4K_MAX_SECTORS; }
}
else
{
return;
}
// Include one invalid block, that is why we add +1 // Include one invalid block, that is why we add +1
for (i = 0; i<max_blocks+1; i++) for (i = 0; i < max_blocks + 1; i++) {
{ printf("BLOCK %d\n", i);
printf("BLOCK %d\n", i); printf("\t is_valid_block: %c\n", (is_valid_block(bTagType, i) ? 'Y' : 'N'));
printf("\t is_valid_block: %c\n", (is_valid_block(bTagType, i)?'Y':'N') ); printf("\t is_first_block: %c\n", (is_first_block(bTagType, i) ? 'Y' : 'N'));
printf("\t is_first_block: %c\n", (is_first_block(bTagType, i)?'Y':'N') ); printf("\t is_trailer_block: %c\n", (is_trailer_block(bTagType, i) ? 'Y' : 'N'));
printf("\t is_trailer_block: %c\n", (is_trailer_block(bTagType, i)?'Y':'N') ); printf("\t get_first_block: %d\n", get_first_block(bTagType, i));
printf("\t get_first_block: %d\n", get_first_block(bTagType, i)); printf("\t get_trailer_block: %d\n", get_trailer_block(bTagType, i));
printf("\t get_trailer_block: %d\n", get_trailer_block(bTagType, i)); printf("\t get_sector_for_block: %d\n", get_sector_for_block(bTagType, i));
printf("\t get_sector_for_block: %d\n", get_sector_for_block(bTagType, i)); }
}
// Include one invalid sector, that is why we add +1 // Include one invalid sector, that is why we add +1
for (i = 0; i<max_sectors+1; i++) for (i = 0; i < max_sectors + 1; i++) {
{ printf("SECTOR %d\n", i);
printf("SECTOR %d\n", i); printf("\t is_valid_sector: %c\n", (is_valid_sector(bTagType, i) ? 'Y' : 'N'));
printf("\t is_valid_sector: %c\n", (is_valid_sector(bTagType, i)?'Y':'N') ); printf("\t is_big_sector: %c\n", (is_big_sector(bTagType, i) ? 'Y' : 'N'));
printf("\t is_big_sector: %c\n", (is_big_sector(bTagType, i)?'Y':'N') ); printf("\t get_first_block_for_sector: %d\n", get_first_block_for_sector(bTagType, i));
printf("\t get_first_block_for_sector: %d\n", get_first_block_for_sector(bTagType, i) ); printf("\t get_trailer_block_for_sector: %d\n", get_trailer_block_for_sector(bTagType, i));
printf("\t get_trailer_block_for_sector: %d\n", get_trailer_block_for_sector(bTagType, i) ); }
}
} }
bool mfcuk_save_tag_dump(char *filename, mifare_classic_tag *tag) bool mfcuk_save_tag_dump(const char *filename, mifare_classic_tag *tag)
{ {
FILE *fp; FILE *fp;
size_t result; size_t result;
fp = fopen(filename, "wb"); fp = fopen(filename, "wb");
if (!fp) if (!fp) {
{ return false;
return false; }
}
// Expect to write 1 record // Expect to write 1 record
result = fwrite((void *) tag, sizeof(*tag), 1, fp); result = fwrite((void *) tag, sizeof(*tag), 1, fp);
// If not written exactly 1 record, something is wrong
if (result != 1)
{
fclose(fp);
return false;
}
// If not written exactly 1 record, something is wrong
if (result != 1) {
fclose(fp); fclose(fp);
return true; return false;
}
fclose(fp);
return true;
} }
bool mfcuk_save_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext) bool mfcuk_save_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext)
{ {
FILE *fp; FILE *fp;
size_t result; size_t result;
fp = fopen(filename, "wb"); fp = fopen(filename, "wb");
if (!fp) if (!fp) {
{ return false;
return false; }
}
// Expect to write 1 record // Expect to write 1 record
result = fwrite((void *) tag_ext, sizeof(*tag_ext), 1, fp); result = fwrite((void *) tag_ext, sizeof(*tag_ext), 1, fp);
// If not written exactly 1 record, something is wrong
if (result != 1)
{
fclose(fp);
return false;
}
// If not written exactly 1 record, something is wrong
if (result != 1) {
fclose(fp); fclose(fp);
return true; return false;
}
fclose(fp);
return true;
} }
bool mfcuk_load_tag_dump(char *filename, mifare_classic_tag *tag) bool mfcuk_load_tag_dump(const char *filename, mifare_classic_tag *tag)
{ {
FILE *fp; FILE *fp;
size_t result; size_t result;
fp = fopen(filename, "rb"); fp = fopen(filename, "rb");
if (!fp) if (!fp) {
{ return false;
return false; }
}
// Expect to read 1 record // Expect to read 1 record
result = fread((void *) tag, sizeof(*tag), 1, fp); result = fread((void *) tag, sizeof(*tag), 1, fp);
// If not read exactly 1 record, something is wrong
if (result != 1)
{
fclose(fp);
return false;
}
// If not read exactly 1 record, something is wrong
if (result != 1) {
fclose(fp); fclose(fp);
return true; return false;
}
fclose(fp);
return true;
} }
bool mfcuk_load_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext) bool mfcuk_load_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext)
{ {
FILE *fp; FILE *fp;
size_t result; size_t result;
fp = fopen(filename, "rb"); fp = fopen(filename, "rb");
if (!fp) if (!fp) {
{ return false;
return false; }
}
// Expect to read 1 record // Expect to read 1 record
result = fread((void *) tag_ext, sizeof(*tag_ext), 1, fp); result = fread((void *) tag_ext, sizeof(*tag_ext), 1, fp);
// If not read exactly 1 record, something is wrong
if (result != sizeof(*tag_ext))
{
fclose(fp);
return false;
}
// If not read exactly 1 record, something is wrong
if (result != sizeof(*tag_ext)) {
fclose(fp); fclose(fp);
return true; return false;
}
fclose(fp);
return true;
} }
void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag) void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag)
{ {
uint32_t i, max_blocks, trailer_block; uint32_t i, max_blocks, trailer_block;
byte_t bTagType; uint8_t bTagType;
mifare_classic_block_trailer *ptr_trailer = NULL; mifare_classic_block_trailer *ptr_trailer = NULL;
if (!tag)
{
return;
}
bTagType = tag->amb->mbm.btUnknown;
if ( !IS_MIFARE_CLASSIC_1K(bTagType) && !IS_MIFARE_CLASSIC_4K(bTagType) )
{
return;
}
printf("%s - UID %02x %02x %02x %02x - TYPE 0x%02x (%s)\n",
title, tag->amb->mbm.abtUID[0], tag->amb->mbm.abtUID[1], tag->amb->mbm.abtUID[2], tag->amb->mbm.abtUID[3], bTagType,
(IS_MIFARE_CLASSIC_1K(bTagType)?(MIFARE_CLASSIC_1K_NAME):(IS_MIFARE_CLASSIC_4K(bTagType)?(MIFARE_CLASSIC_4K_NAME):(MIFARE_CLASSIC_UNKN_NAME)))
);
printf("-------------------------------------------------------\n");
printf("Sector\t| Key A\t| AC bits\t| Key B\n");
printf("-------------------------------------------------------\n");
if ( IS_MIFARE_CLASSIC_1K(tag->amb->mbm.btUnknown) )
{
max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS;
}
else
{
max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS;
}
for (i=0; i<max_blocks; i++)
{
trailer_block = get_trailer_block(bTagType, i);
if ( !is_valid_block(bTagType, trailer_block) )
{
break;
}
ptr_trailer = (mifare_classic_block_trailer *) ((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK) );
printf("%d\t| %02x%02x%02x%02x%02x%02x\t| %02x%02x%02x%02x\t| %02x%02x%02x%02x%02x%02x\n",
get_sector_for_block(bTagType, trailer_block),
ptr_trailer->abtKeyA[0], ptr_trailer->abtKeyA[1], ptr_trailer->abtKeyA[2],
ptr_trailer->abtKeyA[3], ptr_trailer->abtKeyA[4], ptr_trailer->abtKeyA[5],
ptr_trailer->abtAccessBits[0], ptr_trailer->abtAccessBits[1], ptr_trailer->abtAccessBits[2], ptr_trailer->abtAccessBits[3],
ptr_trailer->abtKeyB[0], ptr_trailer->abtKeyB[1], ptr_trailer->abtKeyB[2],
ptr_trailer->abtKeyB[3], ptr_trailer->abtKeyB[4], ptr_trailer->abtKeyB[5]
);
// Go beyond current trailer block, i.e. go to next sector
i = trailer_block;
}
printf("\n");
if (!tag) {
return; return;
}
bTagType = tag->amb->mbm.btUnknown;
if (!IS_MIFARE_CLASSIC_1K(bTagType) && !IS_MIFARE_CLASSIC_4K(bTagType)) {
return;
}
printf("%s - UID %02x %02x %02x %02x - TYPE 0x%02x (%s)\n",
title, tag->amb->mbm.abtUID[0], tag->amb->mbm.abtUID[1], tag->amb->mbm.abtUID[2], tag->amb->mbm.abtUID[3], bTagType,
(IS_MIFARE_CLASSIC_1K(bTagType) ? (MIFARE_CLASSIC_1K_NAME) : (IS_MIFARE_CLASSIC_4K(bTagType) ? (MIFARE_CLASSIC_4K_NAME) : (MIFARE_CLASSIC_UNKN_NAME)))
);
printf("-------------------------------------------------------\n");
printf("Sector\t| Key A\t| AC bits\t| Key B\n");
printf("-------------------------------------------------------\n");
if (IS_MIFARE_CLASSIC_1K(tag->amb->mbm.btUnknown)) {
max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS;
} else {
max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS;
}
for (i = 0; i < max_blocks; i++) {
trailer_block = get_trailer_block(bTagType, i);
if (!is_valid_block(bTagType, trailer_block)) {
break;
}
ptr_trailer = (mifare_classic_block_trailer *)((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK));
printf("%d\t| %02x%02x%02x%02x%02x%02x\t| %02x%02x%02x%02x\t| %02x%02x%02x%02x%02x%02x\n",
get_sector_for_block(bTagType, trailer_block),
ptr_trailer->abtKeyA[0], ptr_trailer->abtKeyA[1], ptr_trailer->abtKeyA[2],
ptr_trailer->abtKeyA[3], ptr_trailer->abtKeyA[4], ptr_trailer->abtKeyA[5],
ptr_trailer->abtAccessBits[0], ptr_trailer->abtAccessBits[1], ptr_trailer->abtAccessBits[2], ptr_trailer->abtAccessBits[3],
ptr_trailer->abtKeyB[0], ptr_trailer->abtKeyB[1], ptr_trailer->abtKeyB[2],
ptr_trailer->abtKeyB[3], ptr_trailer->abtKeyB[4], ptr_trailer->abtKeyB[5]
);
// Go beyond current trailer block, i.e. go to next sector
i = trailer_block;
}
printf("\n");
return;
} }
bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, byte_t *arr6Key) bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, uint8_t *arr6Key)
{ {
int i; int i;
if ( !ui64Key || !arr6Key ) if (!ui64Key || !arr6Key) {
{ return false;
return false; }
}
for (i = 0; i<MIFARE_CLASSIC_KEY_BYTELENGTH; i++) for (i = 0; i < MIFARE_CLASSIC_KEY_BYTELENGTH; i++) {
{ arr6Key[i] = (uint8_t)(((*ui64Key) >> 8 * (MIFARE_CLASSIC_KEY_BYTELENGTH - i - 1)) & 0xFF);
arr6Key[i] = (byte_t) (((*ui64Key) >> 8*(MIFARE_CLASSIC_KEY_BYTELENGTH - i - 1)) & 0xFF); }
}
return true; return true;
} }
bool mfcuk_key_arr_to_uint64(const byte_t *arr6Key, uint64_t *ui64Key) bool mfcuk_key_arr_to_uint64(const uint8_t *arr6Key, uint64_t *ui64Key)
{ {
uint64_t key = 0; uint64_t key = 0;
int i; int i;
if ( !ui64Key || !arr6Key ) if (!ui64Key || !arr6Key) {
{ return false;
return false; }
}
for (i = 0; i<MIFARE_CLASSIC_KEY_BYTELENGTH; i++, key <<= 8) for (i = 0; i < MIFARE_CLASSIC_KEY_BYTELENGTH; i++, key <<= 8) {
{ key |= arr6Key[i];
key |= arr6Key[i]; }
} key >>= 8;
key >>= 8;
*ui64Key = key; *ui64Key = key;
return true; return true;
} }

View File

@@ -100,46 +100,46 @@
// Define an extended type of dump, basically a wrapper dump around basic tag dump // Define an extended type of dump, basically a wrapper dump around basic tag dump
typedef struct { typedef struct {
uint32_t uid; // looks redundant, but it is easier to use dmp.uid instead of dmp.amb.mbm.abtUID[0]...[3] uint32_t uid; // looks redundant, but it is easier to use dmp.uid instead of dmp.amb.mbm.abtUID[0]...[3]
byte_t type; // ATS/SAK from ti.tia.btSak, example 0x08h for Mifare 1K, 0x18h for Mifare 4K uint8_t type; // ATS/SAK from ti.tia.btSak, example 0x08h for Mifare 1K, 0x18h for Mifare 4K
char datetime[14]; // non-zero-terminated date-time of dump in format YYYYMMDDH24MISS, example 20091114231541 - 14 Nov 2009, 11:15:41 PM char datetime[14]; // non-zero-terminated date-time of dump in format YYYYMMDDH24MISS, example 20091114231541 - 14 Nov 2009, 11:15:41 PM
char description[MFCUK_EXTENDED_DESCRIPTION_LENGTH]; // a description of the tag dump, example "RATB_DUMP_BEFORE_PAY" char description[MFCUK_EXTENDED_DESCRIPTION_LENGTH]; // a description of the tag dump, example "RATB_DUMP_BEFORE_PAY"
mifare_classic_tag tag_basic; mifare_classic_tag tag_basic;
} mifare_classic_tag_ext; } mifare_classic_tag_ext;
// Define type of keys (A or B) in NXP notation // Define type of keys (A or B) in NXP notation
typedef enum { typedef enum {
keyA = 0x60, keyA = 0x60,
keyB = 0x61, keyB = 0x61,
} mifare_key_type; } mifare_key_type;
// Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention! // Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention!
extern byte_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH]; extern uint8_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH];
extern int mfcuk_default_keys_num; extern int mfcuk_default_keys_num;
bool is_valid_block(byte_t bTagType, uint32_t uiBlock); bool is_valid_block(uint8_t bTagType, uint32_t uiBlock);
bool is_valid_sector(byte_t bTagType, uint32_t uiSector); bool is_valid_sector(uint8_t bTagType, uint32_t uiSector);
bool is_first_block(byte_t bTagType, uint32_t uiBlock); bool is_first_block(uint8_t bTagType, uint32_t uiBlock);
bool is_trailer_block(byte_t bTagType, uint32_t uiBlock); bool is_trailer_block(uint8_t bTagType, uint32_t uiBlock);
uint32_t get_first_block(byte_t bTagType, uint32_t uiBlock); uint32_t get_first_block(uint8_t bTagType, uint32_t uiBlock);
uint32_t get_trailer_block(byte_t bTagType, uint32_t uiBlock); uint32_t get_trailer_block(uint8_t bTagType, uint32_t uiBlock);
bool is_big_sector(byte_t bTagType, uint32_t uiSector); bool is_big_sector(uint8_t bTagType, uint32_t uiSector);
uint32_t get_first_block_for_sector(byte_t bTagType, uint32_t uiSector); uint32_t get_first_block_for_sector(uint8_t bTagType, uint32_t uiSector);
uint32_t get_trailer_block_for_sector(byte_t bTagType, uint32_t uiSector); uint32_t get_trailer_block_for_sector(uint8_t bTagType, uint32_t uiSector);
uint32_t get_sector_for_block(byte_t bTagType, uint32_t uiBlock); uint32_t get_sector_for_block(uint8_t bTagType, uint32_t uiBlock);
bool is_first_sector(byte_t bTagType, uint32_t uiSector); bool is_first_sector(uint8_t bTagType, uint32_t uiSector);
bool is_first_big_sector(byte_t bTagType, uint32_t uiSector); bool is_first_big_sector(uint8_t bTagType, uint32_t uiSector);
bool is_first_small_sector(byte_t bTagType, uint32_t uiSector); bool is_first_small_sector(uint8_t bTagType, uint32_t uiSector);
bool is_last_sector(byte_t bTagType, uint32_t uiSector); bool is_last_sector(uint8_t bTagType, uint32_t uiSector);
bool is_last_big_sector(byte_t bTagType, uint32_t uiSector); bool is_last_big_sector(uint8_t bTagType, uint32_t uiSector);
bool is_last_small_sector(byte_t bTagType, uint32_t uiSector); bool is_last_small_sector(uint8_t bTagType, uint32_t uiSector);
void test_mifare_classic_blocks_sectors_functions(byte_t bTagType); void test_mifare_classic_blocks_sectors_functions(uint8_t bTagType);
bool mfcuk_save_tag_dump(char *filename, mifare_classic_tag *tag); bool mfcuk_save_tag_dump(const char *filename, mifare_classic_tag *tag);
bool mfcuk_save_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext); bool mfcuk_save_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext);
bool mfcuk_load_tag_dump(char *filename, mifare_classic_tag *tag); bool mfcuk_load_tag_dump(const char *filename, mifare_classic_tag *tag);
bool mfcuk_load_tag_dump_ext(char *filename, mifare_classic_tag_ext *tag_ext); bool mfcuk_load_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext);
void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag); void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag);
bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, byte_t *arr6Key); bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, uint8_t *arr6Key);
bool mfcuk_key_arr_to_uint64(const byte_t *arr6Key, uint64_t *ui64Key); bool mfcuk_key_arr_to_uint64(const uint8_t *arr6Key, uint64_t *ui64Key);
#endif // _MFCUK_MIFARE_H_ #endif // _MFCUK_MIFARE_H_

View File

@@ -45,12 +45,19 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "mfcuk_utils.h" #include "config.h"
#ifdef __STDC__ #if defined(WIN32)
struct timeval global_timeout; #include <windows.h>
#elif defined(HAVE_UNISTD_H)
#include <unistd.h>
#else
#error "Unsupported system"
#endif #endif
#include "mfcuk_utils.h"
#include <stdio.h>
/* /*
http://www.velocityreviews.com/forums/t451319-advice-required-on-my-ascii-to-hex-conversion-c.html http://www.velocityreviews.com/forums/t451319-advice-required-on-my-ascii-to-hex-conversion-c.html
Basically, converting a hex digit into a hex nibble (4 binary digits) algorithm looks like; Basically, converting a hex digit into a hex nibble (4 binary digits) algorithm looks like;
@@ -65,17 +72,36 @@ The below code is just an optimization of the algorithm. Maxim Yegorushkin
/*inline*/ /*inline*/
int is_hex(char c) int is_hex(char c)
{ {
return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
} }
/*inline*/ /*inline*/
unsigned char hex2bin(unsigned char h, unsigned char l) unsigned char hex2bin(unsigned char h, unsigned char l)
{ {
h |= 0x20; // to lower h |= 0x20; // to lower
h -= 0x30; h -= 0x30;
h -= -(h > 9) & 0x27; h -= -(h > 9) & 0x27;
l |= 0x20; l |= 0x20;
l -= 0x30; l -= 0x30;
l -= -(l > 9) & 0x27; l -= -(l > 9) & 0x27;
return h << 4 | l; return h << 4 | l;
} }
void sleepmillis(unsigned int millis)
{
#ifdef WIN32 // If system is Windows, use system's own function if possible to reduce overhead, even if a standard C library is available
Sleep(millis);
#else
usleep(millis * 1000);
#endif
}
void clear_screen()
{
#ifdef WIN32 // On Windows, use "cls" command
system("cls");
#else // Otherwise fall back to TTY control characters
printf("\033[1;1H\033[J");
#endif
}

View File

@@ -48,35 +48,6 @@
#ifndef _MFCUK_UTILS_H_ #ifndef _MFCUK_UTILS_H_
#define _MFCUK_UTILS_H_ #define _MFCUK_UTILS_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#define NOMINMAX
#include "windows.h"
#include "xgetopt.h"
#elif __STDC__
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#endif
// "Portable" sleep(miliseconds)
#ifdef WIN32
#define sleep(x) Sleep(x)
#elif __STDC__
extern struct timeval global_timeout;
#define sleep(x) { global_timeout.tv_usec = 1000 * (x); select(0,NULL,NULL,NULL,&global_timeout); }
#endif
// "Portable" clear_screen() - NOTE: system performance penalty introduced
#ifdef WIN32
#define clear_screen() system("cls")
#elif __STDC__
#define clear_screen() system("sh -c clear")
#endif
/** /**
* @fn int is_hex(char c) * @fn int is_hex(char c)
* @brief Checks if an ASCII character is a valid hexadecimal base digit * @brief Checks if an ASCII character is a valid hexadecimal base digit
@@ -101,4 +72,23 @@ int is_hex(char c);
*/ */
unsigned char hex2bin(unsigned char h, unsigned char l); unsigned char hex2bin(unsigned char h, unsigned char l);
/**
* @fn void sleepmillis(unsigned int millis)
* @brief Pauses execution for a certain amount of milliseconds
* @param millis Number of milliseconds to sleep
*
* Wrapper for system-dependant sleep function. It pauses execution for a certain amount of milliseconds.
*/
void sleepmillis(unsigned int millis);
/**
* @fn void clear_screen(void);
* @brief Clears output console
*
* Wrapper for system-dependant clear screen function.
* Resets output console, clearing text and resetting character pointer.
*/
void clear_screen(void);
#endif // _MFCUK_UTILS_H_ #endif // _MFCUK_UTILS_H_

View File

@@ -1,8 +1,9 @@
/*- /*-
* 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 Romain Tartière
* Copyright (C) 2010, 2011 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:
@@ -27,7 +28,10 @@
* 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>
@@ -48,79 +52,82 @@
* 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,8 +1,9 @@
/*- /*-
* 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 Romain Tartière
* Copyright (C) 2010, 2011 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:
@@ -29,7 +30,7 @@
*/ */
/** /**
* @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 +39,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 +54,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 +112,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,8 +1,13 @@
/*- /*-
* Public platform independent Near Field Communication (NFC) library examples * Free/Libre Near Field Communication (NFC) library
* *
* Copyright (C) 2009, Roel Verdult * Libnfc historical contributors:
* Copyright (C) 2010, Romuald Conty, Romain Tartière * Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Additional contributors of this file:
* *
* 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:
@@ -27,93 +32,78 @@
* 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 +111,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 *pnt, bool verbose)
{ {
(void) verbose; char *s;
printf (" ID (NFCID2): "); str_nfc_target(&s, pnt, verbose);
print_hex (nfi.abtId, 8); printf("%s", s);
printf (" Parameter (PAD): "); nfc_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,8 +1,13 @@
/*- /*-
* Public platform independent Near Field Communication (NFC) library examples * Free/Libre Near Field Communication (NFC) library
* *
* Copyright (C) 2009, Roel Verdult * Libnfc historical contributors:
* Copyright (C) 2010, Romuald Conty, Romain Tartière * Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Additional contributors of this file:
* *
* 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:
@@ -79,22 +84,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 *pnt, bool verbose);
#endif #endif

View File

@@ -158,66 +158,57 @@ int optind = 0; // global argv index
int getopt(int argc, char *argv[], char *optstring) int getopt(int argc, char *argv[], char *optstring)
{ {
char c = 0; char c = 0;
char *cp = NULL; char *cp = NULL;
static char *next = NULL; static char *next = NULL;
if (optind == 0) if (optind == 0)
next = NULL; next = NULL;
optarg = NULL; optarg = NULL;
if (next == NULL || *next == '\0') if (next == NULL || *next == '\0') {
{ if (optind == 0)
if (optind == 0) optind++;
optind++;
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') {
{ optarg = NULL;
optarg = NULL; if (optind < argc)
if (optind < argc) optarg = argv[optind];
optarg = argv[optind]; return EOF;
return EOF; }
}
if (strcmp(argv[optind], "--") == 0) if (strcmp(argv[optind], "--") == 0) {
{ optind++;
optind++; optarg = NULL;
optarg = NULL; if (optind < argc)
if (optind < argc) optarg = argv[optind];
optarg = argv[optind]; return EOF;
return EOF; }
}
next = argv[optind]; next = argv[optind];
next++; // skip past - next++; // skip past -
optind++; optind++;
} }
c = *next++; c = *next++;
cp = strchr(optstring, c); cp = strchr(optstring, c);
if (cp == NULL || c == ':') if (cp == NULL || c == ':')
return '?'; return '?';
cp++; cp++;
if (*cp == ':') if (*cp == ':') {
{ if (*next != '\0') {
if (*next != '\0') optarg = next;
{ next = NULL;
optarg = next; } else if (optind < argc) {
next = NULL; optarg = argv[optind];
} optind++;
else if (optind < argc) } else {
{ return '?';
optarg = argv[optind]; }
optind++; }
}
else
{
return '?';
}
}
return c; return c;
} }

View File

@@ -15,9 +15,15 @@
#ifndef XGETOPT_H #ifndef XGETOPT_H
#define XGETOPT_H #define XGETOPT_H
#if HAVE_UNISTD_H
#include <unistd.h>
#else
extern int optind, opterr; extern int optind, opterr;
extern char *optarg; extern char *optarg;
int getopt(int argc, char *argv[], char *optstring); int getopt(int argc, char *argv[], char *optstring);
#endif
#endif //XGETOPT_H #endif //XGETOPT_H