45 Commits

Author SHA1 Message Date
Romuald Conty
1c5af20e98 Releases MFOC 0.10.5 2013-01-31 18:17:13 +01:00
Romuald Conty
d65d57d06e Uses __asm__ instead of asm keyword to prevent from troubles during compilation.
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
2013-01-30 15:11:24 +01:00
Romuald Conty
6674459a57 Updates Debian package 2013-01-20 16:07:10 +01:00
Romuald Conty
c004dd2c2c Update ChangeLog 2013-01-20 15:49:18 +01:00
Romuald Conty
051d70e2ed Update outdated email addresses 2013-01-20 15:48:16 +01:00
Romuald Conty
6048309a13 Format source code with "make style" 2013-01-20 15:36:59 +01:00
Romuald Conty
2596aeac80 Add "make style" directive to format source code 2013-01-20 15:36:27 +01:00
Romuald Conty
10699271f6 Updates source to use libnfc 1.7.0 2013-01-20 15:27:05 +01:00
Romuald Conty
87d6203b88 Update mifare.* and nfc-utils.* from libnfc utils directory 2013-01-20 15:25:40 +01:00
Romuald Conty
1a2ed65879 Ignore generated files in source repository 2013-01-20 15:24:57 +01:00
Romuald Conty
02afffce07 Fix tolerance (-T) option (Fixes issue 102)
Thanks to fnargwibble
2012-10-14 10:35:37 +00:00
Romuald Conty
25e1b8a3c6 do not display an error when authentication failed 2012-06-03 21:32:57 +00:00
Romuald Conty
451f2fa29c use authuid instead uid name when handling the authentication uid bytes (different from UID with 7bytes MIFARE Classic 2012-06-03 21:23:51 +00:00
Romuald Conty
bc109b9252 some code clean up: find . -name '*.[ch]' | xargs perl -pi -e 's/\t+$//; s/ +$//' 2012-06-03 21:07:51 +00:00
Romuald Conty
435de61cc5 Allow to find default keys using 7bytes UID MIFARE Classic tags 2012-06-02 01:26:48 +00:00
Romuald Conty
3b02985173 Remove not requiered anticol and configuration, its speed up default keys search 2012-06-02 00:48:58 +00:00
Romuald Conty
262e206b0a Enhance default keys search result: '/', '\' and 'x' means respectively A, B and both key(s) found. 2012-06-02 00:44:58 +00:00
Romuald Conty
3545975303 foc> source code maintenance:
- upgrade to last libnfc devel API
 - removes various warnings
 - update debian package
2012-06-01 23:02:01 +00:00
Ludovic Rousseau
f4282f0f5d Update upstream URL
Closes Issue #92
2012-05-28 09:07:05 +00:00
Ludovic Rousseau
8962d407c0 Upgrade libnfc-dev version in Build-Depends:
Closes Issue #91
2012-05-22 11:56:37 +00:00
Romain Tartiere
9187b97249 Export lfsr_rollback_word(). 2012-05-14 13:46:39 +00:00
Romain Tartiere
b27b742472 Drop unused argument. 2012-05-14 13:45:57 +00:00
Romain Tartiere
478d3d92eb Fix a bunch of signed/unsigned comparisons. 2012-05-14 13:45:13 +00:00
Romain Tartiere
08195d70ee Complete configure.ac. 2012-05-14 13:10:02 +00:00
Romain Tartiere
68b71ea26c Rely on variables set by the autotools. 2012-05-14 13:09:38 +00:00
Audrey Diacre
5c62782645 update to use libnfc's trunk 2012-01-26 09:24:21 +00:00
Romuald Conty
ea0c8a7047 compilation improvements (Thanks to Thomas Hood) 2011-10-17 09:50:54 +00:00
Romuald Conty
2be6d8ddef Sync w/ libnfc-1.5.1 (Fixes Issue 79) 2011-09-28 15:32:01 +00:00
Romuald Conty
c3808a240c sync nfc-utils.c with libnfc trunk. 2011-07-11 18:53:23 +00:00
Romuald Conty
ece9619e6d debian: update pam_nfc, mfoc and libfreefare packages to use dh7. 2011-05-20 16:00:11 +00:00
Romuald Conty
a3ddbf6a32 debian: silent lintian warning 2011-05-20 14:59:19 +00:00
Romuald Conty
55c3296983 usage output is now more standard (Thanks to Thomas Hood) 2011-05-20 14:42:40 +00:00
Romuald Conty
21b58f0bf6 debian package now use dh_autoreconf to build against svn. 2011-05-20 14:40:36 +00:00
Romuald Conty
5e3f177ee6 in some cases ./configure file needs to be chmoded (dpkg-source -b mfoc). 2011-05-19 10:42:13 +00:00
Romuald Conty
367f0d050e import debian files (Thanks to Thomas Hood) 2011-05-19 08:01:31 +00:00
Romuald Conty
3b2b569f0d add manpage (Thanks to Thomas Hood) 2011-05-18 15:01:44 +00:00
Romuald Conty
2ff463b5c1 read multiple keys from command line (Thanks to Frank Morgner) (Fixes Issue 63) 2011-05-18 14:56:21 +00:00
Romuald Conty
658d77ec0d prepare 0.10.2 release 2011-05-18 12:10:17 +00:00
Romuald Conty
a13df02f79 improve tests made before running and show tag info using print_nfc_iso14443a_info() 2011-05-18 09:18:29 +00:00
Romuald Conty
001049599f try to disconnect() the device on error. 2011-04-08 15:19:39 +00:00
Romuald Conty
a978ac16a9 show errors then exit on mf_configure() 2011-04-08 10:05:49 +00:00
Romuald Conty
1c2ff2b263 apply a patch suggested by Valentijn Sessink. See Issue 56. 2011-04-08 09:32:56 +00:00
Romuald Conty
d1c676b01d minors fixes and indent. 2011-04-08 09:17:10 +00:00
Romuald Conty
9e636c9885 show error (using nfc_perror) then exit if some nfc_* functions failed on init. 2011-04-08 08:54:55 +00:00
Romuald Conty
ef75599d75 minor debug improvements. 2011-04-08 08:35:55 +00:00
27 changed files with 1911 additions and 1959 deletions

21
.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
INSTALL
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
config.h
config.h.in
config.log
config.status
configure
depcomp
install-sh
missing
src/*.lo
src/*.o
src/.deps/
src/Makefile
src/Makefile.in
src/mfoc
stamp-h1

View File

@@ -6,4 +6,4 @@ Pavol Luptak - project leader, minor coding, testing and bugreporting
= Contributors = Contributors
Michal Boska <boska.michal@gmail.com> - porting to libnfc 1.3.3 Michal Boska <boska.michal@gmail.com> - porting to libnfc 1.3.3
Romuald Conty <romuald@libnfc.org> - porting to libnfc 1.3.9 Romuald Conty <romuald@libnfc.org> - porting to libnfc 1.3.9 and upper

243
ChangeLog
View File

@@ -0,0 +1,243 @@
2013-01-20 Romuald Conty <romuald@libnfc.org>
* ChangeLog: Update outdated email addresses
2013-01-20 Romuald Conty <romuald@libnfc.org>
* src/crapto1.c, src/crapto1.h, src/crypto1.c, src/mfoc.c,
src/mfoc.h: Format source code with "make style"
2013-01-20 Romuald Conty <romuald@libnfc.org>
* Makefile.am: Add "make style" directive to format source code
2013-01-20 Romuald Conty <romuald@libnfc.org>
* configure.ac, src/mfoc.c: Updates source to use libnfc 1.7.0
2013-01-20 Romuald Conty <romuald@libnfc.org>
* src/mifare.c, src/mifare.h, src/nfc-utils.c, src/nfc-utils.h:
Update mifare.* and nfc-utils.* from libnfc utils directory
2013-01-20 Romuald Conty <romuald@libnfc.org>
* .gitignore: Ignore generated files in source repository
2012-10-14 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: Fix tolerance (-T) option (Fixes issue 102) Thanks to
fnargwibble
2012-06-03 Romuald Conty <romuald@libnfc.org>
* src/mifare.c: do not display an error when authentication failed
2012-06-03 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c, src/mfoc.h: use authuid instead uid name when handling
the authentication uid bytes (different from UID with 7bytes MIFARE
Classic
2012-06-03 Romuald Conty <romuald@libnfc.org>
* src/crapto1.h, src/mfoc.c, src/mfoc.h, src/mifare.c,
src/mifare.h, src/nfc-utils.c, src/nfc-utils.h: some code clean up:
find . -name '*.[ch]' | xargs perl -pi -e 's/\t+$//; s/ +$//'
2012-06-02 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c, src/mifare.h: Allow to find default keys using 7bytes
UID MIFARE Classic tags
2012-06-02 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: Remove not requiered anticol and configuration, its
speed up default keys search
2012-06-02 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: Enhance default keys search result: '/', '\' and 'x'
means respectively A, B and both key(s) found.
2012-06-01 Romuald Conty <romuald@libnfc.org>
* INSTALL, configure.ac, debian/control, src/Makefile.am,
src/crapto1.c, src/mfoc.c, src/mfoc.h, src/mifare.c: foc> source
code maintenance: - upgrade to last libnfc devel API - removes various warnings - update debian package
2012-05-28 Ludovic Rousseau <ludovic.rousseau@gmail.com>
* debian/watch: Update upstream URL Closes Issue #92
2012-05-22 Ludovic Rousseau <ludovic.rousseau@gmail.com>
* debian/control: Upgrade libnfc-dev version in Build-Depends: Closes Issue #91
2012-05-14 Romain Tartiere <romain.tartiere@gmail.com>
* src/crapto1.h: Export lfsr_rollback_word().
2012-05-14 Romain Tartiere <romain.tartiere@gmail.com>
* src/mfoc.c, src/mfoc.h: Drop unused argument.
2012-05-14 Romain Tartiere <romain.tartiere@gmail.com>
* src/mfoc.c, src/mfoc.h: Fix a bunch of signed/unsigned
comparisons.
2012-05-14 Romain Tartiere <romain.tartiere@gmail.com>
* configure.ac: Complete configure.ac.
2012-05-14 Romain Tartiere <romain.tartiere@gmail.com>
* src/Makefile.am: Rely on variables set by the autotools.
2012-01-26 Audrey Diacre <adiacre@il4p.fr>
* src/mfoc.c, src/mfoc.h, src/mifare.c, src/mifare.h,
src/nfc-utils.c, src/nfc-utils.h: update to use libnfc's trunk
2011-10-17 Romuald Conty <romuald@libnfc.org>
* configure.ac, src/Makefile.am: compilation improvements (Thanks to
Thomas Hood)
2011-09-28 Romuald Conty <romuald@libnfc.org>
* configure.ac, src/mfoc.c, src/mifare.c: Sync w/ libnfc-1.5.1
(Fixes Issue 79)
2011-07-11 Romuald Conty <romuald@libnfc.org>
* src/nfc-utils.c: sync nfc-utils.c with libnfc trunk.
2011-05-20 Romuald Conty <romuald@libnfc.org>
* debian/control, debian/watch: debian: update pam_nfc, mfoc and
libfreefare packages to use dh7.
2011-05-20 Romuald Conty <romuald@libnfc.org>
* INSTALL, debian/control: debian: silent lintian warning
2011-05-20 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: usage output is now more standard (Thanks to Thomas
Hood)
2011-05-20 Romuald Conty <romuald@libnfc.org>
* debian/changelog, debian/control, debian/rules: debian package now
use dh_autoreconf to build against svn.
2011-05-19 Romuald Conty <romuald@libnfc.org>
* debian/rules: in some cases ./configure file needs to be chmoded
(dpkg-source -b mfoc).
2011-05-19 Romuald Conty <romuald@libnfc.org>
* AUTHORS, debian/changelog, debian/compat, debian/control,
debian/copyright, debian/docs, debian/manpages, debian/rules,
debian/source/format, debian/watch: import debian files (Thanks to
Thomas Hood)
2011-05-18 Romuald Conty <romuald@libnfc.org>
* src/Makefile.am, src/mfoc.1: add manpage (Thanks to Thomas Hood)
2011-05-18 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: read multiple keys from command line (Thanks to Frank
Morgner) (Fixes Issue 63)
2011-05-18 Romuald Conty <romuald@libnfc.org>
* ChangeLog, configure.ac: prepare 0.10.2 release
2011-05-18 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: improve tests made before running and show tag info
using print_nfc_iso14443a_info()
2011-04-08 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: try to disconnect() the device on error.
2011-04-08 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: show errors then exit on mf_configure()
2011-04-08 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: apply a patch suggested by Valentijn Sessink. See
Issue 56.
2011-04-08 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: minors fixes and indent.
2011-04-08 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: show error (using nfc_perror) then exit if some nfc_*
functions failed on init.
2011-04-08 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: minor debug improvements.
2011-04-04 Romuald Conty <romuald@libnfc.org>
* configure.ac, src/mfoc.c: minor fixes/enhancements and version
bumping
2011-04-04 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c, src/mifare.c: hide authentication errors
2011-04-04 Romuald Conty <romuald@libnfc.org>
* src/mifare.c, src/mifare.h, src/nfc-utils.c, src/nfc-utils.h: sync
nfc-utils.h/c and mifare.c/h with libnfc's ones.
2011-02-21 Romain Tartiere <romain.tartiere@gmail.com>
* src/Makefile.am: mfox: Unbreak autotools on FreeBSD.
2011-02-02 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: use strtoll() function in order to retrieve 64bits
wide value. (Fixes Issue 55)
2010-11-18 Romuald Conty <romuald@libnfc.org>
* configure.ac: bump package version
2010-11-18 Romuald Conty <romuald@libnfc.org>
* src/nfc-utils.c, src/nfc-utils.h: sync nfc-utils.* from libnfc
2010-11-02 Romuald Conty <romuald@libnfc.org>
* configure.ac, src/mfoc.c, src/mfoc.h, src/nfc-utils.c,
src/nfc-utils.h: upgrade code to work with develoment version of
libnfc (upcomming 1.4.0) Update code to match with the new API; Sync
nfc-utils.[ch] from libnfc's repo; Update ./configure to detect
libnfc 1.4.0;
2010-09-14 Romuald Conty <romuald@libnfc.org>
* AUTHORS, Makefile.in, aclocal.m4, autogen.sh, config.h,
config.h.in, configure, configure.ac, depcomp, install-sh, missing,
src/Makefile.am, src/mfoc.c, src/mifare.c, src/mifare.h,
src/nfc-utils.c, src/nfc-utils.h: update code in order to use libnfc
1.3.9, minor clean up, and minor enhancements.
2010-09-14 Romuald Conty <romuald@libnfc.org>
* Import MFOC 0.08 from http://www.nethemba.com/mfoc.tar.bz2 on 13th
Sept 2010

View File

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 {} \;

View File

@@ -1,4 +1,4 @@
AC_INIT([mfoc], [0.10.1], [mifare@nethemba.com]) AC_INIT([mfoc],[0.10.5],[mifare@nethemba.com])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
@@ -13,20 +13,29 @@ 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.4.2 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])
AC_C_INLINE
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL AC_HEADER_STDBOOL
AC_TYPE_SIZE_T
AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T AC_TYPE_UINT32_T
AC_TYPE_UINT64_T AC_TYPE_UINT64_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])
# C99
CFLAGS="$CFLAGS -std=c99"
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
src/Makefile]) src/Makefile])

6
debian/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
autoreconf.after
autoreconf.before
files
mfoc.debhelper.log
mfoc.substvars
mfoc/

11
debian/changelog vendored Normal file
View File

@@ -0,0 +1,11 @@
mfoc (0.10.4-0) unstable; urgency=low
* New upstream release
-- Romuald Conty <romuald@libnfc.org> Sun, 20 Jan 2013 15:58:42 +0100
mfoc (0.10.2pre3.1-0) unstable; urgency=low
* Initial package
-- Thomas Hood <jdthood@gmail.com> Wed, 18 May 2011 12:00:00 +0200

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
7

17
debian/control vendored Normal file
View File

@@ -0,0 +1,17 @@
Source: mfoc
Section: utils
Priority: extra
Maintainer: Thomas Hood <jdthood@gmail.com>
Build-Depends: debhelper (>= 7.0.50~), dh-autoreconf, libnfc-dev (>= 1.7.0), pkg-config
Standards-Version: 3.9.2
Homepage: http://code.google.com/p/nfc-tools/wiki/mfoc
Vcs-Svn: http://nfc-tools.googlecode.com/svn/trunk/mfoc
Vcs-Browser: http://code.google.com/p/nfc-tools/source/browse/#svn/trunk/mfoc
Package: mfoc
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: MIFARE Classic offline cracker
This package includes the mfoc program which cracks the
encryption keys of the MIFARE Classic chip and dumps the
chip's memory contents to a file.

44
debian/copyright vendored Normal file
View File

@@ -0,0 +1,44 @@
Format: http://dep.debian.net/deps/dep5
Upstream-Name: MFOC
Source: http://nfc-tools.googlecode.com/svn/trunk/mfoc
Files: *
Copyright: 2009 Norbert Szetei, Pavol Luptak
2010 Micahal Boska, Romuald Conty
2011 Romuald Conty
License: GPL-2+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General Public
License version 2 can be found in "/usr/share/common-licenses/GPL-2".
Files: debian/*
Copyright: 2011 Thomas Hood <jdthood@gmail.com>
License: GPL-2+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General Public
License version 2 can be found in "/usr/share/common-licenses/GPL-2".

1
debian/docs vendored Normal file
View File

@@ -0,0 +1 @@
AUTHORS

1
debian/manpages vendored Normal file
View File

@@ -0,0 +1 @@
src/mfoc.1

16
debian/rules vendored Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
override_dh_installchangelogs:
dh_installchangelogs ChangeLog
%:
dh --with autoreconf $@

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (quilt)

7
debian/watch vendored Normal file
View File

@@ -0,0 +1,7 @@
# See uscan(1) for format
# Compulsory line, this is a version 3 file
version=3
http://code.google.com/p/nfc-tools/downloads/list .*/mfoc-(.*).tar.gz

View File

@@ -1,9 +1,10 @@
AM_CFLAGS = @LIBNFC_CFLAGS@ AM_CFLAGS = @libnfc_CFLAGS@
AM_LDFLAGS = @LIBNFC_LIBS@
bin_PROGRAMS = mfoc bin_PROGRAMS = mfoc
noinst_HEADERS = crapto1.h mfoc.h mifare.h nfc-utils.h noinst_HEADERS = crapto1.h mfoc.h mifare.h nfc-utils.h
mfoc_SOURCES = crapto1.c crypto1.c mfoc.c mifare.c nfc-utils.c
# dist_man_MANS = mfoc.1 mfoc_SOURCES = crapto1.c crypto1.c mfoc.c mifare.c nfc-utils.c
mfoc_LDADD = @libnfc_LIBS@
dist_man_MANS = mfoc.1

View File

@@ -22,52 +22,52 @@
#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); *it ^= (*it ^= *rit, *rit ^= *it);
if(*rit >= *start) if (*rit >= *start)
--rit; --rit;
if(rit != start) if (rit != start)
*rit ^= (*rit ^= *start, *start ^= *rit); *rit ^= (*rit ^= *start, *start ^= *rit);
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 +76,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 +89,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 +111,250 @@ 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_rollback_word(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); s->odd ^= (s->odd ^= s->even, s->even ^= s->odd);
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 +363,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,63 +394,64 @@ 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;
} }
struct Crypto1State *lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]);
/** lfsr_common_prefix /** lfsr_common_prefix
* Implentation of the common prefix attack. * Implentation of the common prefix attack.
* Requires the 29 bit constant prefix used as reader nonce (pfx) * Requires the 29 bit constant prefix used as reader nonce (pfx)
@@ -453,35 +461,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,64 +24,65 @@
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_recovery32(uint32_t ks2, uint32_t in);
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3); struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3);
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( "movl %1, %%eax\n" __asm__("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,62 @@
#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); s->odd ^= (s->odd ^= s->even, s->even ^= s->odd);
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 +84,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);
} }

41
src/mfoc.1 Normal file
View File

@@ -0,0 +1,41 @@
.\" Hey, EMACS: -*- nroff -*-
.TH MFOC 1 "May 13, 2011"
.SH NAME
mfoc \- MIFARE Classic offline cracker
.SH SYNOPSIS
.B mfoc
[ \fB\-h\fP ]
[ \fB\-k\fP \fIKEY\fR ]...
[ \fB\-O\fP \fIFILE\fR ]
[ \fB\-P\fP \fINUM\fR ]
[ \fB\-T\fP \fINUM\fR ]
.SH DESCRIPTION
This manual page documents briefly the
.B mfoc
command.
.PP
\fBmfoc\fP is a program that cracks the encryption of a MIFARE Classic chip and dumps the chip's keys and decrypted memory contents to a file.
To run it you need to have access to an NFC reader and, of course, a card equipped with a MIFARE Classic chip.
.SH OPTIONS
A summary of options is included below.
.TP
\fB\-h\fP
Show summary of options.
.TP
\fB\-k\fP \fIKEY\fR
Initially try KEY in addition to the default keys.
.TP
\fB\-O\fP \fIFILE\fR
Dump card contents to FILE.
.TP
\fB\-P\fP \fINUM\fR
Probe each sector up to NUM times. Default is 20.
.TP
\fB\-T\fP \fINUM\fR
Set half the range for a possible distance tolerance to NUM. Default is 20 (for a total range of 40).
.SH AUTHOR
.B mfoc
was written by Norbert Szetei and Pavol Luptak with contributions by others.
.PP
This manual page was written by Thomas Hood <jdthood@gmail.com>.
MIFARE is a trade mark of NXP bv, Netherlands.

1548
src/mfoc.c

File diff suppressed because it is too large Load Diff

View File

@@ -24,63 +24,63 @@
#define odd_parity(i) (( (i) ^ (i)>>1 ^ (i)>>2 ^ (i)>>3 ^ (i)>>4 ^ (i)>>5 ^ (i)>>6 ^ (i)>>7 ^ 1) & 0x01) #define odd_parity(i) (( (i) ^ (i)>>1 ^ (i)>>2 ^ (i)>>3 ^ (i)>>4 ^ (i)>>5 ^ (i)>>6 ^ (i)>>7 ^ 1) & 0x01)
typedef struct { typedef struct {
byte_t KeyA[6]; uint8_t KeyA[6];
byte_t KeyB[6]; uint8_t KeyB[6];
bool foundKeyA; bool foundKeyA;
bool foundKeyB; bool foundKeyB;
byte_t trailer; // Value of a trailer block uint8_t trailer; // Value of a trailer block
} sector; } sector;
typedef struct { typedef struct {
u_int32_t *distances; uint32_t *distances;
u_int32_t median; uint32_t median;
u_int32_t num_distances; uint32_t num_distances;
u_int32_t tolerance; uint32_t tolerance;
byte_t parity[3]; // used for 3 bits of parity information uint8_t parity[3]; // used for 3 bits of parity information
} denonce; // Revealed information about nonce } denonce; // Revealed information about nonce
typedef struct { typedef struct {
nfc_target_t nt; nfc_target nt;
sector * sectors; // Allocate later, we do not know the number of sectors yet sector *sectors; // Allocate later, we do not know the number of sectors yet
sector e_sector; // Exploit sector sector e_sector; // Exploit sector
uint32_t num_sectors; uint8_t num_sectors;
uint32_t num_blocks; uint8_t num_blocks;
uint32_t uid; uint32_t authuid;
bool b4K; bool b4K;
} mftag; } mftag;
typedef struct { typedef struct {
uint64_t *possibleKeys; uint64_t *possibleKeys;
uint32_t size; uint32_t size;
} pKeys; } pKeys;
typedef struct { typedef struct {
uint64_t *brokenKeys; uint64_t *brokenKeys;
uint32_t size; int32_t size;
} bKeys; } bKeys;
typedef struct { typedef struct {
nfc_device_t *pdi; nfc_device *pdi;
} mfreader; } mfreader;
typedef struct { typedef struct {
uint64_t key; uint64_t key;
int count; int count;
} countKeys; } countKeys;
void usage(FILE * stream, int errno); void usage(FILE *stream, int errno);
void mf_init(mftag *t, mfreader *r); void mf_init(mfreader *r);
void mf_configure(nfc_device_t* pdi); void mf_configure(nfc_device *pdi);
void mf_select_tag(nfc_device_t* pdi, nfc_target_t* pnt); void mf_select_tag(nfc_device *pdi, nfc_target *pnt);
int trailer_block(uint32_t block); int trailer_block(uint32_t block);
int find_exploit_sector(mftag t); int find_exploit_sector(mftag t);
void mf_anticollision(mftag t, mfreader r); void mf_anticollision(mftag t, mfreader r);
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA); int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA);
uint32_t median(denonce d); uint32_t median(denonce d);
int compar_int(const void * a, const void * b); int compar_int(const void *a, const void *b);
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity); int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity);
int compar_special_int(const void * a, const void * b); int compar_special_int(const void *a, const void *b);
countKeys * uniqsort(uint64_t *possibleKeys, uint32_t size); countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size);
void num_to_bytes(uint64_t n, uint32_t len, byte_t* dest); void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest);
long long unsigned int bytes_to_num(byte_t* src, uint32_t len); long long unsigned int bytes_to_num(uint8_t *src, uint32_t len);

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,81 +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)) { 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 if (pnd->iLastError == EMFAUTH) {
// In MFOC, we have to hide authentication errors :)
} else { } else {
nfc_perror (pnd, "nfc_initiator_transceive_bytes"); nfc_perror(pnd, "nfc_initiator_transceive_bytes");
} }
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,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, 2011 Romain Tartière
* Copyright (C) 2009, 2010, 2011, 2012 Romuald Conty
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@@ -27,93 +28,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,601 +107,18 @@ print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDa
// Print the rest bits, these cannot have parity bit // Print the rest bits, these cannot have parity bit
if (uRemainder != 0) { if (uRemainder != 0) {
if (uRemainder < 5) if (uRemainder < 5)
printf ("%01x (%d bits)", pbtData[szBytes], uRemainder); printf("%01x (%d bits)", pbtData[szBytes], uRemainder);
else else
printf ("%02x (%d bits)", pbtData[szBytes], uRemainder); printf("%02x (%d bits)", pbtData[szBytes], uRemainder);
}
printf ("\n");
}
#define SAK_UID_NOT_COMPLETE 0x04
#define SAK_ISO14443_4_COMPLIANT 0x20
#define SAK_ISO18092_COMPLIANT 0x40
void
print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose)
{
printf (" ATQA (SENS_RES): ");
print_hex (nai.abtAtqa, 2);
if (verbose) {
printf("* UID size: ");
switch ((nai.abtAtqa[1] & 0xc0)>>6) {
case 0:
printf("single\n");
break;
case 1:
printf("double\n");
break;
case 2:
printf("triple\n");
break;
case 3:
printf("RFU\n");
break;
}
printf("* bit frame anticollision ");
switch (nai.abtAtqa[1] & 0x1f) {
case 0x01:
case 0x02:
case 0x04:
case 0x08:
case 0x10:
printf("supported\n");
break;
default:
printf("not supported\n");
break;
}
}
printf (" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
print_hex (nai.abtUid, nai.szUidLen);
if (verbose) {
if (nai.abtUid[0] == 0x08) {
printf ("* Random UID\n");
}
}
printf (" SAK (SEL_RES): ");
print_hex (&nai.btSak, 1);
if (verbose) {
if (nai.btSak & SAK_UID_NOT_COMPLETE) {
printf ("* Warning! Cascade bit set: UID not complete\n");
}
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
printf ("* Compliant with ISO/IEC 14443-4\n");
} else {
printf ("* Not compliant with ISO/IEC 14443-4\n");
}
if (nai.btSak & SAK_ISO18092_COMPLIANT) {
printf ("* Compliant with ISO/IEC 18092\n");
} else {
printf ("* Not compliant with ISO/IEC 18092\n");
}
}
if (nai.szAtsLen) {
printf (" ATS: ");
print_hex (nai.abtAts, nai.szAtsLen);
}
if (nai.szAtsLen && verbose) {
// Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
printf ("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
size_t offset = 1;
if (nai.abtAts[0] & 0x10) { // TA(1) present
byte_t TA = nai.abtAts[offset];
offset++;
printf ("* Bit Rate Capability:\n");
if (TA == 0) {
printf (" * PICC supports only 106 kbits/s in both directions\n");
}
if (TA & 1<<7) {
printf (" * Same bitrate in both directions mandatory\n");
}
if (TA & 1<<4) {
printf (" * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
}
if (TA & 1<<5) {
printf (" * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
}
if (TA & 1<<6) {
printf (" * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
}
if (TA & 1<<0) {
printf (" * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
}
if (TA & 1<<1) {
printf (" * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
}
if (TA & 1<<2) {
printf (" * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
}
if (TA & 1<<3) {
printf (" * ERROR unknown value\n");
}
}
if (nai.abtAts[0] & 0x20) { // TB(1) present
byte_t TB= nai.abtAts[offset];
offset++;
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((TB & 0xf0) >> 4))/13560.0);
if ((TB & 0x0f) == 0) {
printf ("* No Start-up Frame Guard Time required\n");
} else {
printf ("* Start-up Frame Guard Time: %.4g ms\n",256.0*16.0*(1<<(TB & 0x0f))/13560.0);
}
}
if (nai.abtAts[0] & 0x40) { // TC(1) present
byte_t TC = nai.abtAts[offset];
offset++;
if (TC & 0x1) {
printf("* Node ADdress supported\n");
} else {
printf("* Node ADdress not supported\n");
}
if (TC & 0x2) {
printf("* Card IDentifier supported\n");
} else {
printf("* Card IDentifier not supported\n");
}
}
if (nai.szAtsLen > offset) {
printf ("* Historical bytes Tk: " );
print_hex (nai.abtAts + offset, (nai.szAtsLen - offset));
byte_t CIB = nai.abtAts[offset];
offset++;
if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
printf(" * Proprietary format\n");
if (CIB == 0xc1) {
printf(" * Tag byte: Mifare or virtual cards of various types\n");
byte_t L = nai.abtAts[offset];
offset++;
if (L != (nai.szAtsLen - offset)) {
printf(" * Warning: Type Identification Coding length (%i)", L);
printf(" not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
}
if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
byte_t CTC = nai.abtAts[offset];
offset++;
printf(" * Chip Type: ");
switch (CTC & 0xf0) {
case 0x00:
printf("(Multiple) Virtual Cards\n");
break;
case 0x10:
printf("Mifare DESFire\n");
break;
case 0x20:
printf("Mifare Plus\n");
break;
default:
printf("RFU\n");
break;
}
printf(" * Memory size: ");
switch (CTC & 0x0f) {
case 0x00:
printf("<1 kbyte\n");
break;
case 0x01:
printf("1 kbyte\n");
break;
case 0x02:
printf("2 kbyte\n");
break;
case 0x03:
printf("4 kbyte\n");
break;
case 0x04:
printf("8 kbyte\n");
break;
case 0x0f:
printf("Unspecified\n");
break;
default:
printf("RFU\n");
break;
}
}
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
byte_t CVC = nai.abtAts[offset];
offset++;
printf(" * Chip Status: ");
switch (CVC & 0xf0) {
case 0x00:
printf("Engineering sample\n");
break;
case 0x20:
printf("Released\n");
break;
default:
printf("RFU\n");
break;
}
printf(" * Chip Generation: ");
switch (CVC & 0x0f) {
case 0x00:
printf("Generation 1\n");
break;
case 0x01:
printf("Generation 2\n");
break;
case 0x02:
printf("Generation 3\n");
break;
case 0x0f:
printf("Unspecified\n");
break;
default:
printf("RFU\n");
break;
}
}
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
byte_t VCS = nai.abtAts[offset];
offset++;
printf(" * Specifics (Virtual Card Selection):\n");
if ((VCS & 0x09) == 0x00) {
printf(" * Only VCSL supported\n");
} else if ((VCS & 0x09) == 0x01) {
printf(" * VCS, VCSL and SVC supported\n");
}
if ((VCS & 0x0e) == 0x00) {
printf(" * SL1, SL2(?), SL3 supported\n");
} else if ((VCS & 0x0e) == 0x02) {
printf(" * SL3 only card\n");
} else if ((VCS & 0x0f) == 0x0e) {
printf(" * No VCS command supported\n");
} else if ((VCS & 0x0f) == 0x0f) {
printf(" * Unspecified\n");
} else {
printf(" * RFU\n");
}
}
}
} else {
if (CIB == 0x00) {
printf(" * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n");
printf(" followed by a mandatory status indicator (the last three bytes, not in TLV)\n");
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
}
if (CIB == 0x10) {
printf(" * DIR data reference: %02x\n", nai.abtAts[offset]);
}
if (CIB == 0x80) {
if (nai.szAtsLen == offset) {
printf(" * No COMPACT-TLV objects found, no status found\n");
} else {
printf(" * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n");
printf(" the last data object may carry a status indicator of one, two or three bytes.\n");
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
}
}
}
}
}
if (verbose) {
printf("Fingerprinting based on ATQA & SAK values:\n");
uint32_t atqasak = 0;
atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff)<<16);
atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff)<<8);
atqasak += ((uint32_t)nai.btSak & 0xff);
bool found_possible_match = false;
switch (atqasak) {
case 0x000218:
printf("* Mifare Classic 4K\n");
found_possible_match = true;
break;
case 0x000408:
printf("* Mifare Classic 1K\n");
printf("* Mifare Plus (4-byte UID) 2K SL1\n");
found_possible_match = true;
break;
case 0x000409:
printf("* Mifare MINI\n");
found_possible_match = true;
break;
case 0x000410:
printf("* Mifare Plus (4-byte UID) 2K SL2\n");
found_possible_match = true;
break;
case 0x000411:
printf("* Mifare Plus (4-byte UID) 4K SL2\n");
found_possible_match = true;
break;
case 0x000418:
printf("* Mifare Plus (4-byte UID) 4K SL1\n");
found_possible_match = true;
break;
case 0x000420:
printf("* Mifare Plus (4-byte UID) 2K/4K SL3\n");
found_possible_match = true;
break;
case 0x004400:
printf("* Mifare Ultralight\n");
printf("* Mifare UltralightC\n");
found_possible_match = true;
break;
case 0x004208:
case 0x004408:
printf("* Mifare Plus (7-byte UID) 2K SL1\n");
found_possible_match = true;
break;
case 0x004218:
case 0x004418:
printf("* Mifare Plus (7-byte UID) 4K SL1\n");
found_possible_match = true;
break;
case 0x004210:
case 0x004410:
printf("* Mifare Plus (7-byte UID) 2K SL2\n");
found_possible_match = true;
break;
case 0x004211:
case 0x004411:
printf("* Mifare Plus (7-byte UID) 4K SL2\n");
found_possible_match = true;
break;
case 0x004220:
case 0x004420:
printf("* Mifare Plus (7-byte UID) 2K/4K SL3\n");
found_possible_match = true;
break;
case 0x034420:
printf("* Mifare DESFire / Desfire EV1\n");
found_possible_match = true;
break;
}
// Other matches not described in
// AN MIFARE Type Identification Procedure
// but seen in the field:
switch (atqasak) {
case 0x000488:
printf("* Mifare Classic 1K Infineon\n");
found_possible_match = true;
break;
case 0x000298:
printf("* Gemplus MPCOS\n");
found_possible_match = true;
break;
case 0x030428:
printf("* JCOP31\n");
found_possible_match = true;
break;
case 0x004820:
printf("* JCOP31 v2.4.1\n");
printf("* JCOP31 v2.2\n");
found_possible_match = true;
break;
case 0x000428:
printf("* JCOP31 v2.3.1\n");
found_possible_match = true;
break;
case 0x000453:
printf("* Fudan FM1208SH01\n");
found_possible_match = true;
break;
case 0x000820:
printf("* Fudan FM1208\n");
found_possible_match = true;
break;
case 0x000238:
printf("* MFC 4K emulated by Nokia 6212 Classic\n");
found_possible_match = true;
break;
case 0x000838:
printf("* MFC 4K emulated by Nokia 6131 NFC\n");
found_possible_match = true;
break;
}
if ((nai.abtAtqa[0] & 0xf0) == 0) {
switch (nai.abtAtqa[1]) {
case 0x02:
printf("* SmartMX with Mifare 4K emulation\n");
found_possible_match = true;
break;
case 0x04:
printf("* SmartMX with Mifare 1K emulation\n");
found_possible_match = true;
break;
case 0x48:
printf("* SmartMX with 7-byte UID\n");
found_possible_match = true;
break;
}
}
if (! found_possible_match) {
printf("* Unknown card, sorry\n");
}
} }
printf("\n");
} }
void void
print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose) print_nfc_target(const nfc_target nt, bool verbose)
{ {
(void) verbose; char *s;
printf (" ID (NFCID2): "); str_nfc_target(&s, nt, verbose);
print_hex (nfi.abtId, 8); printf("%s", s);
printf (" Parameter (PAD): "); free(s);
print_hex (nfi.abtPad, 8);
} }
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_dep_info (const nfc_dep_info_t ndi, bool verbose)
{
(void) verbose;
printf (" NFCID3: ");
print_hex (ndi.abtNFCID3, 10);
printf (" BS: %02x\n", ndi.btBS);
printf (" BR: %02x\n", ndi.btBR);
printf (" TO: %02x\n", ndi.btTO);
printf (" PP: %02x\n", ndi.btPP);
if (ndi.szGB) {
printf ("General Bytes: ");
print_hex (ndi.abtGB, ndi.szGB);
}
}
/**
* @brief Tries to parse arguments to find device descriptions.
* @return Returns the list of found device descriptions.
*/
nfc_device_desc_t *
parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose)
{
nfc_device_desc_t *pndd = 0;
int arg;
*szFound = 0;
// Get commandline options
for (arg = 1; arg < argc; arg++) {
if (0 == strcmp (argv[arg], "--device")) {
// FIXME: this device selection by command line options is terrible & does not support USB/PCSC drivers
if (argc > arg + 1) {
char buffer[256];
pndd = malloc (sizeof (nfc_device_desc_t));
strncpy (buffer, argv[++arg], 256);
// Driver.
pndd->pcDriver = (char *) malloc (256);
strcpy (pndd->pcDriver, strtok (buffer, ":"));
// Port.
pndd->pcPort = (char *) malloc (256);
strcpy (pndd->pcPort, strtok (NULL, ":"));
// Speed.
sscanf (strtok (NULL, ":"), "%u", &pndd->uiSpeed);
*szFound = 1;
} else {
errx (1, "usage: %s [--device driver:port:speed]", argv[0]);
}
}
if ((0 == strcmp (argv[arg], "-v")) || (0 == strcmp (argv[arg], "--verbose"))) {
*verbose = true;
}
}
return pndd;
}
const char *
str_nfc_baud_rate (const nfc_baud_rate_t nbr)
{
switch(nbr) {
case NBR_UNDEFINED:
return "undefined baud rate";
break;
case NBR_106:
return "106 kbps";
break;
case NBR_212:
return "212 kbps";
break;
case NBR_424:
return "424 kbps";
break;
case NBR_847:
return "847 kbps";
break;
}
return "";
}
void
print_nfc_target (const nfc_target_t nt, bool verbose)
{
switch(nt.nm.nmt) {
case NMT_ISO14443A:
printf ("ISO/IEC 14443A (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443a_info (nt.nti.nai, verbose);
break;
case NMT_JEWEL:
printf ("Innovision Jewel (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_jewel_info (nt.nti.nji, verbose);
break;
case NMT_FELICA:
printf ("FeliCa (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_felica_info (nt.nti.nfi, verbose);
break;
case NMT_ISO14443B:
printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_iso14443b_info (nt.nti.nbi, verbose);
break;
case NMT_DEP:
printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
print_nfc_dep_info (nt.nti.ndi, verbose);
break;
}
}

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, 2012 Romuald Conty
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@@ -79,21 +80,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_felica_info (const nfc_felica_info_t nfi, bool verbose); void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar);
void print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose);
void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose);
void print_nfc_target (const nfc_target_t nt, bool verbose); void print_nfc_target(const nfc_target nt, bool verbose);
nfc_device_desc_t *parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose);
#endif #endif