Compare commits

...

97 commits

Author SHA1 Message Date
Davide Depau 5524dd8af4 Always pretend cards are not vulnerable 2023-10-21 00:41:39 +02:00
Samuel Henrique ba072f16f6 update debian dir with up-to-date packaging 2018-07-24 11:45:40 +02:00
Philippe Teuwen dd0ce5caa6
Merge pull request #51 from iceman1001/master
define   #endif warning
2018-02-03 21:25:47 +01:00
Iceman 987c3dab3a
Merge pull request #1 from iceman1001/iceman1001-patch-1
chg:  remote faulty statement
2018-02-02 23:38:21 +01:00
Iceman 77db13ef90
chg: remote faulty statement
copy-paste error,  #endif
2018-02-02 23:38:08 +01:00
Romuald Conty 519e475b09
Merge pull request #50 from iceman1001/master
FIX:  warnings on gcc v7.2 ubuntu
2018-01-31 18:42:19 +01:00
Romuald Conty fa3573cfb6
Merge pull request #49 from ceres-c/patch-1
Fixed readme compiling options
2018-01-31 18:29:39 +01:00
Federico Cerutti c24b6ac572
Updated (again) readme using a single command 2018-01-31 14:39:14 +01:00
user 593315f7d4 FIX: warning "DBG" redefine 2018-01-31 11:22:41 +01:00
Federico Cerutti 9fed51206f
Added missing "autoconf" to readme 2018-01-20 16:27:49 +01:00
Romuald Conty 809f3bc62c
Merge pull request #45 from agebhar1/patch/README.md
add 'Build from source' section to `README.md`
2018-01-09 23:07:41 +01:00
Andreas Gebhardt b13beeac09 add 'Build from source' section to README.md 2017-10-12 19:58:15 +02:00
Philippe Teuwen 9d9f01fba4 Simplify PRNG validation 2017-02-17 16:14:01 +01:00
Philippe Teuwen 34d42e5e47 Port miLazyCracker patch: test PRNG
cf 39658a2ac4/mfoc_test_prng.diff
2017-02-17 15:44:30 +01:00
Philippe Teuwen 2316ad0815 Replace non-ANSI-C getline by fgets 2017-02-17 15:44:30 +01:00
Philippe Teuwen 0970559b97 Port miLazyCracker patch: support 2k
cf 39658a2ac4/mfoc_support_2k.diff
2017-02-17 13:52:48 +01:00
Philippe Teuwen e36025bb25 Port miLazyCracker patch: support tnp
cf 39658a2ac4/mfoc_support_tnp.diff
2017-02-17 13:52:48 +01:00
Philippe Teuwen f172064f98 Port miLazyCracker patch: fix 4k and Mini
cf 39658a2ac4/mfoc_fix_4k_and_mini.diff
2017-02-17 13:52:48 +01:00
Romuald Conty 48156f9bf0 Merge pull request #23 from AdamLaurie/master
Show known keys before trying to crack
2015-06-09 14:41:27 +02:00
Adam Laurie e2cf90202a show known keys before trying to crack 2015-06-08 16:34:00 +01:00
Romuald Conty eac78225eb Merge pull request #20 from quantum-x/master
Adds ability to load custom keys from a file
2015-04-15 14:33:33 +02:00
Simon Yorkston 51bae1e1c8 Final tweaks to regexp 2015-04-15 14:24:55 +02:00
Simon Yorkston 0976e6f285 Added -f to CL arguments 2015-04-15 13:28:50 +02:00
Simon Yorkston eff3dc0d5f Updated SLRE syntax to comply with new version 2015-04-15 13:25:43 +02:00
Simon Yorkston 7ff1465409 Added SLRE files 2015-04-15 13:22:08 +02:00
Simon Yorkston c346e2af72 Tweaked in the SLRE libraries 2015-04-15 13:18:09 +02:00
Simon Yorkston 86caca5f6b Adding ability to load keys from file
Switch -f allows for a file to be provided that contains additional keys
2015-04-15 12:45:15 +02:00
Romuald Conty 00eae36f89 Merge pull request #19 from kirelagin/fixes
A bunch of pretty minor fixes
2015-04-13 08:57:11 +02:00
Kirill Elagin 3b5be84676 Proper amount of data to dump 2015-04-11 23:56:21 +03:00
Kirill Elagin f3ebde09ef Fix user-provided keys handling
This makes mfoc try user-provided keys even if the built-in
ones are removed from the code (for efficiency).
2015-04-11 23:30:58 +03:00
Kirill Elagin b872a328e3 Fix typo
This was horrible as this made mfoc non-functional for cards
with unknown SAK’s.
2015-04-11 23:30:20 +03:00
Kirill Elagin 30ce00aa8e Alternative Mifare Classic 1k SAK 2015-04-11 23:29:59 +03:00
Romuald Conty f3a793dc0c Merge pull request #18 from AdamLaurie/master
Don't bother cracking KeyB when you can just read it out of data block
2015-03-23 22:14:19 +01:00
Adam Laurie 5d8bf95968 don't bother cracking KeyB when you can just read it out of data block 2015-03-23 15:20:46 +00:00
Romuald Conty 1eac72641c Merge pull request #16 from socram8888/mini
Implemented Mifare Mini
2015-03-22 09:54:19 +01:00
Romuald Conty f3558144d8 Merge pull request #15 from socram8888/master
Fix compilation warnings under Cygwin
2015-03-22 09:51:29 +01:00
Marcos Vives Del Sol f13efb0a6d Implemented Mifare Mini using FireFart's patch 2015-03-17 16:06:16 +01:00
Marcos Vives Del Sol a1be79d0ff Fix compilation warnings under Cygwin 2015-03-17 15:04:28 +01:00
Romuald Conty b31ac50224 Create README.md 2015-03-14 20:51:58 +01:00
Romuald Conty 290a075956 Bump version to 0.10.7 2013-12-06 15:30:30 +01:00
Romuald Conty 2fa70fb3d3 Use bzip2 instead of gzip compression algorithm 2013-12-06 15:25:56 +01:00
Romuald Conty e1a2b0225f Check if nfc_init() returns a valid context
This fixes a potential segfault when libnfc is not correctly initialized
2013-12-06 15:24:08 +01:00
Romuald Conty 222ba1838c Display right message when no tag is detected
This fixes a potential segfault due to an access to uninitialised memory variable access
2013-12-06 15:22:42 +01:00
Romuald Conty fa47ca0223 Releases MFOC 0.10.6 2013-06-06 16:37:48 +02:00
Romuald Conty 9b37ccd725 Restore missing default keys
Bug introduced in previous commit...
2013-04-05 10:15:54 +02:00
Romuald Conty e5024608f3 Sync nfc-utils.[hc] with devel libnfc files 2013-04-04 23:55:00 +02:00
Romuald Conty ba7e75cd16 make style 2013-02-20 19:01:41 +01:00
Romuald Conty 0c2d2b5894 Fixes error handling when performing MIFARE commands:
Before this commit, MFOC was considering any errors as authentication error (AUTH command) or permission error (READ/WRITE commands);
With this patch, any error which is not a tag-related error will produce a program exit (with EXIT_FAILURE flag).

Plus, this commit silents MIFARE authentication error while MFOC try some default keys...
2013-02-20 18:50:42 +01:00
Romuald Conty 9a02d34ede Clean GPL licence header in mfoc.c 2013-02-20 18:44:29 +01:00
Romuald Conty 6b65fb4ca2 Cleans code: cosmetic variables alignment 2013-02-20 18:27:16 +01:00
Romuald Conty 0406f0002e Fixes comparaisons between signed and unsigned values 2013-02-20 18:23:07 +01:00
Romuald Conty b1bc800c83 Removes redundant redeclaration of ‘lfsr_rollback_word’ [-Wredundant-decls] 2013-02-20 18:11:56 +01:00
Romuald Conty 166a1467c2 Use defined macros instead of hardcoded values (MC_AUTH_A/MC_AUTH_B) 2013-02-20 18:08:36 +01:00
Romuald Conty 2b16dc7ff8 Prints symbols signification during key search 2013-02-20 18:05:57 +01:00
Romuald Conty 35489b09a1 Debian: update watch file 2013-02-19 20:05:49 +01:00
Romuald Conty ab826c9fe8 Debian: upgrade compat from 7 to 9 2013-02-16 15:57:34 +01:00
Romuald Conty e52c737242 Debian: update program description 2013-02-16 15:56:28 +01:00
Romuald Conty 205050848c Debian: update website and VCS 2013-02-16 15:55:49 +01:00
Romuald Conty ed16dec250 Debian: allow to use libnfc 1.7.0 RCx 2013-02-16 15:54:23 +01:00
Romuald Conty d10f2e0bdb Debian: new entry for 0.10.5 2013-02-16 15:50:55 +01:00
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
29 changed files with 2808 additions and 2130 deletions

23
.gitignore vendored Normal file
View file

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

View file

@ -6,4 +6,4 @@ Pavol Luptak - project leader, minor coding, testing and bugreporting
= Contributors
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

261
ChangeLog
View file

@ -1,90 +1,243 @@
2011-05-18 09:18 rconty@il4p.fr
2013-01-20 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: mfoc: improve tests made before running and show tag
info using print_nfc_iso14443a_info()
* ChangeLog: Update outdated email addresses
2011-04-08 15:19 rconty@il4p.fr
2013-01-20 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: mfoc: try to disconnect() the device on error.
* src/crapto1.c, src/crapto1.h, src/crypto1.c, src/mfoc.c,
src/mfoc.h: Format source code with "make style"
2011-04-08 10:05 rconty@il4p.fr
2013-01-20 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: mfoc: show errors then exit on mf_configure()
* Makefile.am: Add "make style" directive to format source code
2011-04-08 09:32 rconty@il4p.fr
2013-01-20 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: mfoc: apply a patch suggested by Valentijn Sessink.
See Issue 56.
* configure.ac, src/mfoc.c: Updates source to use libnfc 1.7.0
2011-04-08 09:17 rconty@il4p.fr
2013-01-20 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: mfoc: minors fixes and indent.
* src/mifare.c, src/mifare.h, src/nfc-utils.c, src/nfc-utils.h:
Update mifare.* and nfc-utils.* from libnfc utils directory
2011-04-08 08:54 rconty@il4p.fr
2013-01-20 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: mfoc: show error (using nfc_perror) then exit if some
nfc_* functions failed on init.
* .gitignore: Ignore generated files in source repository
2011-04-08 08:35 rconty@il4p.fr
2012-10-14 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: mfoc: minor debug improvements.
* src/mfoc.c: Fix tolerance (-T) option (Fixes issue 102) Thanks to
fnargwibble
2011-04-04 12:28 rconty@il4p.fr
2012-06-03 Romuald Conty <romuald@libnfc.org>
* configure.ac, src/mfoc.c: mfoc: minor fixes/enhancements and
version bumping
* src/mifare.c: do not display an error when authentication failed
2011-04-04 10:38 rconty@il4p.fr
2012-06-03 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c, src/mifare.c: mfoc: hide authentication errors
* src/mfoc.c, src/mfoc.h: use authuid instead uid name when handling
the authentication uid bytes (different from UID with 7bytes MIFARE
Classic
2011-04-04 10:01 rconty@il4p.fr
2012-06-03 Romuald Conty <romuald@libnfc.org>
* src/mifare.c, src/mifare.h, src/nfc-utils.c, src/nfc-utils.h:
mfoc: sync nfc-utils.h/c and mifare.c/h with libnfc's ones.
* 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/ +$//'
2011-02-21 16:26 rtartiere@il4p.fr
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 10:46 rconty@il4p.fr
2011-02-02 Romuald Conty <romuald@libnfc.org>
* src/mfoc.c: mfoc: use strtoll() function in order to retrieve
64bits wide value. (Fixes Issue 55)
* src/mfoc.c: use strtoll() function in order to retrieve 64bits
wide value. (Fixes Issue 55)
2010-11-18 11:20 rconty@il4p.fr
2010-11-18 Romuald Conty <romuald@libnfc.org>
* configure.ac: mfoc: bump package version
* configure.ac: bump package version
2010-11-18 11:18 rconty@il4p.fr
2010-11-18 Romuald Conty <romuald@libnfc.org>
* src/nfc-utils.c, src/nfc-utils.h: mfoc: sync nfc-utils.* from
libnfc
* src/nfc-utils.c, src/nfc-utils.h: sync nfc-utils.* from libnfc
2010-11-02 09:36 rconty@il4p.fr
2010-11-02 Romuald Conty <romuald@libnfc.org>
* configure.ac, src/mfoc.c, src/mfoc.h, src/nfc-utils.c,
src/nfc-utils.h: mfoc: 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;
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 09:38 rconty@il4p.fr
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, src/Makefile.am, src/mfoc.c, src/mifare.c,
src/mifare.h, src/nfc-utils.c, src/nfc-utils.h: mfoc: update code
in order to use libnfc 1.3.9, minor clean up, and minor
enhancements.
* 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 09:34 rconty@il4p.fr
2010-09-14 Romuald Conty <romuald@libnfc.org>
* ., AUTHORS, COPYING, ChangeLog, INSTALL, Makefile.am,
Makefile.in, NEWS, README, TODO, aclocal.m4, autogen.sh,
config.h, config.h.in, configure, configure.ac, depcomp,
install-sh, missing, src, src/Makefile.am, src/crapto1.c,
src/crapto1.h, src/crypto1.c, src/mfoc.c, src/mfoc.h: Import MFOC
0.08 from http://www.nethemba.com/mfoc.tar.bz2 on 13th Sept 2010
* Import MFOC 0.08 from http://www.nethemba.com/mfoc.tar.bz2 on 13th
Sept 2010

View file

@ -1,4 +1,10 @@
SUBDIRS = src
#pkgconfigdir = $(libdir)/pkgconfig
#pkgconfig_DATA = libnfc.pc
style:
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 {} \;

20
README.md Normal file
View file

@ -0,0 +1,20 @@
MFOC is an open source implementation of "offline nested" attack by Nethemba.
This program allow to recover authentication keys from MIFARE Classic card.
Please note MFOC is able to recover keys from target only if it have a known key: default one (hardcoded in MFOC) or custom one (user provided using command line).
# Build from source
```
autoreconf -is
./configure
make && sudo make install
```
# Usage #
Put one MIFARE Classic tag that you want keys recovering;
Lauching mfoc, you will need to pass options, see
```
mfoc -h
```

View file

@ -1,32 +1,41 @@
AC_INIT([mfoc], [0.10.2], [mifare@nethemba.com])
AC_INIT([mfoc],[0.10.7],[mifare@nethemba.com])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/mfoc.c])
AM_INIT_AUTOMAKE
AM_INIT_AUTOMAKE(dist-bzip2 no-dist-gzip)
AC_PROG_CC
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
# Checks for pkg-config modules.
LIBNFC_REQUIRED_VERSION=1.4.2
PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
LIBNFC_REQUIRED_VERSION=1.7.0
PKG_CHECK_MODULES([libnfc], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
PKG_CONFIG_REQUIRES="libnfc"
AC_SUBST([PKG_CONFIG_REQUIRES])
AC_C_INLINE
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_TYPE_SIZE_T
AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([memset])
# C99
CFLAGS="$CFLAGS -std=c99"
AC_CONFIG_FILES([Makefile
src/Makefile])

67
debian/changelog vendored Normal file
View file

@ -0,0 +1,67 @@
mfoc (0.10.7+git20180724-1) unstable; urgency=medium
* New upstream version 0.10.7+git20180724
-- Samuel Henrique <samueloph@debian.org> Tue, 24 Jul 2018 01:19:50 -0300
mfoc (0.10.7+git20150512-0kali1) kali; urgency=medium
* Import upstream (Closes: 0002240)
* Update debian files: watch, copyright
* Use debhelper 9
-- Sophie Brun <sophie@freexian.com> Tue, 12 May 2015 12:05:24 +0200
mfoc (0.10.7-0kali2) kali; urgency=low
* Updated watch file
-- Mati Aharoni <muts@kali.org> Sun, 12 Jan 2014 18:06:21 -0500
mfoc (0.10.7-0kali1) kali; urgency=low
* Upstream import
-- Mati Aharoni <muts@kali.org> Tue, 17 Dec 2013 09:12:38 -0500
mfoc (0.10.6-0kali0) kali; urgency=low
* Upstream import
-- Mati Aharoni <muts@kali.org> Mon, 19 Aug 2013 10:37:12 -0400
mfoc (0.10.5-0kali0) kali; urgency=low
* Upstream import.
-- Mati Aharoni <muts@kali.org> Sun, 24 Mar 2013 05:49:58 -0400
mfoc (0.10.3-1kali4) kali; urgency=low
* Removed desktop file
-- Mati Aharoni <muts@kali.org> Sat, 15 Dec 2012 14:23:37 -0500
mfoc (0.10.3-1kali3) kali; urgency=low
* Fixed compilation issue
-- Mati Aharoni <muts@kali.org> Tue, 04 Dec 2012 06:43:46 -0500
mfoc (0.10.3-1kali2) kali; urgency=low
* Version bump
-- Mati Aharoni <muts@kali.org> Sat, 01 Dec 2012 16:23:29 -0500
mfoc (0.10.3-1kali1) kali; urgency=low
* Version bump
-- Mati Aharoni <muts@kali.org> Sat, 01 Dec 2012 16:13:27 -0500
mfoc (0.10.3-1kali0) kali; urgency=low
* Initial release
-- Mati Aharoni <muts@kali.org> Sat, 01 Dec 2012 13:42:57 -0500

1
debian/compat vendored Normal file
View file

@ -0,0 +1 @@
11

18
debian/control vendored Normal file
View file

@ -0,0 +1,18 @@
Source: mfoc
Section: utils
Priority: optional
Maintainer: Debian Security Tools <team+pkg-security@tracker.debian.org>
Uploaders: Samuel Henrique <samueloph@debian.org>
Build-Depends: debhelper (>= 11), libnfc-dev, pkg-config
Standards-Version: 4.1.5
Homepage: https://github.com/nfc-tools/mfoc
Vcs-Browser: https://salsa.debian.org/pkg-security-team/mfoc
Vcs-Git: https://salsa.debian.org/pkg-security-team/mfoc.git
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.

73
debian/copyright vendored Normal file
View file

@ -0,0 +1,73 @@
Format: http://dep.debian.net/deps/dep5
Upstream-Name: MFOC
Source: https://github.com/nfc-tools/mfoc
Files: *
Copyright: 2009 Norbert Szetei
2009 Pavol Luptak
2010 Micahal Boska
2010-2011 Romuald Conty <romuald@libnfc.org>
License: GPL-2+
Files: src/crypto1.c src/crapto1.c src/crapto1.h
Copyright: 2008-2009 bla <blapost@gmail.com>
License: GPL-2+
Files: src/slre.c src/slre.h
Copyright: 2013 Cesanta Software Limited
2004-2013 Sergey Lyubka <valenok@gmail.com>
License: GPL-2+
Files: src/nfc-utils.c src/mifare.c src/mifare.h src/nfc-utils.h
Copyright: 2010-2013 Philippe Teuwen
2009-2013 Romuald Conty <romuald@libnfc.org>
2009 Roel Verdult
2012-2013 Ludovic Rousseau <ludovic.rousseau@gmail.com>
2010-2012 Romain Tartière <romain.tartiere@gmail.com>
License: BSD-2-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
.
1) Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
.
2 )Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Files: debian/*
Copyright: 2011 Thomas Hood <jdthood@gmail.com>
2012-2014 Mati Aharoni <muts@kali.org>
2015 Sophie Brun <sophie@freexian.com
2018 Samuel Henrique <samueloph@debian.org>
License: GPL-2+
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

8
debian/rules vendored Executable file
View file

@ -0,0 +1,8 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@
override_dh_installchangelogs:
dh_installchangelogs ChangeLog

1
debian/source/format vendored Normal file
View file

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

3
debian/watch vendored Normal file
View file

@ -0,0 +1,3 @@
version=4
https://github.com/nfc-tools/mfoc/tags/ .*/mfoc-(.*)\.tar\.gz

View file

View file

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

View file

@ -20,68 +20,71 @@
#ifndef CRAPTO1_INCLUDED
#define CRAPTO1_INCLUDED
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct Crypto1State {uint32_t odd, even;};
struct Crypto1State* crypto1_create(uint64_t);
void crypto1_destroy(struct Crypto1State*);
void crypto1_get_lfsr(struct Crypto1State*, uint64_t*);
uint8_t crypto1_bit(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 prng_successor(uint32_t x, uint32_t n);
struct Crypto1State {uint32_t odd, even;};
struct Crypto1State *crypto1_create(uint64_t);
void crypto1_destroy(struct Crypto1State *);
void crypto1_get_lfsr(struct Crypto1State *, uint64_t *);
uint8_t crypto1_bit(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 prng_successor(uint32_t x, uint32_t n);
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in);
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);
int nonce_distance(uint32_t from, uint32_t to);
void lfsr_rollback(struct Crypto1State *s, uint32_t in, int fb);
uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb);
int nonce_distance(uint32_t from, uint32_t to);
bool validate_prng_nonce(uint32_t nonce);
#define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\
uint32_t __n = 0,__M = 0, N = 0;\
int __i;\
for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\
for(__i = FSIZE - 1; __i >= 0; __i--)\
if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\
break;\
else if(__i)\
__M = prng_successor(__M, (__i == 7) ? 48 : 8);\
else
uint32_t __n = 0,__M = 0, N = 0;\
int __i;\
for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\
for(__i = FSIZE - 1; __i >= 0; __i--)\
if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\
break;\
else if(__i)\
__M = prng_successor(__M, (__i == 7) ? 48 : 8);\
else
#define LF_POLY_ODD (0x29CE5C)
#define LF_POLY_EVEN (0x870804)
#define BIT(x, n) ((x) >> (n) & 1)
#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__
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
return BIT(0x6996, x & 0xf);
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
return BIT(0x6996, x & 0xf);
#else
asm( "movl %1, %%eax\n"
"mov %%ax, %%cx\n"
"shrl $0x10, %%eax\n"
"xor %%ax, %%cx\n"
"xor %%ch, %%cl\n"
"setpo %%al\n"
"movzx %%al, %0\n": "=r"(x) : "r"(x): "eax","ecx");
return x;
__asm__("movl %1, %%eax\n"
"mov %%ax, %%cx\n"
"shrl $0x10, %%eax\n"
"xor %%ax, %%cx\n"
"xor %%ch, %%cl\n"
"setpo %%al\n"
"movzx %%al, %0\n": "=r"(x) : "r"(x): "eax", "ecx");
return x;
#endif
}
static inline int filter(uint32_t const x)
{
uint32_t f;
}
static inline int filter(uint32_t const x)
{
uint32_t f;
f = 0xf22c0 >> (x & 0xf) & 16;
f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8;
f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4;
f |= 0x1e458 >> (x >> 12 & 0xf) & 2;
f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
return BIT(0xEC57E80A, f);
}
f = 0xf22c0 >> (x & 0xf) & 16;
f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8;
f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4;
f |= 0x1e458 >> (x >> 12 & 0xf) & 2;
f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
return BIT(0xEC57E80A, f);
}
#ifdef __cplusplus
}
#endif

View file

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

2062
src/mfoc.c

File diff suppressed because it is too large Load diff

View file

@ -2,10 +2,24 @@
#define TRY_KEYS 50
// Number of trailers == number of sectors
// 16x64b = 16
// Mifare Classic 1k 16x64b = 16
#define NR_TRAILERS_1k (16)
// 32x64b + 8*256b = 40
// Mifare Classic Mini
#define NR_TRAILERS_MINI (5)
// Mifare Classic 4k 32x64b + 8*256b = 40
#define NR_TRAILERS_4k (40)
// Mifare Classic 2k 32x64b
#define NR_TRAILERS_2k (32)
// Number of blocks
// Mifare Classic 1k
#define NR_BLOCKS_1k 0x3f
// Mifare Classic Mini
#define NR_BLOCKS_MINI 0x13
// Mifare Classic 4k
#define NR_BLOCKS_4k 0xff
// Mifare Classic 2k
#define NR_BLOCKS_2k 0x7f
#define MAX_FRAME_LEN 264
@ -16,7 +30,7 @@
#define DEFAULT_DIST_NR 15
// Default number of probes for a key recovery for one sector
#define DEFAULT_PROBES_NR 150
#define DEFAULT_PROBES_NR 1
// Number of sets with 32b keys
#define DEFAULT_SETS_NR 5
@ -24,63 +38,63 @@
#define odd_parity(i) (( (i) ^ (i)>>1 ^ (i)>>2 ^ (i)>>3 ^ (i)>>4 ^ (i)>>5 ^ (i)>>6 ^ (i)>>7 ^ 1) & 0x01)
typedef struct {
byte_t KeyA[6];
byte_t KeyB[6];
bool foundKeyA;
bool foundKeyB;
byte_t trailer; // Value of a trailer block
uint8_t KeyA[6];
uint8_t KeyB[6];
bool foundKeyA;
bool foundKeyB;
uint8_t trailer; // Value of a trailer block
} sector;
typedef struct {
u_int32_t *distances;
u_int32_t median;
u_int32_t num_distances;
u_int32_t tolerance;
byte_t parity[3]; // used for 3 bits of parity information
} denonce; // Revealed information about nonce
uint32_t *distances;
uint32_t median;
uint32_t num_distances;
uint32_t tolerance;
uint8_t parity[3]; // used for 3 bits of parity information
} denonce; // Revealed information about nonce
typedef struct {
nfc_target_t nt;
sector * sectors; // Allocate later, we do not know the number of sectors yet
sector e_sector; // Exploit sector
uint32_t num_sectors;
uint32_t num_blocks;
uint32_t uid;
bool b4K;
nfc_target nt;
sector *sectors; // Allocate later, we do not know the number of sectors yet
sector e_sector; // Exploit sector
uint8_t num_sectors;
uint8_t num_blocks;
uint32_t authuid;
} mftag;
typedef struct {
uint64_t *possibleKeys;
uint32_t size;
uint64_t *possibleKeys;
uint32_t size;
} pKeys;
typedef struct {
uint64_t *brokenKeys;
uint32_t size;
uint64_t *brokenKeys;
uint32_t size;
} bKeys;
typedef struct {
nfc_device_t *pdi;
nfc_device *pdi;
} mfreader;
typedef struct {
uint64_t key;
int count;
uint64_t key;
int count;
} countKeys;
void usage(FILE * stream, int errno);
void mf_init(mftag *t, mfreader *r);
void mf_configure(nfc_device_t* pdi);
void mf_select_tag(nfc_device_t* pdi, nfc_target_t* pnt);
void usage(FILE *stream, int errno);
void mf_init(mfreader *r);
void mf_configure(nfc_device *pdi);
void mf_select_tag(nfc_device *pdi, nfc_target *pnt);
int trailer_block(uint32_t block);
int find_exploit_sector(mftag t);
void mf_anticollision(mftag t, mfreader r);
bool get_rats_is_2k(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);
uint32_t median(denonce d);
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 compar_special_int(const void * a, const void * b);
countKeys * uniqsort(uint64_t *possibleKeys, uint32_t size);
void num_to_bytes(uint64_t n, uint32_t len, byte_t* dest);
long long unsigned int bytes_to_num(byte_t* src, uint32_t len);
int compar_int(const void *a, const void *b);
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);
countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size);
void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest);
long long unsigned int bytes_to_num(uint8_t *src, uint32_t len);

View file

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

View file

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

View file

@ -1,13 +1,18 @@
/*-
* Public platform independent Near Field Communication (NFC) library examples
*
* Copyright (C) 2009, Roel Verdult
* Copyright (C) 2010, Romuald Conty, Romain Tartière
*
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* 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
* modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
@ -23,97 +28,82 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @file nfc-utils.c
* @brief Provide some examples shared functions like print, parity calculation, options parsing.
*/
#include <nfc/nfc.h>
#include <err.h>
#include "nfc-utils.h"
static const byte_t OddParity[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
};
byte_t
oddparity (const byte_t bt)
uint8_t
oddparity(const uint8_t bt)
{
return OddParity[bt];
// cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
return (0x9669 >> ((bt ^(bt >> 4)) & 0xF)) & 1;
}
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;
// Calculate the parity bits for the command
for (szByteNr = 0; szByteNr < szLen; szByteNr++) {
pbtPar[szByteNr] = OddParity[pbtData[szByteNr]];
pbtPar[szByteNr] = oddparity(pbtData[szByteNr]);
}
}
void
print_hex (const byte_t * pbtData, const size_t szBytes)
print_hex(const uint8_t *pbtData, const size_t szBytes)
{
size_t szPos;
for (szPos = 0; szPos < szBytes; szPos++) {
printf ("%02x ", pbtData[szPos]);
printf("%02x ", pbtData[szPos]);
}
printf ("\n");
printf("\n");
}
void
print_hex_bits (const byte_t * pbtData, const size_t szBits)
print_hex_bits(const uint8_t *pbtData, const size_t szBits)
{
uint8_t uRemainder;
size_t szPos;
size_t szBytes = szBits / 8;
for (szPos = 0; szPos < szBytes; szPos++) {
printf ("%02x ", pbtData[szPos]);
printf("%02x ", pbtData[szPos]);
}
uRemainder = szBits % 8;
// Print the rest bits
if (uRemainder != 0) {
if (uRemainder < 5)
printf ("%01x (%d bits)", pbtData[szBytes], uRemainder);
printf("%01x (%d bits)", pbtData[szBytes], uRemainder);
else
printf ("%02x (%d bits)", pbtData[szBytes], uRemainder);
printf("%02x (%d bits)", pbtData[szBytes], uRemainder);
}
printf ("\n");
printf("\n");
}
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;
size_t szPos;
size_t szBytes = szBits / 8;
for (szPos = 0; szPos < szBytes; szPos++) {
printf ("%02x", pbtData[szPos]);
if (OddParity[pbtData[szPos]] != pbtDataPar[szPos]) {
printf ("! ");
printf("%02x", pbtData[szPos]);
if (oddparity(pbtData[szPos]) != pbtDataPar[szPos]) {
printf("! ");
} else {
printf (" ");
printf(" ");
}
}
@ -121,601 +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
if (uRemainder != 0) {
if (uRemainder < 5)
printf ("%01x (%d bits)", pbtData[szBytes], uRemainder);
printf("%01x (%d bits)", pbtData[szBytes], uRemainder);
else
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("%02x (%d bits)", pbtData[szBytes], uRemainder);
}
printf("\n");
}
void
print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose)
print_nfc_target(const nfc_target *pnt, bool verbose)
{
(void) verbose;
printf (" ID (NFCID2): ");
print_hex (nfi.abtId, 8);
printf (" Parameter (PAD): ");
print_hex (nfi.abtPad, 8);
char *s;
str_nfc_target(&s, pnt, verbose);
printf("%s", s);
nfc_free(s);
}
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,13 +1,18 @@
/*-
* Public platform independent Near Field Communication (NFC) library examples
*
* Copyright (C) 2009, Roel Verdult
* Copyright (C) 2010, Romuald Conty, Romain Tartière
*
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* 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
* modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
@ -23,7 +28,7 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
@ -79,21 +84,20 @@
# define ERR(...) warnx ("ERROR: " __VA_ARGS__ )
#endif
byte_t oddparity (const byte_t bt);
void oddparity_byte_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar);
#ifndef MIN
#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);
void print_hex_bits (const byte_t * pbtData, const size_t szBits);
void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar);
uint8_t oddparity(const uint8_t bt);
void oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar);
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose);
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, 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_hex(const uint8_t *pbtData, const size_t szLen);
void print_hex_bits(const uint8_t *pbtData, const size_t szBits);
void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar);
void print_nfc_target (const nfc_target_t nt, bool verbose);
nfc_device_desc_t *parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose);
void print_nfc_target(const nfc_target *pnt, bool verbose);
#endif

437
src/slre.c Normal file
View file

@ -0,0 +1,437 @@
/*
* Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
* Copyright (c) 2013 Cesanta Software Limited
* All rights reserved
*
* This library is dual-licensed: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see <http://www.gnu.org/licenses/>.
*
* You are free to use this library under the terms of the GNU General
* Public License, 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.
*
* Alternatively, you can license this library under a commercial
* license, as set out in <http://cesanta.com/products.html>.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "slre.h"
#define MAX_BRANCHES 100
#define MAX_BRACKETS 100
#define FAIL_IF(condition, error_code) if (condition) return (error_code)
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(ar) (sizeof(ar) / sizeof((ar)[0]))
#endif
#ifdef SLRE_DEBUG
# ifndef DBG
# define DBG(x) printf x
# endif
#else
# ifndef DBG
# define DBG(x)
# endif
#endif
struct bracket_pair {
const char *ptr; /* Points to the first char after '(' in regex */
int len; /* Length of the text between '(' and ')' */
int branches; /* Index in the branches array for this pair */
int num_branches; /* Number of '|' in this bracket pair */
};
struct branch {
int bracket_index; /* index for 'struct bracket_pair brackets' */
/* array defined below */
const char *schlong; /* points to the '|' character in the regex */
};
struct regex_info {
/*
* Describes all bracket pairs in the regular expression.
* First entry is always present, and grabs the whole regex.
*/
struct bracket_pair brackets[MAX_BRACKETS];
int num_brackets;
/*
* Describes alternations ('|' operators) in the regular expression.
* Each branch falls into a specific branch pair.
*/
struct branch branches[MAX_BRANCHES];
int num_branches;
/* Array of captures provided by the user */
struct slre_cap *caps;
int num_caps;
/* E.g. SLRE_IGNORE_CASE. See enum below */
int flags;
};
static int is_metacharacter(const unsigned char *s) {
static const char *metacharacters = "^$().[]*+?|\\Ssdbfnrtv";
return strchr(metacharacters, *s) != NULL;
}
static int op_len(const char *re) {
return re[0] == '\\' && re[1] == 'x' ? 4 : re[0] == '\\' ? 2 : 1;
}
static int set_len(const char *re, int re_len) {
int len = 0;
while (len < re_len && re[len] != ']') {
len += op_len(re + len);
}
return len <= re_len ? len + 1 : -1;
}
static int get_op_len(const char *re, int re_len) {
return re[0] == '[' ? set_len(re + 1, re_len - 1) + 1 : op_len(re);
}
static int is_quantifier(const char *re) {
return re[0] == '*' || re[0] == '+' || re[0] == '?';
}
static int toi(int x) {
return isdigit(x) ? x - '0' : x - 'W';
}
static int hextoi(const unsigned char *s) {
return (toi(tolower(s[0])) << 4) | toi(tolower(s[1]));
}
static int match_op(const unsigned char *re, const unsigned char *s,
struct regex_info *info) {
int result = 0;
switch (*re) {
case '\\':
/* Metacharacters */
switch (re[1]) {
case 'S': FAIL_IF(isspace(*s), SLRE_NO_MATCH); result++; break;
case 's': FAIL_IF(!isspace(*s), SLRE_NO_MATCH); result++; break;
case 'd': FAIL_IF(!isdigit(*s), SLRE_NO_MATCH); result++; break;
case 'b': FAIL_IF(*s != '\b', SLRE_NO_MATCH); result++; break;
case 'f': FAIL_IF(*s != '\f', SLRE_NO_MATCH); result++; break;
case 'n': FAIL_IF(*s != '\n', SLRE_NO_MATCH); result++; break;
case 'r': FAIL_IF(*s != '\r', SLRE_NO_MATCH); result++; break;
case 't': FAIL_IF(*s != '\t', SLRE_NO_MATCH); result++; break;
case 'v': FAIL_IF(*s != '\v', SLRE_NO_MATCH); result++; break;
case 'x':
/* Match byte, \xHH where HH is hexadecimal byte representaion */
FAIL_IF(hextoi(re + 2) != *s, SLRE_NO_MATCH);
result++;
break;
default:
/* Valid metacharacter check is done in bar() */
FAIL_IF(re[1] != s[0], SLRE_NO_MATCH);
result++;
break;
}
break;
case '|': FAIL_IF(1, SLRE_INTERNAL_ERROR); break;
case '$': FAIL_IF(1, SLRE_NO_MATCH); break;
case '.': result++; break;
default:
if (info->flags & SLRE_IGNORE_CASE) {
FAIL_IF(tolower(*re) != tolower(*s), SLRE_NO_MATCH);
} else {
FAIL_IF(*re != *s, SLRE_NO_MATCH);
}
result++;
break;
}
return result;
}
static int match_set(const char *re, int re_len, const char *s,
struct regex_info *info) {
int len = 0, result = -1, invert = re[0] == '^';
if (invert) re++, re_len--;
while (len <= re_len && re[len] != ']' && result <= 0) {
/* Support character range */
if (re[len] != '-' && re[len + 1] == '-' && re[len + 2] != ']' &&
re[len + 2] != '\0') {
result = info->flags && SLRE_IGNORE_CASE ?
*s >= re[len] && *s <= re[len + 2] :
tolower(*s) >= tolower(re[len]) && tolower(*s) <= tolower(re[len + 2]);
len += 3;
} else {
result = match_op((unsigned char *) re + len, (unsigned char *) s, info);
len += op_len(re + len);
}
}
return (!invert && result > 0) || (invert && result <= 0) ? 1 : -1;
}
static int doh(const char *s, int s_len, struct regex_info *info, int bi);
static int bar(const char *re, int re_len, const char *s, int s_len,
struct regex_info *info, int bi) {
/* i is offset in re, j is offset in s, bi is brackets index */
int i, j, n, step;
for (i = j = 0; i < re_len && j <= s_len; i += step) {
/* Handle quantifiers. Get the length of the chunk. */
step = re[i] == '(' ? info->brackets[bi + 1].len + 2 :
get_op_len(re + i, re_len - i);
DBG(("%s [%.*s] [%.*s] re_len=%d step=%d i=%d j=%d\n", __func__,
re_len - i, re + i, s_len - j, s + j, re_len, step, i, j));
FAIL_IF(is_quantifier(&re[i]), SLRE_UNEXPECTED_QUANTIFIER);
FAIL_IF(step <= 0, SLRE_INVALID_CHARACTER_SET);
if (i + step < re_len && is_quantifier(re + i + step)) {
DBG(("QUANTIFIER: [%.*s]%c [%.*s]\n", step, re + i,
re[i + step], s_len - j, s + j));
if (re[i + step] == '?') {
int result = bar(re + i, step, s + j, s_len - j, info, bi);
j += result > 0 ? result : 0;
i++;
} else if (re[i + step] == '+' || re[i + step] == '*') {
int j2 = j, nj = j, n1, n2 = -1, ni, non_greedy = 0;
/* Points to the regexp code after the quantifier */
ni = i + step + 1;
if (ni < re_len && re[ni] == '?') {
non_greedy = 1;
ni++;
}
do {
if ((n1 = bar(re + i, step, s + j2, s_len - j2, info, bi)) > 0) {
j2 += n1;
}
if (re[i + step] == '+' && n1 < 0) break;
if (ni >= re_len) {
/* After quantifier, there is nothing */
nj = j2;
} else if ((n2 = bar(re + ni, re_len - ni, s + j2,
s_len - j2, info, bi)) >= 0) {
/* Regex after quantifier matched */
nj = j2 + n2;
}
if (nj > j && non_greedy) break;
} while (n1 > 0);
if (n1 < 0 && re[i + step] == '*' &&
(n2 = bar(re + ni, re_len - ni, s + j, s_len - j, info, bi)) > 0) {
nj = j + n2;
}
DBG(("STAR/PLUS END: %d %d %d %d %d\n", j, nj, re_len - ni, n1, n2));
FAIL_IF(re[i + step] == '+' && nj == j, SLRE_NO_MATCH);
/* If while loop body above was not executed for the * quantifier, */
/* make sure the rest of the regex matches */
FAIL_IF(nj == j && ni < re_len && n2 < 0, SLRE_NO_MATCH);
/* Returning here cause we've matched the rest of RE already */
return nj;
}
continue;
}
if (re[i] == '[') {
n = match_set(re + i + 1, re_len - (i + 2), s + j, info);
DBG(("SET %.*s [%.*s] -> %d\n", step, re + i, s_len - j, s + j, n));
FAIL_IF(n <= 0, SLRE_NO_MATCH);
j += n;
} else if (re[i] == '(') {
n = SLRE_NO_MATCH;
bi++;
FAIL_IF(bi >= info->num_brackets, SLRE_INTERNAL_ERROR);
DBG(("CAPTURING [%.*s] [%.*s] [%s]\n",
step, re + i, s_len - j, s + j, re + i + step));
if (re_len - (i + step) <= 0) {
/* Nothing follows brackets */
n = doh(s + j, s_len - j, info, bi);
} else {
int j2;
for (j2 = 0; j2 <= s_len - j; j2++) {
if ((n = doh(s + j, s_len - (j + j2), info, bi)) >= 0 &&
bar(re + i + step, re_len - (i + step),
s + j + n, s_len - (j + n), info, bi) >= 0) break;
}
}
DBG(("CAPTURED [%.*s] [%.*s]:%d\n", step, re + i, s_len - j, s + j, n));
FAIL_IF(n < 0, n);
if (info->caps != NULL) {
info->caps[bi - 1].ptr = s + j;
info->caps[bi - 1].len = n;
}
j += n;
} else if (re[i] == '^') {
FAIL_IF(j != 0, SLRE_NO_MATCH);
} else if (re[i] == '$') {
FAIL_IF(j != s_len, SLRE_NO_MATCH);
} else {
FAIL_IF(j >= s_len, SLRE_NO_MATCH);
n = match_op((unsigned char *) (re + i), (unsigned char *) (s + j), info);
FAIL_IF(n <= 0, n);
j += n;
}
}
return j;
}
/* Process branch points */
static int doh(const char *s, int s_len, struct regex_info *info, int bi) {
const struct bracket_pair *b = &info->brackets[bi];
int i = 0, len, result;
const char *p;
do {
p = i == 0 ? b->ptr : info->branches[b->branches + i - 1].schlong + 1;
len = b->num_branches == 0 ? b->len :
i == b->num_branches ? (int) (b->ptr + b->len - p) :
(int) (info->branches[b->branches + i].schlong - p);
DBG(("%s %d %d [%.*s] [%.*s]\n", __func__, bi, i, len, p, s_len, s));
result = bar(p, len, s, s_len, info, bi);
DBG(("%s <- %d\n", __func__, result));
} while (result <= 0 && i++ < b->num_branches); /* At least 1 iteration */
return result;
}
static int baz(const char *s, int s_len, struct regex_info *info) {
int i, result = -1, is_anchored = info->brackets[0].ptr[0] == '^';
for (i = 0; i <= s_len; i++) {
result = doh(s + i, s_len - i, info, 0);
if (result >= 0) {
result += i;
break;
}
if (is_anchored) break;
}
return result;
}
static void setup_branch_points(struct regex_info *info) {
int i, j;
struct branch tmp;
/* First, sort branches. Must be stable, no qsort. Use bubble algo. */
for (i = 0; i < info->num_branches; i++) {
for (j = i + 1; j < info->num_branches; j++) {
if (info->branches[i].bracket_index > info->branches[j].bracket_index) {
tmp = info->branches[i];
info->branches[i] = info->branches[j];
info->branches[j] = tmp;
}
}
}
/*
* For each bracket, set their branch points. This way, for every bracket
* (i.e. every chunk of regex) we know all branch points before matching.
*/
for (i = j = 0; i < info->num_brackets; i++) {
info->brackets[i].num_branches = 0;
info->brackets[i].branches = j;
while (j < info->num_branches && info->branches[j].bracket_index == i) {
info->brackets[i].num_branches++;
j++;
}
}
}
static int foo(const char *re, int re_len, const char *s, int s_len,
struct regex_info *info) {
int i, step, depth = 0;
/* First bracket captures everything */
info->brackets[0].ptr = re;
info->brackets[0].len = re_len;
info->num_brackets = 1;
/* Make a single pass over regex string, memorize brackets and branches */
for (i = 0; i < re_len; i += step) {
step = get_op_len(re + i, re_len - i);
if (re[i] == '|') {
FAIL_IF(info->num_branches >= (int) ARRAY_SIZE(info->branches),
SLRE_TOO_MANY_BRANCHES);
info->branches[info->num_branches].bracket_index =
info->brackets[info->num_brackets - 1].len == -1 ?
info->num_brackets - 1 : depth;
info->branches[info->num_branches].schlong = &re[i];
info->num_branches++;
} else if (re[i] == '\\') {
FAIL_IF(i >= re_len - 1, SLRE_INVALID_METACHARACTER);
if (re[i + 1] == 'x') {
/* Hex digit specification must follow */
FAIL_IF(re[i + 1] == 'x' && i >= re_len - 3,
SLRE_INVALID_METACHARACTER);
FAIL_IF(re[i + 1] == 'x' && !(isxdigit(re[i + 2]) &&
isxdigit(re[i + 3])), SLRE_INVALID_METACHARACTER);
} else {
FAIL_IF(!is_metacharacter((unsigned char *) re + i + 1),
SLRE_INVALID_METACHARACTER);
}
} else if (re[i] == '(') {
FAIL_IF(info->num_brackets >= (int) ARRAY_SIZE(info->brackets),
SLRE_TOO_MANY_BRACKETS);
depth++; /* Order is important here. Depth increments first. */
info->brackets[info->num_brackets].ptr = re + i + 1;
info->brackets[info->num_brackets].len = -1;
info->num_brackets++;
FAIL_IF(info->num_caps > 0 && info->num_brackets - 1 > info->num_caps,
SLRE_CAPS_ARRAY_TOO_SMALL);
} else if (re[i] == ')') {
int ind = info->brackets[info->num_brackets - 1].len == -1 ?
info->num_brackets - 1 : depth;
info->brackets[ind].len = (int) (&re[i] - info->brackets[ind].ptr);
DBG(("SETTING BRACKET %d [%.*s]\n",
ind, info->brackets[ind].len, info->brackets[ind].ptr));
depth--;
FAIL_IF(depth < 0, SLRE_UNBALANCED_BRACKETS);
FAIL_IF(i > 0 && re[i - 1] == '(', SLRE_NO_MATCH);
}
}
FAIL_IF(depth != 0, SLRE_UNBALANCED_BRACKETS);
setup_branch_points(info);
return baz(s, s_len, info);
}
int slre_match(const char *regexp, const char *s, int s_len,
struct slre_cap *caps, int num_caps, int flags) {
struct regex_info info;
/* Initialize info structure */
info.flags = flags;
info.num_brackets = info.num_branches = 0;
info.num_caps = num_caps;
info.caps = caps;
DBG(("========================> [%s] [%.*s]\n", regexp, s_len, s));
return foo(regexp, (int) strlen(regexp), s, s_len, &info);
}

60
src/slre.h Normal file
View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
* Copyright (c) 2013 Cesanta Software Limited
* All rights reserved
*
* This library is dual-licensed: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see <http://www.gnu.org/licenses/>.
*
* You are free to use this library under the terms of the GNU General
* Public License, 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.
*
* Alternatively, you can license this library under a commercial
* license, as set out in <http://cesanta.com/products.html>.
*/
/*
* This is a regular expression library that implements a subset of Perl RE.
* Please refer to README.md for a detailed reference.
*/
#ifndef SLRE_HEADER_DEFINED
#define SLRE_HEADER_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
struct slre_cap {
const char *ptr;
int len;
};
int slre_match(const char *regexp, const char *buf, int buf_len,
struct slre_cap *caps, int num_caps, int flags);
/* Possible flags for slre_match() */
enum { SLRE_IGNORE_CASE = 1 };
/* slre_match() failure codes */
#define SLRE_NO_MATCH -1
#define SLRE_UNEXPECTED_QUANTIFIER -2
#define SLRE_UNBALANCED_BRACKETS -3
#define SLRE_INTERNAL_ERROR -4
#define SLRE_INVALID_CHARACTER_SET -5
#define SLRE_INVALID_METACHARACTER -6
#define SLRE_CAPS_ARRAY_TOO_SMALL -7
#define SLRE_TOO_MANY_BRANCHES -8
#define SLRE_TOO_MANY_BRACKETS -9
#ifdef __cplusplus
}
#endif
#endif /* SLRE_HEADER_DEFINED */