Compare commits

...

113 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
Romuald Conty 658d77ec0d prepare 0.10.2 release 2011-05-18 12:10:17 +00:00
Romuald Conty a13df02f79 improve tests made before running and show tag info using print_nfc_iso14443a_info() 2011-05-18 09:18:29 +00:00
Romuald Conty 001049599f try to disconnect() the device on error. 2011-04-08 15:19:39 +00:00
Romuald Conty a978ac16a9 show errors then exit on mf_configure() 2011-04-08 10:05:49 +00:00
Romuald Conty 1c2ff2b263 apply a patch suggested by Valentijn Sessink. See Issue 56. 2011-04-08 09:32:56 +00:00
Romuald Conty d1c676b01d minors fixes and indent. 2011-04-08 09:17:10 +00:00
Romuald Conty 9e636c9885 show error (using nfc_perror) then exit if some nfc_* functions failed on init. 2011-04-08 08:54:55 +00:00
Romuald Conty ef75599d75 minor debug improvements. 2011-04-08 08:35:55 +00:00
Romuald Conty e076683dea minor fixes/enhancements and version bumping 2011-04-04 12:28:11 +00:00
Romuald Conty 4d1ce73772 hide authentication errors 2011-04-04 10:38:30 +00:00
Romuald Conty dafa6e42db sync nfc-utils.h/c and mifare.c/h with libnfc's ones. 2011-04-04 10:01:33 +00:00
Romain Tartiere c973c3cd81 mfox: Unbreak autotools on FreeBSD. 2011-02-21 16:26:48 +00:00
Romuald Conty 6a3977545e use strtoll() function in order to retrieve 64bits wide value. (Fixes Issue 55) 2011-02-02 10:46:16 +00:00
Romuald Conty af8ec581be bump package version 2010-11-18 11:20:55 +00:00
Romuald Conty d4eb0e3eba sync nfc-utils.* from libnfc 2010-11-18 11:18:21 +00:00
Romuald Conty 0320ded902 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-11-02 09:36:39 +00:00
29 changed files with 2994 additions and 1493 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

243
ChangeLog
View file

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

View file

@ -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.09], [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.3.9
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])
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,7 +1,10 @@
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
mfoc_LDADD = @LIBNFC_LIBS@
# 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.

1995
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_info_t ti;
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_info_t* ti);
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,3 +1,50 @@
/*-
* Public platform independent Near Field Communication (NFC) library examples
*
* 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.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @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>
@ -5,82 +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 szRxLen;
uint8_t abtRx[265];
size_t szParamLen;
byte_t abtCmd[265];
// Make sure we are dealing with a active device
if (!pnd->bActive)
return false;
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);
// Fire the mifare command
if (!nfc_initiator_transceive_bytes (pnd, abtCmd, 2 + szParamLen, abtRx, &szRxLen)) {
if (pnd->iLastError != 0x14)
nfc_perror (pnd, "nfc_initiator_transceive_bytes");
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 ((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 (szRxLen == 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,33 +1,46 @@
/**
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, Roel Verdult, 2010, Romuald Conty
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
/*-
* Public platform independent Near Field Communication (NFC) library examples
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*
* @file mifaretag.h
* 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.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @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,
@ -41,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 {
@ -99,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,88 +1,109 @@
/*-
* 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.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @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(" ");
}
}
@ -90,102 +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_ISO14443_4_COMPLIANT 0x20
#define SAK_ISO18092_COMPLIANT 0x40
void
print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai)
{
printf (" ATQA (SENS_RES): ");
print_hex (nai.abtAtqa, 2);
printf (" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
print_hex (nai.abtUid, nai.szUidLen);
printf (" SAK (SEL_RES): ");
print_hex (&nai.btSak, 1);
if (nai.szAtsLen) {
printf (" ATS (ATR): ");
print_hex (nai.abtAts, nai.szAtsLen);
}
if ((nai.btSak & SAK_ISO14443_4_COMPLIANT) || (nai.btSak & SAK_ISO18092_COMPLIANT)) {
printf (" Compliant with: ");
if (nai.btSak & SAK_ISO14443_4_COMPLIANT)
printf ("ISO/IEC 14443-4 ");
if (nai.btSak & SAK_ISO18092_COMPLIANT)
printf ("ISO/IEC 18092");
printf ("\n");
printf("%02x (%d bits)", pbtData[szBytes], uRemainder);
}
printf("\n");
}
void
print_nfc_felica_info (const nfc_felica_info_t nfi)
print_nfc_target(const nfc_target *pnt, bool verbose)
{
printf (" ID (NFCID2): ");
print_hex (nfi.abtId, 8);
printf (" Parameter (PAD): ");
print_hex (nfi.abtPad, 8);
}
void
print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi)
{
printf (" ATQB: ");
print_hex (nbi.abtAtqb, 12);
printf (" ID: ");
print_hex (nbi.abtId, 4);
printf (" CID: %02x\n", nbi.btCid);
if (nbi.szInfLen > 0) {
printf (" INF: ");
print_hex (nbi.abtInf, nbi.szInfLen);
}
printf (" PARAMS: %02x %02x %02x %02x\n", nbi.btParam1, nbi.btParam2, nbi.btParam3, nbi.btParam4);
}
/**
* @brief Tries to parse arguments to find device descriptions.
* @return Returns the list of found device descriptions.
*/
nfc_device_desc_t *
parse_device_desc (int argc, const char *argv[], size_t * szFound)
{
nfc_device_desc_t *pndd = 0;
int arg;
*szFound = 0;
// Get commandline options
for (arg = 1; arg < argc; arg++) {
if (0 == strcmp (argv[arg], "--device")) {
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;
}
break;
}
}
return pndd;
char *s;
str_nfc_target(&s, pnt, verbose);
printf("%s", s);
nfc_free(s);
}

View file

@ -1,22 +1,39 @@
/**
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2010, Romuald Conty
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
/*-
* Free/Libre Near Field Communication (NFC) library
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*
* 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.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @file nfc-utils.h
* @brief Provide some examples shared functions like print, parity calculation, options parsing.
*/
@ -26,18 +43,61 @@
# include <stdlib.h>
# include <string.h>
# include <err.h>
byte_t oddparity (const byte_t bt);
void oddparity_byte_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar);
/**
* @macro DBG
* @brief Print a message of standard output only in DEBUG mode
*/
#ifdef DEBUG
# define DBG(...) do { \
warnx ("DBG %s:%d", __FILE__, __LINE__); \
warnx (" " __VA_ARGS__ ); \
} while (0)
#else
# define DBG(...) {}
#endif
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);
/**
* @macro WARN
* @brief Print a warn message
*/
#ifdef DEBUG
# define WARN(...) do { \
warnx ("WARNING %s:%d", __FILE__, __LINE__); \
warnx (" " __VA_ARGS__ ); \
} while (0)
#else
# define WARN(...) warnx ("WARNING: " __VA_ARGS__ )
#endif
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai);
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi);
void print_nfc_felica_info (const nfc_felica_info_t nfi);
/**
* @macro ERR
* @brief Print a error message
*/
#ifdef DEBUG
# define ERR(...) do { \
warnx ("ERROR %s:%d", __FILE__, __LINE__); \
warnx (" " __VA_ARGS__ ); \
} while (0)
#else
# define ERR(...) warnx ("ERROR: " __VA_ARGS__ )
#endif
nfc_device_desc_t *parse_device_desc (int argc, const char *argv[], size_t * szFound);
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
uint8_t oddparity(const uint8_t bt);
void oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar);
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 *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 */