├── .gitignore ├── .travis-ci-build ├── .travis.yml ├── AUTHORS ├── CMakeLists.txt ├── COPYING ├── ChangeLog ├── HACKING.md ├── Makefile.am ├── NEWS ├── README.md ├── TODO ├── Updating.md ├── cmake ├── config_posix.h.cmake ├── config_windows.h.cmake └── modules │ └── FindLIBNFC.cmake ├── configure.ac ├── contrib ├── Makefile.am ├── libfreefare_zsnippets.vim ├── libutil │ ├── Makefile.am │ ├── hexdump.c │ └── libutil.h └── win32 │ └── err.h ├── debian ├── .gitignore ├── README.Debian ├── README.source ├── changelog ├── compat ├── control ├── copyright ├── libfreefare-bin.install ├── libfreefare-dev.install ├── libfreefare-doc.install ├── libfreefare0.install ├── rules ├── source │ └── format └── watch ├── examples ├── CMakeLists.txt ├── Makefile.am ├── felica-lite-dump.c ├── felica-read-ndef.c ├── mifare-classic-format.c ├── mifare-classic-read-ndef.c ├── mifare-classic-write-ndef.c ├── mifare-desfire-access.c ├── mifare-desfire-create-ndef.c ├── mifare-desfire-ev1-configure-ats.c ├── mifare-desfire-ev1-configure-default-key.c ├── mifare-desfire-ev1-configure-random-uid.c ├── mifare-desfire-format.c ├── mifare-desfire-info.c ├── mifare-desfire-read-ndef.c ├── mifare-desfire-write-ndef.c ├── mifare-ultralight-info.c ├── mifare-ultralightc-diversify.c ├── ntag-detect.c ├── ntag-removeauth.c ├── ntag-setauth.c └── ntag-write.c ├── libfreefare.pc.in ├── libfreefare ├── CMakeLists.txt ├── Makefile.am ├── felica.c ├── freefare.3 ├── freefare.c ├── freefare.h ├── freefare_error.3 ├── freefare_internal.h ├── mad.3 ├── mad.c ├── mifare_application.3 ├── mifare_application.c ├── mifare_classic.3 ├── mifare_classic.c ├── mifare_desfire.3 ├── mifare_desfire.c ├── mifare_desfire_aid.3 ├── mifare_desfire_aid.c ├── mifare_desfire_crypto.c ├── mifare_desfire_error.c ├── mifare_desfire_key.3 ├── mifare_desfire_key.c ├── mifare_key_deriver.3 ├── mifare_key_deriver.c ├── mifare_ultralight.3 ├── mifare_ultralight.c ├── ntag21x.3 ├── ntag21x.c ├── ntag21x_error.c ├── tlv.3 └── tlv.c ├── m4 └── .gitignore └── test ├── Makefile.am ├── common ├── Makefile.am ├── mifare_desfire_auto_authenticate.c └── mifare_desfire_auto_authenticate.h ├── felica_fixture.c ├── fixture.h ├── mifare_classic_fixture.c ├── mifare_desfire_ev1_fixture.c ├── mifare_desfire_fixture.c ├── mifare_ultralight_fixture.c ├── run-test.sh ├── test_felica.c ├── test_freefare.c ├── test_mad.c ├── test_mifare_application.c ├── test_mifare_classic.c ├── test_mifare_classic_create_trailer_block.c ├── test_mifare_classic_mad.c ├── test_mifare_classic_sector_boundaries.c ├── test_mifare_desfire.c ├── test_mifare_desfire_aes.c ├── test_mifare_desfire_aid.c ├── test_mifare_desfire_des.c ├── test_mifare_desfire_ev1.c ├── test_mifare_desfire_ev1_3des.c ├── test_mifare_desfire_ev1_3k3des.c ├── test_mifare_desfire_ev1_aes.c ├── test_mifare_desfire_ev1_iso.c ├── test_mifare_desfire_key.c ├── test_mifare_key_deriver_an10922.c ├── test_mifare_ultralight.c └── test_tlv.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.la 3 | *.lo 4 | *.Plo 5 | *.pc 6 | */.deps/ 7 | **/.libs/ 8 | autom4te.cache/ 9 | Makefile 10 | Makefile.in 11 | INSTALL 12 | aclocal.m4 13 | ar-lib 14 | compile 15 | config.* 16 | configure 17 | depcomp 18 | install-sh 19 | libtool 20 | ltmain.sh 21 | missing 22 | stamp-h1 23 | test-driver 24 | examples/felica-lite-dump 25 | examples/felica-read-ndef 26 | examples/mifare-classic-format 27 | examples/mifare-classic-read-ndef 28 | examples/mifare-classic-write-ndef 29 | examples/mifare-desfire-access 30 | examples/mifare-desfire-create-ndef 31 | examples/mifare-desfire-ev1-configure-ats 32 | examples/mifare-desfire-ev1-configure-default-key 33 | examples/mifare-desfire-ev1-configure-random-uid 34 | examples/mifare-desfire-format 35 | examples/mifare-desfire-info 36 | examples/mifare-desfire-read-ndef 37 | examples/mifare-desfire-write-ndef 38 | examples/mifare-ultralight-info 39 | examples/ntag-detect 40 | examples/ntag-removeauth 41 | examples/ntag-setauth 42 | examples/ntag-write 43 | test/test-suite.log 44 | test/run-test.sh.log 45 | test/run-test.sh.trs 46 | -------------------------------------------------------------------------------- /.travis-ci-build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd $1 3 | 4 | if [ "$BLD" = autotools ]; then 5 | set -ex 6 | autoreconf -vis 7 | mkdir build-autotools 8 | cd build-autotools 9 | ../configure --prefix=$HOME/.local LIBNFC_CFLAGS="-I$HOME/.local/include" LIBNFC_LIBS="-L$HOME/.local/lib -lnfc" 10 | make 11 | make install 12 | elif [ "$BLD" = cmake ]; then 13 | set -ex 14 | mkdir build-cmake 15 | cd build-cmake 16 | cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .. 17 | make 18 | make install 19 | else 20 | echo "Unsupported build system: '$BLD'" >&2 21 | exit 1 22 | fi 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | compiler: 4 | - clang 5 | - gcc 6 | 7 | env: 8 | - BLD=cmake 9 | - BLD=autotools 10 | 11 | addons: 12 | apt: 13 | sources: 14 | - sourceline: 'ppa:cutter-testing-framework/ppa' 15 | packages: 16 | - libusb-dev 17 | - cmake 18 | - cutter-testing-framework 19 | 20 | install: 21 | - git clone https://github.com/nfc-tools/libnfc 22 | - ./.travis-ci-build libnfc 23 | script: 24 | - ./.travis-ci-build . 25 | - if [ "$BLD" = autotools ]; then (cd build-autotools && make check TESTS_ENVIRONMENT=SKIP_TESTS=1 && cutter test); fi 26 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | romuald@libnfc.org:Romuald Conty 2 | romain.tartiere:Romain Tartière 3 | rtartiere@il4p.fr:Romain Tartière 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(libfreefare C) 2 | cmake_minimum_required(VERSION 2.6) 3 | 4 | SET(VERSION_MAJOR "0") 5 | SET(VERSION_MINOR "4") 6 | SET(VERSION_PATCH "0") 7 | 8 | SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") 9 | 10 | SET(PACKAGE_NAME "libnfc") 11 | SET(PACKAGE_VERSION ${VERSION}) 12 | SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") 13 | 14 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") 15 | 16 | add_definitions("-std=c99") 17 | 18 | find_package(LIBNFC REQUIRED) 19 | find_package(OpenSSL REQUIRED) 20 | 21 | IF(WIN32) 22 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) 23 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32) 24 | find_library(WINSOCK_LIB libws2_32.a) 25 | set(LIBS ${LIBS} ${WINSOCK_LIB}) 26 | ELSE(WIN32) 27 | include(CheckIncludeFiles) 28 | check_include_files("sys/endian.h" HAVE_SYS_ENDIAN_H) 29 | check_include_files("endian.h" HAVE_ENDIAN_H) 30 | check_include_files("byteswap.h" HAVE_BYTESWAP_H) 31 | check_include_files("CoreFoundation/CoreFoundation.h" HAVE_COREFOUNDATION_COREFOUNDATION_H) 32 | set(_XOPEN_SOURCE 600) 33 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) 34 | ENDIF(WIN32) 35 | 36 | include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/) 37 | add_definitions("-DHAVE_CONFIG_H") 38 | 39 | if(MINGW AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") 40 | # force MinGW-w64 in 32bit mode 41 | add_definitions("-m32") 42 | add_definitions("-DNOCRYPT") 43 | set(CMAKE_SHARED_LINKER_FLAGS -m32) 44 | set(CMAKE_EXE_LINKER_FLAGS -m32) 45 | endif(MINGW) 46 | 47 | message("CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS}) 48 | message("CMAKE_SHARED_LINKER_FLAGS: " ${CMAKE_SHARED_LINKER_FLAGS}) 49 | 50 | include_directories(${LIBNFC_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/contrib/libutil) 51 | set(LIBS ${LIBS} ${LIBNFC_LIBRARIES} ${OPENSSL_LIBRARIES}) 52 | 53 | option(WITH_DEBUG "Extra debug information is outputted when this is turned on" OFF) 54 | 55 | if(DEFINED CMAKE_INSTALL_LIBDIR) 56 | set(libdir ${CMAKE_INSTALL_LIBDIR}) 57 | else(DEFINED CMAKE_INSTALL_LIBDIR) 58 | set(CMAKE_INSTALL_LIBDIR lib) 59 | set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) 60 | endif(DEFINED CMAKE_INSTALL_LIBDIR) 61 | 62 | if(DEFINED INCLUDE_INSTALL_DIR) 63 | set(includedir ${INCLUDE_INSTALL_DIR}) 64 | else(DEFINED INCLUDE_INSTALL_DIR) 65 | set(INCLUDE_INSTALL_DIR include) 66 | set(includedir ${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}) 67 | endif(DEFINED INCLUDE_INSTALL_DIR) 68 | 69 | if(NOT DEFINED SHARE_INSTALL_PREFIX) 70 | set(SHARE_INSTALL_PREFIX share) 71 | endif(NOT DEFINED SHARE_INSTALL_PREFIX) 72 | 73 | add_subdirectory(libfreefare) 74 | add_subdirectory(examples) 75 | -------------------------------------------------------------------------------- /HACKING.md: -------------------------------------------------------------------------------- 1 | Hello hackers! 2 | 3 | # General remarks about contributing 4 | 5 | Contributions to the libfreefare are welcome! Here are some directions to get 6 | you started: 7 | 8 | ## Install Cutter 9 | 10 | [Cutter](http://cutter.sourceforge.net/) is a cool unit test framework for C 11 | code. You will need it to run the regression tests suite (`make check`) and 12 | ensure that your code does not break other features. 13 | 14 | To cover all tests you'll need several blank cards: 15 | 16 | * MIFARE Classic 4k with default keys (`FFFFFFFFFF`) 17 | * MIFARE DESFire EV1 4k with default PICC key (`0000000000000000`) 18 | * MIFARE Ultralight 19 | * MIFARE Ultralight C with default key (`BREAKMEIFYOUCAN!`) 20 | 21 | After "make check", you can run sub-sets of tests directly with cutter: 22 | 23 | ~~~ 24 | $ cutter -n /ultralight/ test 25 | $ cutter -n /classic/ test 26 | $ cutter -n /desfire/ test 27 | ~~~ 28 | 29 | ## Follow style conventions 30 | 31 | The source code of the library trend to follow some conventions so that it is 32 | consistent in style and thus easier to read. Basically, it follows [FreeBSD's 33 | style(9)](http://www.freebsd.org/cgi/man.cgi?query=style); adding 4-space 34 | indentation and 8-space tabs (which you should configure in your editor, e.g. 35 | `:set sw=4 ts=8` in vim). You are also advised to `:set cinoptions=t0(0:0` so 36 | that you don't have to care about indentation anymore. For more details, please 37 | read the [style(9) man page from FreeBSD's 38 | website](http://www.freebsd.org/cgi/man.cgi?query=style). 39 | 40 | For style correction install package `astyle`. Then run `make style`. 41 | 42 | ## Write tests 43 | 44 | I already told you cutter is lovely, so you really should use it! If you want 45 | to contribute code, write test: only code with appropriate tests will be 46 | considered. And remember that 47 | [TDD](http://en.wikipedia.org/wiki/Test-driven_development) (Test Driven 48 | Development) is cool and writing all tests at the end deeply depressing, so 49 | test early, test often! 50 | 51 | # Adding support for a new type of card 52 | 53 | Adding a new supported card to the libfreefare requires a few modification in 54 | multiple places. Here is a list of the things to do in order to have the 55 | infrastructure ready for hacking the new card support: 56 | 57 | - Edit `libfreefare/freefare.h`: 58 | - Add your tag to the `freefare_tag_type` enum; 59 | - Add a `_connect()` and a `_disconnect()` function prototype; 60 | - Edit `libfreefare/freefare.3`: 61 | - Add your tag to the `freefare_tag_type' enum documentation; 62 | - Edit `libfreefare/freefare_internal.h`: 63 | - Add a new `_tag struct`. It's very first member SHALL be `struct 64 | freefare_tag __tag`; 65 | - Add a `_tag_new()` and a `_tag_free()` function prototype; 66 | - Add a `ASSERT_()` macro to check the tag's type; 67 | - Add a `()` macro to cast a generic tag to your type. 68 | - Edit `libfreefare/freefare.c`: 69 | - Add your tag type to the supported_tags array; 70 | - Edit the `freefare_get_tags()` function so that it calls `_tag_new()` 71 | when it finds your tag; 72 | - Edit the `freefare_free_tags()` function so that it calls 73 | `_tag_free()` to free your tags; 74 | - Create `libfreefare/.c` and implement all that's missing: 75 | - `_tag_new()` MUST allocate all data-structure the tag may need to 76 | use during it's lifetime. We do not want to have any function to fail 77 | later because the running system is out of resources. Buffers for 78 | cryptographic operations on random amount of data MAY however be 79 | (re)allocated on demand, in such case refrain from shrinking 80 | unnecessarily the buffer size. 81 | - `_connect()` SHOULD initialise data allocated by `_tag_new()`. 82 | Keep in mind that a single tag may be disconnected from and connected 83 | to again, without being freed in the meantime. Since all memory 84 | allocations are done in `_tag_new()`, your code SHOULD only care 85 | about initialising these data structures; 86 | - `_disconnect()` MAY do more that just send a disconnect command to 87 | the tag. At time of writing I have no idea what it could be but who 88 | knows... 89 | - `_tag_free()` SHALL free all resources allocated for the tag 90 | (surprising, isn't it?) 91 | 92 | # Various guidelines 93 | 94 | - If a given card has different cryptographic modes, you SHOULD use 95 | switch/cases to handle specific branches of code, even when applicable to 96 | only one cypher. The idea is that if you don't provide support for all 97 | cryptographic schemes, or if an evolution of the card provides more 98 | cryptographic possibilities, when adding support for a new cypher, the 99 | compiler can warn the developer about unhandled values in switch 100 | statements. Please refer to the MIFARE DESFire code for an example. 101 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | libfreefare_subdirs = libfreefare test examples 4 | 5 | SUBDIRS = contrib $(libfreefare_subdirs) 6 | 7 | pkgconfigdir = $(libdir)/pkgconfig 8 | pkgconfig_DATA = libfreefare.pc 9 | 10 | dist-hook: 11 | @if ! grep -qi "$$(LC_ALL=C date +'%d %b %Y')" NEWS; then \ 12 | printf "\033[31;1mBEWARE! The first line from the NEWS file does not contain the current date!\033[0m\n"; \ 13 | sleep 3; \ 14 | fi 15 | @if test -d "$(srcdir)/.svn"; then \ 16 | echo "Creating ChangeLog..." && \ 17 | ( cd "$(top_srcdir)" && \ 18 | echo '# Generated by Makefile. Do not edit.'; echo; \ 19 | $(top_srcdir)/missing --run svn2cl --authors=AUTHORS --strip-prefix=/trunk/libfreefare --stdout ) > ChangeLog.tmp \ 20 | && mv -f ChangeLog.tmp $(top_distdir)/ChangeLog \ 21 | || ( rm -f ChangeLog.tmp ; \ 22 | echo "Failed to generate ChangeLog" >&2 ); \ 23 | else \ 24 | echo "A svn checkout is required to generate a ChangeLog" >&2; \ 25 | fi 26 | 27 | EXTRA_DIST = HACKING 28 | CLEANFILES = coverage.info 29 | clean-local: clean-local-coverage 30 | .PHONY: clean-local-coverage 31 | clean-local-coverage: 32 | -rm -rf coverage 33 | 34 | SVN_KEYWORDS_FILES_LIST_CMD = find $(top_srcdir) -name '*.[hc]' -a ! -name config.h \ 35 | -o -name Makefile.am -o -name '*.cmake' -o -name 'CMakeLists.txt' 36 | svn-keywords: 37 | @echo Update files svn:keywords... 38 | @$(SVN_KEYWORDS_FILES_LIST_CMD) | xargs svn propset -q svn:keywords Id 39 | $(MAKE) svn-keywords-check 40 | 41 | svn-keywords-check: 42 | @echo "Files missing a '$$"Id"$$' vcs keyword:" 43 | @$(SVN_KEYWORDS_FILES_LIST_CMD) | xargs grep -L '\$$Id[^$$]*\$$' 44 | 45 | style: 46 | find ${libfreefare_subdirs} -name '*.[ch]' -exec perl -pi -e 's/[ \t]+$$//' {} \; 47 | find ${libfreefare_subdirs} -name '*.[ch]' -print0 | xargs -0 astyle --style=linux --indent=force-tab-x --lineend=linux --indent-preproc-define --indent-preproc-block 48 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Changes between 0.3.4 and 0.3.5 [20 jan 2013] 2 | 3 | *) Depends on libnfc 1.7.0 4 | 5 | Changes between 0.3.3 and 0.3.4 [1 mar 2012] 6 | 7 | *) Fix Mifare Ultralight C card detection routine 8 | 9 | Changes between 0.3.2 and 0.3.3 [1 mar 2012] 10 | 11 | *) Depends on libnfc 1.6.0 12 | 13 | Changes between 0.3.1 and 0.3.2 [17 oct 2011] 14 | 15 | *) New API functions to ease up creation of applications with strong 16 | cryptography on Mifare DESFire EV1: 17 | mifare_desfire_create_application_3k3des(), 18 | mifare_desfire_create_application_aes(). 19 | *) New API functions for ISO 7616 support om Mifare DESFire EV1: 20 | mifare_desfire_create_application_iso(), 21 | mifare_desfire_create_application_3k3des_iso(), 22 | mifare_desfire_create_application_aes_iso(), 23 | mifare_desfire_get_df_names(), 24 | mifare_desfire_get_iso_file_ids(), 25 | mifare_desfire_create_std_data_file_iso(), 26 | mifare_desfire_create_backup_data_file_iso(), 27 | mifare_desfire_create_linear_record_file_iso(), 28 | mifare_desfire_create_cyclic_record_file_iso(). 29 | *) New public API function freefare_tag_new(); 30 | *) Microsoft Windows support. 31 | 32 | Changes between 0.3.0 and 0.3.1 [23 feb 2011] 33 | 34 | *) Fix mifare_classic_transfer() for devices returning a 1 byte response on 35 | success. 36 | *) New API function mifare_desfire_last_pcd_error(). 37 | 38 | Changes between 0.2.3 and 0.3.0 [23 dec 2010] 39 | 40 | *) Add support for ISO and AES authentication through 41 | mifare_desfire_authenticate_iso() and mifare_desfire_authenticate_aes(). 42 | *) Add support for 3K3DES and AES cryptographic operations and add new 43 | functions mifare_desfire_3k3des_key_new(), 44 | mifare_desfire_3k3des_key_new_with_version(), mifare_desfire_aes_key_new() 45 | and mifare_desfire_aes_key_new_with_version() for generating keys. 46 | *) New functions mifare_desfire_free_mem(), 47 | mifare_desfire_set_configuration(), mifare_desfire_set_default_key(), 48 | mifare_desfire_set_ats(), mifare_desfire_get_card_uid(), for Mifare 49 | DESFire EV1 targets manipulation. 50 | *) Deprecate authentication information when deleting the currently selected 51 | application 52 | 53 | Changes between 0.2.2 and 0.2.3 [23 dec 2010] 54 | 55 | *) Fix a buffer overflow in mifare_desfire_get_file_settings(). 56 | 57 | Changes between 0.2.1 and 0.2.2 [23 nov 2010] 58 | 59 | *) Fix build when cutter is not available or is disabled. 60 | 61 | Changes between 0.2.0 and 0.2.1 [23 nov 2010] 62 | 63 | *) The mifare_desfire_error_lookup() and mifare_desfire_get_last_error() 64 | functions were removed and replaced by the freefare_strerror(), 65 | freefare_strerror_r() and freefare_perror() functions. 66 | *) The library reports errors other that the ones returned by the PICC. 67 | *) The MDAD_KEYx macro where renamed MDAR_KEYx for consistency. 68 | *) The MDCM_MACING macro was renamed MDCM_MACED. 69 | *) The MDCM_FULLDES macro was renamed MDCM_ENCIPHERED. 70 | *) New function mifare_desfire_last_picc_error(). 71 | *) New function mifare_desfire_aid_get_aid(). 72 | 73 | Changes between 0.1.0 and 0.2.0 [07 sep 2010] 74 | 75 | *) New function freefare_free_tag() to free individual tags from a MifareTag 76 | list. 77 | *) The mifare_application_alloc() size parameter is now expressed in bytes 78 | and not in sectors. 79 | *) New API function mad_sector_reserved(). 80 | *) The mifare_classic_format_sector() functions now require a sector number 81 | instead of a block number. 82 | *) New API functions mifare_classic_block_sector(), 83 | mifare_classic_sector_first_block(), mifare_classic_sector_block_count() 84 | and mifare_classic_sector_last_block(). 85 | *) New API functions mifare_application_read(), mifare_application_write(). 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | [![Build Status](https://travis-ci.org/nfc-tools/libfreefare.svg?branch=master)](https://travis-ci.org/nfc-tools/libfreefare) 4 | [![Join the chat at https://gitter.im/nfc-tools/libfreefare](https://badges.gitter.im/nfc-tools/libfreefare.svg)](https://gitter.im/nfc-tools/libfreefare?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | The _libfreefare_ project provides a convenient API for MIFARE card manipulations. 7 | 8 | It is part of the _nfc-tools_, you can find more info on them on the [nfc-tools wiki](http://nfc-tools.org/). 9 | 10 | If you are new to _libfreefare_ or the _nfc-tools_, you should collect useful information on the [project website](http://nfc-tools.org/) and the [dedicated forums](http://www.libnfc.org/community). 11 | 12 | # Feature matrix 13 | ## Tags 14 | | Tag | Status | 15 | |:--------------------|:--------------| 16 | | FeliCa Lite | Supported | 17 | | MIFARE Classic 1k | Supported | 18 | | MIFARE Classic 4k | Supported | 19 | | MIFARE DESFire 2k | Supported | 20 | | MIFARE DESFire 4k | Supported | 21 | | MIFARE DESFire 8k | Supported | 22 | | MIFARE DESFire EV1 | Supported | 23 | | MIFARE Mini | Supported | 24 | | MIFARE Plus S 2k | Not supported | 25 | | MIFARE Plus S 4k | Not supported | 26 | | MIFARE Plus X 2k | Not supported | 27 | | MIFARE Plus X 4k | Not supported | 28 | | MIFARE Ultralight | Supported | 29 | | MIFARE Ultralight C | Supported | 30 | | NTAG21x | Supported | 31 | 32 | ## Specifications 33 | | Specification | Status | 34 | |:--------------------------------------|:----------| 35 | | Mifare Application Directory (MAD) v1 | Supported | 36 | | Mifare Application Directory (MAD) v2 | Supported | 37 | | Mifare Application Directory (MAD) v3 | Supported (part of Mifare DESFire support) | 38 | 39 | # Installation 40 | 41 | ## For *NIX systems 42 | 43 | You can use released version (see **Download** section) or development version: 44 | 45 | First, ensure all dependencies are installed: 46 | * [libnfc](https://github.com/nfc-tools/libnfc); 47 | * git; 48 | * Autotools (autoconf, automake, libtool); 49 | * OpenSSL development package. 50 | ``` 51 | apt-get install autoconf automake git libtool libssl-dev pkg-config 52 | ``` 53 | 54 | Clone this repository: 55 | ``` 56 | git clone https://github.com/nfc-tools/libfreefare.git 57 | cd libfreefare 58 | ``` 59 | 60 | Before compiling, remember to run: 61 | ``` 62 | autoreconf -vis 63 | ``` 64 | 65 | You can now compile **libfreefare** the usual autotools way: 66 | ``` 67 | ./configure --prefix=/usr 68 | make 69 | sudo make install 70 | ``` 71 | ## For Windows Systems 72 | 73 | ### Requirements 74 | 75 | * cmake 76 | * make 77 | * mingw{32,64}-gcc 78 | 79 | ### Building 80 | 81 | mingw64-cmake -DLIBNFC_INCLUDE_DIRS=/path/to/libnfc-source/include -DLIBNFC_LIBRARIES=/path/to/libnfc.dll 82 | mingw64-make 83 | 84 | # Debug 85 | In order to debug using gdb, you should tune the CFLAGS: 86 | ``` 87 | CFLAGS="-O0 -ggdb" ./configure --prefix=/usr 88 | make clean all 89 | ``` 90 | 91 | It is then possible to debug examples using this kind of command from the root of the repository: 92 | ``` 93 | ./libtool --mode=execute gdb examples/mifare-classic-write-ndef 94 | ``` 95 | 96 | If you are only interested in viewing transfert traces between the PCD and the PICC, simply use the `--enable-debug` configure flag: 97 | ``` 98 | ./configure --enable-debug 99 | make clean all 100 | ``` 101 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | [ ] Enforce valid parameters. 2 | Some functions will cause a crash when called with invalid parameters (e.g. 3 | mifare_classic_authenticate() with a NULL key). 4 | [ ] MAD and MifareApplication functions are tied to mifare_clasic_* ones and 5 | some refactoring is required to have a consistent API. 6 | [ ] Refactor examples and have consistent behavior. 7 | Dump to stdout unless -o is specified; 8 | Read from stdin unless a file is specified; 9 | Humanize dumps with a -h flag; 10 | Target aquisition is the same in all examples; 11 | -------------------------------------------------------------------------------- /Updating.md: -------------------------------------------------------------------------------- 1 | # Updating from 0.4.0 to ? 2 | 3 | * The abstract `MifareTag` structure was renamed to `FreefareTag` in order to avoid confusion when adding support for non-MIFARE tags; 4 | Users of libfreefare can simply replace any occurence of `MifareTag` with `FreefareTag`. 5 | * The `mifare_tag_type` enum was renamed to `freefare_tag_type` (this should not have incidence for users) and defined values for MIFARE tags (that is *all* values) have been prefixed with `MIFARE_` for consistency. 6 | Users of libfreefare will need to adjust comparisons of the return value of `freefare_get_tag_type()` if they use this in their code. 7 | 8 | -------------------------------------------------------------------------------- /cmake/config_posix.h.cmake: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __CONFIG_POSIX_H__ 3 | #define __CONFIG_POSIX_H__ 4 | 5 | #cmakedefine _XOPEN_SOURCE @_XOPEN_SOURCE@ 6 | 7 | #cmakedefine HAVE_SYS_ENDIAN_H @_HAVE_SYS_ENDIAN_H@ 8 | #cmakedefine HAVE_ENDIAN_H @_HAVE_ENDIAN_H@ 9 | #cmakedefine HAVE_BYTESWAP_H @_HAVE_BYTESWAP_H@ 10 | #cmakedefine HAVE_COREFOUNDATION_COREFOUNDATION_H @_HAVE_COREFOUNDATION_COREFOUNDATION_H@ 11 | 12 | #cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" 13 | #cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" 14 | #cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" 15 | #cmakedefine _XOPEN_SOURCE @_XOPEN_SOURCE@ 16 | #cmakedefine SYSCONFDIR "@SYSCONFDIR@" 17 | 18 | #endif /* !__CONFIG_POSIX_H__ */ 19 | 20 | -------------------------------------------------------------------------------- /cmake/config_windows.h.cmake: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (C) 2011 Glenn Ergeerts. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as published by the 6 | * Free Software Foundation, either version 3 of the License, or (at your 7 | * option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 | * more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see 16 | */ 17 | 18 | #ifndef __CONFIG_WINDOWS_H__ 19 | #define __CONFIG_WINDOWS_H__ 20 | 21 | #cmakedefine WITH_DEBUG 22 | 23 | #include 24 | 25 | #define htole32(x) (x) 26 | #define le32toh(x) (x) 27 | #define le16toh(x) (x) 28 | #define htobe16(x) htons(x) 29 | #define be16toh(x) ntohs(x) 30 | 31 | #define ENOTSUP WSAEOPNOTSUPP 32 | 33 | #cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" 34 | #cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" 35 | #cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" 36 | #cmakedefine _XOPEN_SOURCE @_XOPEN_SOURCE@ 37 | #cmakedefine SYSCONFDIR "@SYSCONFDIR@" 38 | 39 | #endif /* !__CONFIG_WINDOWS_H__ */ 40 | -------------------------------------------------------------------------------- /cmake/modules/FindLIBNFC.cmake: -------------------------------------------------------------------------------- 1 | # TODO locate using pkg-config for linux/bsd 2 | 3 | #set(LIBNFC_INCLUDE_DIRS "") 4 | #set(LIBNFC_LIBRARIES "") 5 | set(LIBNFC_INSTALL_DIR $ENV{PROGRAMFILES}/libnfc CACHE PATH "libnfc installation directory") 6 | 7 | message("libnfc install dir: " ${LIBNFC_INSTALL_DIR}) 8 | 9 | find_path(LIBNFC_INCLUDE_DIRS NAMES nfc/nfc.h PATHS ${LIBNFC_INSTALL_DIR}/include) 10 | message("libnfc include dir found: " ${LIBNFC_INCLUDE_DIRS}) 11 | 12 | find_library(LIBNFC_LIBRARIES nfc PATHS ${LIBNFC_INSTALL_DIR}/lib) 13 | message("libnfc library found: " ${LIBNFC_LIBRARIES}) 14 | 15 | INCLUDE(FindPackageHandleStandardArgs) 16 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBNFC DEFAULT_MSG 17 | LIBNFC_INCLUDE_DIRS 18 | LIBNFC_LIBRARIES 19 | ) 20 | MARK_AS_ADVANCED(LIBNFC_INCLUDE_DIRS LIBNFC_LIBRARIES) 21 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([libfreefare],[0.4.0]) 2 | 3 | AC_CONFIG_MACRO_DIR([m4]) 4 | 5 | AC_PROG_CC 6 | AC_PROG_CXX 7 | 8 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 9 | LT_INIT 10 | 11 | AC_CONFIG_HEADERS([config.h]) 12 | 13 | AM_INIT_AUTOMAKE(foreign dist-bzip2 no-dist-gzip) 14 | 15 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) 16 | 17 | # Debug support (default:no) 18 | AC_ARG_ENABLE([debug],AS_HELP_STRING([--enable-debug],[Enable debug output]),[enable_debug=$enableval],[enable_debug="no"]) 19 | if test x"$enable_debug" = xyes; then 20 | AC_CHECK_LIB([util], [hexdump], [has_libutil=yes], [has_libutil=no]) 21 | fi 22 | AM_CONDITIONAL(WITH_DEBUG, [test x"$enable_debug" = xyes]) 23 | AM_CONDITIONAL(HAS_LIBUTIL, [test x"$has_libutil" = xyes]) 24 | 25 | # Checks for typedefs, structures, and compiler characteristics. 26 | AC_C_INLINE 27 | AC_HEADER_STDBOOL 28 | AC_TYPE_INT16_T 29 | AC_TYPE_INT32_T 30 | AC_TYPE_OFF_T 31 | AC_TYPE_UINT8_T 32 | AC_TYPE_UINT16_T 33 | AC_TYPE_UINT32_T 34 | AC_TYPE_SIZE_T 35 | AC_TYPE_SSIZE_T 36 | 37 | # Checks for library functions. 38 | AC_FUNC_MALLOC 39 | AC_FUNC_REALLOC 40 | 41 | AC_CHECK_HEADERS([sys/types.h]) 42 | AC_CHECK_FUNCS([memset letoh32 htole32 pow strdup strerror]) 43 | 44 | AC_CHECK_HEADERS([endian.h sys/endian.h CoreFoundation/CoreFoundation.h]) 45 | if test $ac_cv_header_endian_h = "no" -a $ac_cv_header_sys_endian_h = "no" -a $ac_cv_header_CoreFoundation_CoreFoundation_h = "no"; then 46 | AC_MSG_ERROR(["Can't locate usable header file for endianness convertions."]); 47 | fi 48 | 49 | AC_CHECK_HEADERS([byteswap.h]) 50 | 51 | AC_DEFINE([_XOPEN_SOURCE], [600], [Define to 500 if Single Unix conformance is wanted, 600 for sixth revision.]) 52 | AC_DEFINE([_BSD_SOURCE], [1], [Define on BSD to activate all library features]) 53 | 54 | CFLAGS="$CFLAGS -std=c99" 55 | 56 | # Crypto functions for MIFARE DesFire support are provided by OpenSSL. 57 | AC_CHECK_LIB([crypto], [DES_ecb_encrypt], [], [AC_MSG_ERROR([Cannot find libcrypto.])]) 58 | AC_CHECK_HEADERS([openssl/aes.h openssl/des.h openssl/rand.h], [], [AC_MSG_ERROR([Cannot find openssl headers.])]) 59 | 60 | # Checks for pkg-config modules. 61 | LIBNFC_REQUIRED_VERSION="1.7.0" 62 | PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])]) 63 | 64 | PKG_CONFIG_REQUIRES="libnfc" 65 | AC_SUBST([PKG_CONFIG_REQUIRES]) 66 | 67 | CUTTER_REQUIRED_VERSION=1.1.7 68 | m4_ifdef([AC_CHECK_CUTTER], [AC_CHECK_CUTTER([>= $CUTTER_REQUIRED_VERSION])], [ac_cv_use_cutter="no"]) 69 | if test x$ac_cv_with_cutter = xyes -a x$ac_cv_use_cutter = xno; then 70 | AC_MSG_ERROR([cutter >= $CUTTER_REQUIRED_VERSION is mandatory.]) 71 | fi 72 | AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"]) 73 | 74 | m4_ifdef([AC_CHECK_COVERAGE], [AC_CHECK_COVERAGE]) 75 | 76 | if test x$cutter_enable_coverage = xyes; then 77 | CFLAGS="$CFLAGS -O0 -fprofile-arcs -ftest-coverage" 78 | fi 79 | 80 | AC_CONFIG_FILES([Makefile 81 | contrib/Makefile 82 | contrib/libutil/Makefile 83 | examples/Makefile 84 | libfreefare/Makefile 85 | libfreefare.pc 86 | test/Makefile 87 | test/common/Makefile]) 88 | AC_OUTPUT 89 | 90 | -------------------------------------------------------------------------------- /contrib/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = libutil 2 | 3 | EXTRA_DIST = libfreefare_zsnippets.vim 4 | -------------------------------------------------------------------------------- /contrib/libfreefare_zsnippets.vim: -------------------------------------------------------------------------------- 1 | "- 2 | " Copyright (c) 2010 Romain Tartiere. All rights reserved. 3 | " 4 | " Redistribution and use, with or without modification, are permitted provided 5 | " that the following conditions are met: 6 | " 1. Redistributions of source code must retain the above copyright 7 | " notice, this list of conditions and the following disclaimer. 8 | " 9 | " THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 10 | " ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 11 | " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 12 | " ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 13 | " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 14 | " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 15 | " OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 16 | " HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 17 | " LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 18 | " OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 19 | " SUCH DAMAGE. 20 | 21 | " Additionnal snippets for working with libfreefare in vim with the 22 | " snippetsEmu script: 23 | " http://www.vim.org/scripts/script.php?script_id=1318 24 | " 25 | " (Contribution for porting this to better snippet handler are welcome!) 26 | 27 | if !exists('loaded_snippet') || &cp 28 | finish 29 | endif 30 | 31 | let st = g:snip_start_tag 32 | let et = g:snip_end_tag 33 | let cd = g:snip_elem_delim 34 | 35 | exec "Snippet m mifare_".st.et 36 | exec "Snippet mifare_c mifare_classic_".st.et 37 | exec "Snippet mifare_d mifare_desfire_".st.et 38 | exec "Snippet mifare_u mifare_ultralight_".st.et 39 | 40 | exec "Snippet mc mifare_classic_".st.et 41 | exec "Snippet md mifare_desfire_".st.et 42 | exec "Snippet mu mifare_ultralight_".st.et 43 | 44 | exec "Snippet MC MIFARE_CLASSIC".st.et 45 | exec "Snippet MCB MifareClassicBlock".st.et 46 | exec "Snippet MCBN MifareClassicBlockNumber".st.et 47 | exec "Snippet MCSN MifareClassicSectorNumber".st.et 48 | exec "Snippet MCK MifareClassicKey".st.et 49 | exec "Snippet MCKT MifareClassicKeyType".st.et 50 | 51 | exec "Snippet MD MIFARE_DESFIRE".st.et 52 | exec "Snippet MDA MifareDESFireAID".st.et 53 | exec "Snippet MDK MifareDESFireKey".st.et 54 | 55 | exec "Snippet MT FreefareTag".st.et 56 | 57 | exec "Snippet MU MIFARE_ULTRALIGHT".st.et 58 | exec "Snippet MUP MifareUltralightPage".st.et 59 | exec "Snippet MUPN MifareUltralightPageNumber".st.et 60 | 61 | -------------------------------------------------------------------------------- /contrib/libutil/Makefile.am: -------------------------------------------------------------------------------- 1 | if WITH_DEBUG 2 | if !HAS_LIBUTIL 3 | noinst_LTLIBRARIES = libutil.la 4 | noinst_HEADERS = libutil.h 5 | 6 | libutil_la_SOURCES = hexdump.c 7 | endif # !HAS_LIBUTIL 8 | endif # WITH_DEBUG 9 | -------------------------------------------------------------------------------- /contrib/libutil/hexdump.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1986, 1988, 1991, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * (c) UNIX System Laboratories, Inc. 5 | * All or some portions of this file are derived from material licensed 6 | * to the University of California by American Telephone and Telegraph 7 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 | * the permission of UNIX System Laboratories, Inc. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 4. Neither the name of the University nor the names of its contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 | * SUCH DAMAGE. 33 | * 34 | * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 35 | */ 36 | 37 | //#include 38 | //__FBSDID("$FreeBSD: stable/8/lib/libutil/hexdump.c 180161 2008-07-01 22:30:57Z jhb $"); 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | void 45 | hexdump(const void *ptr, int length, const char *hdr, int flags) 46 | { 47 | int i, j, k; 48 | int cols; 49 | const unsigned char *cp; 50 | char delim; 51 | 52 | if ((flags & HD_DELIM_MASK) != 0) 53 | delim = (flags & HD_DELIM_MASK) >> 8; 54 | else 55 | delim = ' '; 56 | 57 | if ((flags & HD_COLUMN_MASK) != 0) 58 | cols = flags & HD_COLUMN_MASK; 59 | else 60 | cols = 16; 61 | 62 | cp = ptr; 63 | for (i = 0; i < length; i+= cols) { 64 | if (hdr != NULL) 65 | printf("%s", hdr); 66 | 67 | if ((flags & HD_OMIT_COUNT) == 0) 68 | printf("%04x ", i); 69 | 70 | if ((flags & HD_OMIT_HEX) == 0) { 71 | for (j = 0; j < cols; j++) { 72 | k = i + j; 73 | if (k < length) 74 | printf("%c%02x", delim, cp[k]); 75 | else 76 | printf(" "); 77 | } 78 | } 79 | 80 | if ((flags & HD_OMIT_CHARS) == 0) { 81 | printf(" |"); 82 | for (j = 0; j < cols; j++) { 83 | k = i + j; 84 | if (k >= length) 85 | printf(" "); 86 | else if (cp[k] >= ' ' && cp[k] <= '~') 87 | printf("%c", cp[k]); 88 | else 89 | printf("."); 90 | } 91 | printf("|"); 92 | } 93 | printf("\n"); 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /contrib/libutil/libutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996 Peter Wemm . 3 | * All rights reserved. 4 | * Copyright (c) 2002 Networks Associates Technology, Inc. 5 | * All rights reserved. 6 | * 7 | * Portions of this software were developed for the FreeBSD Project by 8 | * ThinkSec AS and NAI Labs, the Security Research Division of Network 9 | * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10 | * ("CBOSS"), as part of the DARPA CHATS research program. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, is permitted provided that the following conditions 14 | * are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. The name of the author may not be used to endorse or promote 21 | * products derived from this software without specific prior written 22 | * permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 | * SUCH DAMAGE. 35 | * 36 | * $FreeBSD: stable/8/lib/libutil/libutil.h 185548 2008-12-02 06:50:26Z peter $ 37 | */ 38 | 39 | #ifndef _LIBUTIL_H_ 40 | #define _LIBUTIL_H_ 41 | 42 | void hexdump(const void *ptr, int length, const char *hdr, int flags); 43 | 44 | /* hexdump(3) */ 45 | #define HD_COLUMN_MASK 0xff 46 | #define HD_DELIM_MASK 0xff00 47 | #define HD_OMIT_COUNT (1 << 16) 48 | #define HD_OMIT_HEX (1 << 17) 49 | #define HD_OMIT_CHARS (1 << 18) 50 | 51 | #endif /* !_LIBUTIL_H_ */ 52 | -------------------------------------------------------------------------------- /contrib/win32/err.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (C) 2011 Glenn Ergeerts. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as published by the 6 | * Free Software Foundation, either version 3 of the License, or (at your 7 | * option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 | * more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see 16 | */ 17 | 18 | #ifndef __ERR_H__ 19 | #define __ERR_H__ 20 | 21 | #include 22 | 23 | #define warnx(...) do { \ 24 | fprintf (stderr, __VA_ARGS__); \ 25 | fprintf (stderr, "\n"); \ 26 | } while (0) 27 | 28 | #define errx(code, ...) do { \ 29 | fprintf (stderr, __VA_ARGS__); \ 30 | fprintf (stderr, "\n"); \ 31 | exit (code); \ 32 | } while (0) 33 | 34 | /* FIXME: warn / err are supposed to display errno's message */ 35 | #define warn warnx 36 | #define err errx 37 | 38 | #endif /* !__ERR_H__ */ 39 | -------------------------------------------------------------------------------- /debian/.gitignore: -------------------------------------------------------------------------------- 1 | *.debhelper 2 | *.log 3 | *.substvars 4 | autoreconf.after 5 | autoreconf.before 6 | files 7 | libfreefare*/ 8 | tmp/ 9 | -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | libfreefare for Debian 2 | ---------------------- 3 | 4 | 5 | 6 | -- neomilium Wed, 18 May 2011 12:20:45 +0200 7 | -------------------------------------------------------------------------------- /debian/README.source: -------------------------------------------------------------------------------- 1 | libfreefare for Debian 2 | ---------------------- 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | libfreefare (0.4.0-0) unstable; urgency=low 2 | 3 | * New upstream version 4 | 5 | -- Romuald Conty Wed, 4 Dec 2013 10:42:42 +0100 6 | 7 | libfreefare (0.3.4-0) unstable; urgency=low 8 | 9 | * New upstream version 10 | 11 | -- Romuald Conty Thu, 1 Mar 2012 18:42:42 +0200 12 | 13 | libfreefare (0.3.3-0) unstable; urgency=low 14 | 15 | * New upstream version 16 | 17 | -- Romuald Conty Thu, 1 Mar 2012 16:42:42 +0200 18 | 19 | libfreefare (0.3.1-0) unstable; urgency=low 20 | 21 | * Initial debian package release 22 | 23 | -- Romuald Conty Wed, 18 May 2011 12:42:42 +0200 24 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: libfreefare 2 | Section: libs 3 | Priority: extra 4 | Maintainer: Romuald Conty 5 | Build-Depends: debhelper (>= 7.0.50~), dh-autoreconf, libnfc-dev (>= 1.7.0~rc7), pkg-config, libssl-dev 6 | Standards-Version: 3.9.1 7 | Homepage: http://code.google.com/p/nfc-tools/wiki/libfreefare 8 | Vcs-Svn: http://nfc-tools.googlecode.com/svn/trunk/libfreefare 9 | Vcs-Browser: http://code.google.com/p/nfc-tools/source/browse/#svn/trunk/libfreefare 10 | 11 | Package: libfreefare0 12 | Section: libs 13 | Architecture: any 14 | Depends: ${shlibs:Depends}, ${misc:Depends} 15 | Description: MIFARE card manipulations library 16 | The libfreefare project aims to provide a convenient API for MIFARE 17 | card manipulations. This package contains the libfreefare library. 18 | 19 | Package: libfreefare-dev 20 | Section: libdevel 21 | Architecture: any 22 | Depends: ${misc:Depends}, libfreefare0 (= ${binary:Version}), libnfc-dev 23 | Description: MIFARE card manipulations library (development files) 24 | The libfreefare project aims to provide a convenient API for MIFARE 25 | card manipulations. This package contains development files. 26 | 27 | Package: libfreefare-bin 28 | Section: utils 29 | Architecture: any 30 | Depends: ${shlibs:Depends}, ${misc:Depends}, libfreefare0 (>= ${binary:Version}) 31 | Description: MIFARE card manipulations binaries 32 | The libfreefare project aims to provide a convenient API for MIFARE 33 | card manipulations. This package includes some binaries that are 34 | useful for development purposes. 35 | 36 | Package: libfreefare-doc 37 | Architecture: all 38 | Section: doc 39 | Depends: ${misc:Depends} 40 | Description: documentation for libfreefare 41 | The libfreefare project aims to provide a convenient API for MIFARE 42 | card manipulations. 43 | 44 | 45 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://dep.debian.net/deps/dep5 2 | Upstream-Name: libfreefare 3 | Source: http://code.google.com/p/nfc-tools/wiki/libfreefare 4 | 5 | Files: * 6 | Copyright: 2010-2011, Romain Tartière , Romuald Conty 7 | License: LGPL-3 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU Lesser General Public License version 3 10 | as published by the Free Software Foundation 11 | . 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | . 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, see . 19 | . 20 | On Debian GNU/Linux systems, the complete text of the GNU General 21 | Public License, version 3, can be found in the file 22 | /usr/share/common-licenses/LGPL-3. 23 | 24 | -------------------------------------------------------------------------------- /debian/libfreefare-bin.install: -------------------------------------------------------------------------------- 1 | debian/tmp/usr/bin/mifare-* 2 | -------------------------------------------------------------------------------- /debian/libfreefare-dev.install: -------------------------------------------------------------------------------- 1 | debian/tmp/usr/include/freefare.h 2 | debian/tmp/usr/lib/libfreefare.{a,la,so} 3 | debian/tmp/usr/lib/pkgconfig/libfreefare.pc 4 | -------------------------------------------------------------------------------- /debian/libfreefare-doc.install: -------------------------------------------------------------------------------- 1 | debian/tmp/usr/share/man/man3/* 2 | -------------------------------------------------------------------------------- /debian/libfreefare0.install: -------------------------------------------------------------------------------- 1 | debian/tmp/usr/lib/libfreefare.so.* 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # 5 | # This file was originally written by Joey Hess and Craig Small. 6 | # As a special exception, when this file is copied by dh-make into a 7 | # dh-make output file, you may use that output file without restriction. 8 | # This special exception was added by Craig Small in version 0.37 of dh-make. 9 | # 10 | # Modified to make a template file for a multi-binary package with separated 11 | # build-arch and build-indep targets by Bill Allombert 2001 12 | 13 | # Uncomment this to turn on verbose mode. 14 | #export DH_VERBOSE=1 15 | 16 | # This has to be exported to make some magic below work. 17 | export DH_OPTIONS 18 | 19 | override_dh_auto_configure: 20 | dh_auto_configure -- --without-cutter 21 | 22 | %: 23 | dh --with autoreconf $@ 24 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | # See uscan(1) for format 2 | 3 | # Compulsory line, this is a version 3 file 4 | version=3 5 | 6 | http://googlecode.debian.net/p/nfc-tools/libfreefare-(.*)\.tar\.gz 7 | 8 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(EXAMPLES-SOURCES 2 | mifare-classic-format 3 | mifare-classic-read-ndef 4 | mifare-classic-write-ndef 5 | mifare-desfire-access 6 | mifare-desfire-create-ndef 7 | mifare-desfire-format 8 | mifare-desfire-info 9 | mifare-desfire-read-ndef 10 | mifare-desfire-write-ndef 11 | mifare-desfire-ev1-configure-ats 12 | mifare-desfire-ev1-configure-default-key 13 | mifare-desfire-ev1-configure-random-uid 14 | mifare-ultralight-info 15 | ntag-detect 16 | ntag-removeauth 17 | ntag-setauth 18 | ntag-write 19 | ) 20 | 21 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../libfreefare) 22 | 23 | # Examples 24 | foreach(source ${EXAMPLES-SOURCES}) 25 | add_executable(${source} ${source}.c) 26 | target_link_libraries(${source} freefare) 27 | install(TARGETS ${source} RUNTIME DESTINATION bin COMPONENT examples) 28 | endforeach(source) 29 | -------------------------------------------------------------------------------- /examples/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -I. -I$(top_srcdir)/libfreefare @LIBNFC_CFLAGS@ 2 | AM_LDFLAGS = @LIBNFC_LIBS@ 3 | 4 | bin_PROGRAMS = felica-lite-dump \ 5 | felica-read-ndef \ 6 | mifare-classic-format \ 7 | mifare-classic-write-ndef \ 8 | mifare-classic-read-ndef \ 9 | mifare-desfire-access \ 10 | mifare-desfire-create-ndef \ 11 | mifare-desfire-ev1-configure-ats \ 12 | mifare-desfire-ev1-configure-default-key \ 13 | mifare-desfire-ev1-configure-random-uid \ 14 | mifare-desfire-format \ 15 | mifare-desfire-info \ 16 | mifare-desfire-read-ndef \ 17 | mifare-desfire-write-ndef \ 18 | mifare-ultralight-info \ 19 | mifare-ultralightc-diversify \ 20 | ntag-detect \ 21 | ntag-removeauth \ 22 | ntag-setauth \ 23 | ntag-write 24 | 25 | felica_lite_dump_SOURCES = felica-lite-dump.c 26 | felica_lite_dump_LDADD = $(top_builddir)/libfreefare/libfreefare.la 27 | 28 | felica_read_ndef_SOURCES = felica-read-ndef.c 29 | felica_read_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la 30 | 31 | mifare_classic_format_SOURCES = mifare-classic-format.c 32 | mifare_classic_format_LDADD = $(top_builddir)/libfreefare/libfreefare.la 33 | 34 | mifare_classic_read_ndef_SOURCES = mifare-classic-read-ndef.c 35 | mifare_classic_read_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la 36 | 37 | mifare_classic_write_ndef_SOURCES = mifare-classic-write-ndef.c 38 | mifare_classic_write_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la 39 | 40 | mifare_desfire_access_SOURCES = mifare-desfire-access.c 41 | mifare_desfire_access_LDADD = $(top_builddir)/libfreefare/libfreefare.la 42 | 43 | mifare_desfire_create_ndef_SOURCES = mifare-desfire-create-ndef.c 44 | mifare_desfire_create_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la 45 | 46 | mifare_desfire_ev1_configure_ats_SOURCES = mifare-desfire-ev1-configure-ats.c 47 | mifare_desfire_ev1_configure_ats_LDADD = $(top_builddir)/libfreefare/libfreefare.la 48 | 49 | mifare_desfire_ev1_configure_default_key_SOURCES = mifare-desfire-ev1-configure-default-key.c 50 | mifare_desfire_ev1_configure_default_key_LDADD = $(top_builddir)/libfreefare/libfreefare.la 51 | 52 | mifare_desfire_ev1_configure_random_uid_SOURCES = mifare-desfire-ev1-configure-random-uid.c 53 | mifare_desfire_ev1_configure_random_uid_LDADD = $(top_builddir)/libfreefare/libfreefare.la 54 | 55 | mifare_desfire_format_SOURCES = mifare-desfire-format.c 56 | mifare_desfire_format_LDADD = $(top_builddir)/libfreefare/libfreefare.la 57 | 58 | mifare_desfire_info_SOURCES = mifare-desfire-info.c 59 | mifare_desfire_info_LDADD = $(top_builddir)/libfreefare/libfreefare.la -lm 60 | 61 | mifare_desfire_read_ndef_SOURCES = mifare-desfire-read-ndef.c 62 | mifare_desfire_read_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la 63 | 64 | mifare_desfire_write_ndef_SOURCES = mifare-desfire-write-ndef.c 65 | mifare_desfire_write_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la 66 | 67 | mifare_ultralight_info_SOURCES = mifare-ultralight-info.c 68 | mifare_ultralight_info_LDADD = $(top_builddir)/libfreefare/libfreefare.la 69 | 70 | mifare_ultralightc_diversify_SOURCES = mifare-ultralightc-diversify.c 71 | mifare_ultralightc_diversify_LDADD = $(top_builddir)/libfreefare/libfreefare.la 72 | 73 | ntag_detect_SOURCES = ntag-detect.c 74 | ntag_detect_LDADD = $(top_builddir)/libfreefare/libfreefare.la 75 | 76 | ntag_removeauth_SOURCES = ntag-removeauth.c 77 | ntag_removeauth_LDADD = $(top_builddir)/libfreefare/libfreefare.la 78 | 79 | ntag_setauth_SOURCES = ntag-setauth.c 80 | ntag_setauth_LDADD = $(top_builddir)/libfreefare/libfreefare.la 81 | 82 | ntag_write_SOURCES = ntag-write.c 83 | ntag_write_LDADD = $(top_builddir)/libfreefare/libfreefare.la 84 | 85 | CLEANFILES= *.gcno 86 | -------------------------------------------------------------------------------- /examples/felica-lite-dump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | int 9 | main(void) 10 | { 11 | nfc_device *device = NULL; 12 | FreefareTag *tags = NULL; 13 | nfc_connstring devices[8]; 14 | 15 | nfc_context *context; 16 | nfc_init(&context); 17 | if (context == NULL) 18 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 19 | 20 | size_t device_count = nfc_list_devices(context, devices, 8); 21 | if (device_count <= 0) 22 | errx(EXIT_FAILURE, "No NFC device found."); 23 | 24 | for (size_t d = 0; d < device_count; d++) { 25 | device = nfc_open(context, devices[d]); 26 | if (!device) { 27 | errx(EXIT_FAILURE, "nfc_open() failed."); 28 | } 29 | 30 | tags = freefare_get_tags(device); 31 | if (!tags) { 32 | nfc_close(device); 33 | errx(EXIT_FAILURE, "Error listing FeliCa tag."); 34 | } 35 | 36 | for (int i = 0; tags[i]; i++) { 37 | if (FELICA != freefare_get_tag_type(tags[i])) 38 | continue; 39 | 40 | char *uid = freefare_get_tag_uid(tags[i]); 41 | printf("Dumping %s tag %s\n", freefare_get_tag_friendly_name(tags[i]), uid); 42 | free(uid); 43 | printf("Number\tName\tData\n"); 44 | 45 | for (int block = 0x00; block < 0x0f; block++) { 46 | uint8_t buffer[16]; 47 | 48 | if (felica_read(tags[i], FELICA_SC_RO, block, buffer, sizeof(buffer)) < 0) 49 | errx(EXIT_FAILURE, "Error reading block %d", block); 50 | 51 | if (block < 0x0e) 52 | printf("0x%02x\tS_PAD%d\t", block, block); 53 | else 54 | printf("0x%02x\tREG\t", block); 55 | for (int j = 0; j < 16; j++) { 56 | printf("%02x ", buffer[j]); 57 | } 58 | printf("\n"); 59 | } 60 | 61 | char *block_names[] = { 62 | "RC", "MAC", "ID", "D_ID", "SER_C", "SYS_C", "CKV", "CK", "MC", 63 | }; 64 | int valid_bytes[] = { 65 | 16, 8, 16, 16, 2, 2, 2, 16, 5 66 | }; 67 | for (int block = 0x80; block < 0x89; block++) { 68 | uint8_t buffer[16]; 69 | 70 | if (felica_read(tags[i], FELICA_SC_RO, block, buffer, sizeof(buffer)) < 0) 71 | errx(EXIT_FAILURE, "Error reading block %d", block); 72 | 73 | printf("0x%02x\t%s\t", block, block_names[block - 0x80]); 74 | for (int j = 0; j < valid_bytes[block - 0x80]; j++) { 75 | printf("%02x ", buffer[j]); 76 | } 77 | printf("\n"); 78 | } 79 | } 80 | 81 | freefare_free_tags(tags); 82 | nfc_close(device); 83 | } 84 | 85 | exit(EXIT_SUCCESS); 86 | } 87 | -------------------------------------------------------------------------------- /examples/felica-read-ndef.c: -------------------------------------------------------------------------------- 1 | #if defined(HAVE_CONFIG_H) 2 | #include "config.h" 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if defined(HAVE_SYS_ENDIAN_H) 11 | #include 12 | #endif 13 | 14 | #if defined(HAVE_ENDIAN_H) 15 | #include 16 | #endif 17 | 18 | #if defined(HAVE_COREFOUNDATION_COREFOUNDATION_H) 19 | #include 20 | #endif 21 | 22 | #include 23 | 24 | #include 25 | #include "../libfreefare/freefare_internal.h" 26 | 27 | #define NDEF_BUFFER_SIZE 512 28 | 29 | void 30 | usage(char *progname) 31 | { 32 | fprintf(stderr, "usage: %s [options]\n", progname); 33 | fprintf(stderr, "\nAvailable options:\n"); 34 | fprintf(stderr, " -o FILE Write NDEF message to FILE\n"); 35 | } 36 | 37 | int 38 | main(int argc, char *argv[]) 39 | { 40 | int error = EXIT_SUCCESS; 41 | nfc_device *device = NULL; 42 | FreefareTag *tags = NULL; 43 | 44 | int ch; 45 | char *ndef_file = NULL; 46 | while ((ch = getopt(argc, argv, "o:")) != -1) { 47 | switch (ch) { 48 | case 'o': 49 | ndef_file = optarg; 50 | break; 51 | case '?': 52 | usage(argv[0]); 53 | exit(EXIT_FAILURE); 54 | } 55 | } 56 | 57 | nfc_connstring devices[8]; 58 | 59 | size_t device_count; 60 | 61 | nfc_context *context; 62 | nfc_init(&context); 63 | if (context == NULL) 64 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 65 | 66 | device_count = nfc_list_devices(context, devices, 8); 67 | if (device_count <= 0) 68 | errx(EXIT_FAILURE, "No NFC device found."); 69 | 70 | for (size_t d = 0; d < device_count; d++) { 71 | device = nfc_open(context, devices[d]); 72 | if (!device) { 73 | warnx("nfc_open() failed."); 74 | error = EXIT_FAILURE; 75 | continue; 76 | } 77 | 78 | tags = freefare_get_tags(device); 79 | if (!tags) { 80 | nfc_close(device); 81 | errx(EXIT_FAILURE, "Error listing FeliCa tag."); 82 | } 83 | 84 | for (int i = 0; (!error) && tags[i]; i++) { 85 | int block = 1; 86 | uint8_t ndef_message[NDEF_BUFFER_SIZE]; 87 | int ndef_space_left = NDEF_BUFFER_SIZE; 88 | uint8_t *p = ndef_message; 89 | ssize_t s; 90 | 91 | // FIXME Instead of reading as much as we can, we should read until end of NDEF record (if any is found). 92 | while ((ndef_space_left >= 16) && (s = felica_read(tags[i], FELICA_SC_RO, block++, p, 16)) > 0) { 93 | p += s; 94 | ndef_space_left -= s; 95 | } 96 | 97 | size_t ndef_message_length = 0; 98 | 99 | if ((ndef_message[0] & 0x80) == 0x80) { 100 | uint8_t *ndef_record; 101 | do { 102 | ndef_record = ndef_message + ndef_message_length; 103 | 104 | size_t ndef_record_length = 1 + 1 + ndef_record[1]; 105 | size_t payload_length; 106 | size_t payload_length_length; 107 | 108 | if (ndef_record[0] & 0x10) { 109 | /* Short record */ 110 | payload_length = ndef_record[2]; 111 | payload_length_length = 1; 112 | } else { 113 | payload_length = be32toh(*(uint32_t *)(ndef_record + 2)); 114 | payload_length_length = 4; 115 | } 116 | ndef_record_length += payload_length_length; 117 | ndef_record_length += payload_length; 118 | 119 | if (ndef_record[0] & 0x08) { 120 | ndef_record_length += 2; 121 | } 122 | 123 | ndef_message_length += ndef_record_length; 124 | if (ndef_message_length > NDEF_BUFFER_SIZE) 125 | errx(EXIT_FAILURE, "NDEF message truncated"); 126 | 127 | } while ((ndef_record[0] & 0x40) != 0x40); 128 | } 129 | 130 | if (ndef_message_length == 0) 131 | errx(EXIT_FAILURE, "No NDEF message found"); 132 | 133 | FILE *f; 134 | if (ndef_file) 135 | f = fopen(ndef_file, "w"); 136 | else 137 | f = stdout; 138 | 139 | if (fwrite(ndef_message, ndef_message_length, 1, f) != 1) 140 | err(EXIT_FAILURE, "Can't write NDEF message"); 141 | 142 | fclose(f); 143 | } 144 | 145 | freefare_free_tags(tags); 146 | nfc_close(device); 147 | } 148 | exit(EXIT_SUCCESS); 149 | } 150 | -------------------------------------------------------------------------------- /examples/mifare-desfire-access.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | uint8_t key_data_null[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 11 | 12 | int 13 | main(int argc, char *argv[]) 14 | { 15 | int error = EXIT_SUCCESS; 16 | nfc_device *device = NULL; 17 | FreefareTag *tags = NULL; 18 | 19 | if (argc > 1) 20 | errx(EXIT_FAILURE, "usage: %s", argv[0]); 21 | 22 | nfc_connstring devices[8]; 23 | size_t device_count; 24 | 25 | nfc_context *context; 26 | nfc_init(&context); 27 | if (context == NULL) 28 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 29 | 30 | device_count = nfc_list_devices(context, devices, 8); 31 | if (device_count <= 0) 32 | errx(EXIT_FAILURE, "No NFC device found."); 33 | 34 | for (size_t d = 0; d < device_count; d++) { 35 | device = nfc_open(context, devices[d]); 36 | if (!device) { 37 | warnx("nfc_open() failed."); 38 | error = EXIT_FAILURE; 39 | continue; 40 | } 41 | 42 | tags = freefare_get_tags(device); 43 | if (!tags) { 44 | nfc_close(device); 45 | errx(EXIT_FAILURE, "Error listing tags."); 46 | } 47 | 48 | for (int i = 0; (!error) && tags[i]; i++) { 49 | if (MIFARE_DESFIRE != freefare_get_tag_type(tags[i])) 50 | continue; 51 | 52 | int res; 53 | char *tag_uid = freefare_get_tag_uid(tags[i]); 54 | 55 | res = mifare_desfire_connect(tags[i]); 56 | if (res < 0) { 57 | warnx("Can't connect to Mifare DESFire target."); 58 | error = EXIT_FAILURE; 59 | break; 60 | } 61 | 62 | 63 | MifareDESFireKey key = mifare_desfire_des_key_new_with_version(key_data_null); 64 | res = mifare_desfire_authenticate(tags[i], 0, key); 65 | if (res < 0) 66 | errx(EXIT_FAILURE, "Authentication on master application failed"); 67 | 68 | MadAid mad_aid = { 0x12, 0x34 }; 69 | MifareDESFireAID aid = mifare_desfire_aid_new_with_mad_aid(mad_aid, 0x5); 70 | res = mifare_desfire_create_application(tags[i], aid, 0xFF, 0x1); 71 | if (res < 0) 72 | errx(EXIT_FAILURE, "Application creation failed"); 73 | 74 | res = mifare_desfire_select_application(tags[i], aid); 75 | if (res < 0) 76 | errx(EXIT_FAILURE, "Application selection failed"); 77 | 78 | res = mifare_desfire_authenticate(tags[i], 0, key); 79 | if (res < 0) 80 | errx(EXIT_FAILURE, "Authentication on application failed"); 81 | 82 | res = mifare_desfire_create_std_data_file(tags[i], 1, MDCM_ENCIPHERED, 0x0000, 20); 83 | if (res < 0) 84 | errx(EXIT_FAILURE, "File creation failed"); 85 | 86 | const char *s = "Hello World"; 87 | res = mifare_desfire_write_data(tags[i], 1, 0, strlen(s), s); 88 | if (res < 0) 89 | errx(EXIT_FAILURE, "File write failed"); 90 | 91 | char buffer[20]; 92 | res = mifare_desfire_read_data(tags[i], 1, 0, 0, buffer); 93 | if (res < 0) 94 | errx(EXIT_FAILURE, "File read failed"); 95 | 96 | res = mifare_desfire_select_application(tags[i], NULL); 97 | if (res < 0) 98 | errx(EXIT_FAILURE, "Master application selection failed"); 99 | 100 | res = mifare_desfire_authenticate(tags[i], 0, key); 101 | if (res < 0) 102 | errx(EXIT_FAILURE, "Authentication on master application failed"); 103 | 104 | res = mifare_desfire_format_picc(tags[i]); 105 | if (res < 0) 106 | errx(EXIT_FAILURE, "PICC format failed"); 107 | 108 | mifare_desfire_key_free(key); 109 | free(tag_uid); 110 | free(aid); 111 | 112 | mifare_desfire_disconnect(tags[i]); 113 | } 114 | 115 | freefare_free_tags(tags); 116 | nfc_close(device); 117 | } 118 | nfc_exit(context); 119 | exit(error); 120 | } /* main() */ 121 | 122 | -------------------------------------------------------------------------------- /examples/mifare-desfire-ev1-configure-ats.c: -------------------------------------------------------------------------------- 1 | #if defined(HAVE_CONFIG_H) 2 | #include "config.h" 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | uint8_t key_data_picc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 16 | 17 | // TODO: Allow to pass another ATS as option 18 | // Default Mifare DESFire ATS 19 | uint8_t new_ats[] = { 0x06, 0x75, 0x77, 0x81, 0x02, 0x80 }; 20 | 21 | struct { 22 | bool interactive; 23 | } configure_options = { 24 | .interactive = true 25 | }; 26 | 27 | static void 28 | usage(char *progname) 29 | { 30 | fprintf(stderr, "usage: %s [-y] [-K 11223344AABBCCDD]\n", progname); 31 | fprintf(stderr, "\nOptions:\n"); 32 | fprintf(stderr, " -y Do not ask for confirmation (dangerous)\n"); 33 | fprintf(stderr, " -K Provide another PICC key than the default one\n"); 34 | } 35 | 36 | int 37 | main(int argc, char *argv[]) 38 | { 39 | int ch; 40 | int error = EXIT_SUCCESS; 41 | nfc_device *device = NULL; 42 | FreefareTag *tags = NULL; 43 | 44 | while ((ch = getopt(argc, argv, "hyK:")) != -1) { 45 | switch (ch) { 46 | case 'h': 47 | usage(argv[0]); 48 | exit(EXIT_SUCCESS); 49 | break; 50 | case 'y': 51 | configure_options.interactive = false; 52 | break; 53 | case 'K': 54 | if (strlen(optarg) != 16) { 55 | usage(argv[0]); 56 | exit(EXIT_FAILURE); 57 | } 58 | uint64_t n = strtoull(optarg, NULL, 16); 59 | int i; 60 | for (i = 7; i >= 0; i--) { 61 | key_data_picc[i] = (uint8_t) n; 62 | n >>= 8; 63 | } 64 | break; 65 | default: 66 | usage(argv[0]); 67 | exit(EXIT_FAILURE); 68 | } 69 | } 70 | // Remaining args, if any, are in argv[optind .. (argc-1)] 71 | 72 | nfc_connstring devices[8]; 73 | size_t device_count; 74 | 75 | nfc_context *context; 76 | nfc_init(&context); 77 | if (context == NULL) 78 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 79 | 80 | device_count = nfc_list_devices(context, devices, 8); 81 | if (device_count <= 0) 82 | errx(EXIT_FAILURE, "No NFC device found."); 83 | 84 | for (size_t d = 0; (!error) && (d < device_count); d++) { 85 | device = nfc_open(context, devices[d]); 86 | if (!device) { 87 | warnx("nfc_open() failed."); 88 | error = EXIT_FAILURE; 89 | continue; 90 | } 91 | 92 | tags = freefare_get_tags(device); 93 | if (!tags) { 94 | nfc_close(device); 95 | errx(EXIT_FAILURE, "Error listing Mifare DESFire tags."); 96 | } 97 | 98 | for (int i = 0; (!error) && tags[i]; i++) { 99 | if (MIFARE_DESFIRE != freefare_get_tag_type(tags[i])) 100 | continue; 101 | 102 | char *tag_uid = freefare_get_tag_uid(tags[i]); 103 | char buffer[BUFSIZ]; 104 | int res; 105 | 106 | res = mifare_desfire_connect(tags[i]); 107 | if (res < 0) { 108 | warnx("Can't connect to Mifare DESFire target."); 109 | error = EXIT_FAILURE; 110 | break; 111 | } 112 | 113 | // Make sure we've at least an EV1 version 114 | struct mifare_desfire_version_info info; 115 | res = mifare_desfire_get_version(tags[i], &info); 116 | if (res < 0) { 117 | freefare_perror(tags[i], "mifare_desfire_get_version"); 118 | error = 1; 119 | break; 120 | } 121 | if (info.software.version_major < 1) { 122 | warnx("Found old DESFire, skipping"); 123 | continue; 124 | } 125 | printf("Found %s with UID %s. ", freefare_get_tag_friendly_name(tags[i]), tag_uid); 126 | bool do_it = true; 127 | 128 | if (configure_options.interactive) { 129 | printf("Change ATS? [yN] "); 130 | fgets(buffer, BUFSIZ, stdin); 131 | do_it = ((buffer[0] == 'y') || (buffer[0] == 'Y')); 132 | } else { 133 | printf("\n"); 134 | } 135 | 136 | if (do_it) { 137 | 138 | MifareDESFireKey key_picc = mifare_desfire_des_key_new_with_version(key_data_picc); 139 | res = mifare_desfire_authenticate(tags[i], 0, key_picc); 140 | if (res < 0) { 141 | freefare_perror(tags[i], "mifare_desfire_authenticate"); 142 | error = EXIT_FAILURE; 143 | break; 144 | } 145 | mifare_desfire_key_free(key_picc); 146 | 147 | res = mifare_desfire_set_ats(tags[i], new_ats); 148 | if (res < 0) { 149 | freefare_perror(tags[i], "mifare_desfire_set_ats"); 150 | error = EXIT_FAILURE; 151 | break; 152 | } 153 | 154 | } 155 | 156 | mifare_desfire_disconnect(tags[i]); 157 | free(tag_uid); 158 | } 159 | 160 | freefare_free_tags(tags); 161 | nfc_close(device); 162 | } 163 | nfc_exit(context); 164 | exit(error); 165 | } /* main() */ 166 | 167 | -------------------------------------------------------------------------------- /examples/mifare-desfire-ev1-configure-random-uid.c: -------------------------------------------------------------------------------- 1 | #if defined(HAVE_CONFIG_H) 2 | #include "config.h" 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | uint8_t key_data_picc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 16 | 17 | struct { 18 | bool interactive; 19 | } configure_options = { 20 | .interactive = true 21 | }; 22 | 23 | static void 24 | usage(char *progname) 25 | { 26 | fprintf(stderr, "usage: %s [-y] [-K 11223344AABBCCDD]\n", progname); 27 | fprintf(stderr, "\nOptions:\n"); 28 | fprintf(stderr, " -y Do not ask for confirmation (dangerous)\n"); 29 | fprintf(stderr, " -K Provide another PICC key than the default one\n"); 30 | } 31 | 32 | int 33 | main(int argc, char *argv[]) 34 | { 35 | int ch; 36 | int error = EXIT_SUCCESS; 37 | nfc_device *device = NULL; 38 | FreefareTag *tags = NULL; 39 | 40 | while ((ch = getopt(argc, argv, "hyK:")) != -1) { 41 | switch (ch) { 42 | case 'h': 43 | usage(argv[0]); 44 | exit(EXIT_SUCCESS); 45 | break; 46 | case 'y': 47 | configure_options.interactive = false; 48 | break; 49 | case 'K': 50 | if (strlen(optarg) != 16) { 51 | usage(argv[0]); 52 | exit(EXIT_FAILURE); 53 | } 54 | uint64_t n = strtoull(optarg, NULL, 16); 55 | int i; 56 | for (i = 7; i >= 0; i--) { 57 | key_data_picc[i] = (uint8_t) n; 58 | n >>= 8; 59 | } 60 | break; 61 | default: 62 | usage(argv[0]); 63 | exit(EXIT_FAILURE); 64 | } 65 | } 66 | // Remaining args, if any, are in argv[optind .. (argc-1)] 67 | 68 | nfc_connstring devices[8]; 69 | size_t device_count; 70 | 71 | nfc_context *context; 72 | nfc_init(&context); 73 | if (context == NULL) 74 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 75 | 76 | device_count = nfc_list_devices(context, devices, 8); 77 | if (device_count <= 0) 78 | errx(EXIT_FAILURE, "No NFC device found."); 79 | 80 | for (size_t d = 0; (!error) && (d < device_count); d++) { 81 | device = nfc_open(context, devices[d]); 82 | if (!device) { 83 | warnx("nfc_open() failed."); 84 | error = EXIT_FAILURE; 85 | continue; 86 | } 87 | 88 | tags = freefare_get_tags(device); 89 | if (!tags) { 90 | nfc_close(device); 91 | errx(EXIT_FAILURE, "Error listing Mifare DESFire tags."); 92 | } 93 | 94 | for (int i = 0; (!error) && tags[i]; i++) { 95 | if (MIFARE_DESFIRE != freefare_get_tag_type(tags[i])) 96 | continue; 97 | 98 | char *tag_uid = freefare_get_tag_uid(tags[i]); 99 | char buffer[BUFSIZ]; 100 | 101 | int res; 102 | 103 | res = mifare_desfire_connect(tags[i]); 104 | if (res < 0) { 105 | warnx("Can't connect to Mifare DESFire target."); 106 | error = EXIT_FAILURE; 107 | break; 108 | } 109 | 110 | // Make sure we've at least an EV1 version 111 | struct mifare_desfire_version_info info; 112 | res = mifare_desfire_get_version(tags[i], &info); 113 | if (res < 0) { 114 | freefare_perror(tags[i], "mifare_desfire_get_version"); 115 | error = 1; 116 | break; 117 | } 118 | if (info.software.version_major < 1) { 119 | warnx("Found old DESFire, skipping"); 120 | continue; 121 | } 122 | 123 | printf("Found %s with UID %s. ", freefare_get_tag_friendly_name(tags[i]), tag_uid); 124 | bool do_it = true; 125 | 126 | size_t tag_uid_len = strlen(tag_uid) / 2; 127 | switch (tag_uid_len) { 128 | case 7: // Regular UID 129 | if (configure_options.interactive) { 130 | printf("Configure random UID (this cannot be undone) [yN] "); 131 | fgets(buffer, BUFSIZ, stdin); 132 | do_it = ((buffer[0] == 'y') || (buffer[0] == 'Y')); 133 | } else { 134 | printf("\n"); 135 | } 136 | 137 | if (do_it) { 138 | 139 | MifareDESFireKey key_picc = mifare_desfire_des_key_new_with_version(key_data_picc); 140 | res = mifare_desfire_authenticate(tags[i], 0, key_picc); 141 | if (res < 0) { 142 | freefare_perror(tags[i], "mifare_desfire_authenticate"); 143 | error = EXIT_FAILURE; 144 | break; 145 | } 146 | mifare_desfire_key_free(key_picc); 147 | 148 | res = mifare_desfire_set_configuration(tags[i], false, true); 149 | if (res < 0) { 150 | freefare_perror(tags[i], "mifare_desfire_set_configuration"); 151 | error = EXIT_FAILURE; 152 | break; 153 | } 154 | } 155 | break; 156 | case 4: { // Random UID 157 | } // Compilation fails if label is directly followed by the declaration rather than a statement 158 | MifareDESFireKey key_picc = mifare_desfire_des_key_new_with_version(key_data_picc); 159 | res = mifare_desfire_authenticate(tags[i], 0, key_picc); 160 | if (res < 0) { 161 | freefare_perror(tags[i], "mifare_desfire_authenticate"); 162 | error = EXIT_FAILURE; 163 | break; 164 | } 165 | mifare_desfire_key_free(key_picc); 166 | 167 | char *old_tag_uid; 168 | res = mifare_desfire_get_card_uid(tags[i], &old_tag_uid); 169 | if (res < 0) { 170 | freefare_perror(tags[i], "mifare_desfire_get_card_uid"); 171 | error = EXIT_FAILURE; 172 | break; 173 | } 174 | 175 | printf("Old card UID: %s\n", old_tag_uid); 176 | free(old_tag_uid); 177 | 178 | break; 179 | default: // Should not happen 180 | warnx("Unsupported UID length %d.", (int) tag_uid_len); 181 | error = EXIT_FAILURE; 182 | break; 183 | } 184 | 185 | mifare_desfire_disconnect(tags[i]); 186 | free(tag_uid); 187 | } 188 | 189 | freefare_free_tags(tags); 190 | nfc_close(device); 191 | } 192 | nfc_exit(context); 193 | exit(error); 194 | } /* main() */ 195 | 196 | -------------------------------------------------------------------------------- /examples/mifare-desfire-format.c: -------------------------------------------------------------------------------- 1 | #if defined(HAVE_CONFIG_H) 2 | #include "config.h" 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | uint8_t key_data_picc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 16 | 17 | struct { 18 | bool interactive; 19 | } format_options = { 20 | .interactive = true 21 | }; 22 | 23 | static void 24 | usage(char *progname) 25 | { 26 | fprintf(stderr, "usage: %s [-y] [-K 11223344AABBCCDD]\n", progname); 27 | fprintf(stderr, "\nOptions:\n"); 28 | fprintf(stderr, " -y Do not ask for confirmation (dangerous)\n"); 29 | fprintf(stderr, " -K Provide another PICC key than the default one\n"); 30 | } 31 | 32 | int 33 | main(int argc, char *argv[]) 34 | { 35 | int ch; 36 | int error = EXIT_SUCCESS; 37 | nfc_device *device = NULL; 38 | FreefareTag *tags = NULL; 39 | 40 | while ((ch = getopt(argc, argv, "hyK:")) != -1) { 41 | switch (ch) { 42 | case 'h': 43 | usage(argv[0]); 44 | exit(EXIT_SUCCESS); 45 | break; 46 | case 'y': 47 | format_options.interactive = false; 48 | break; 49 | case 'K': 50 | if (strlen(optarg) != 16) { 51 | usage(argv[0]); 52 | exit(EXIT_FAILURE); 53 | } 54 | uint64_t n = strtoull(optarg, NULL, 16); 55 | int i; 56 | for (i = 7; i >= 0; i--) { 57 | key_data_picc[i] = (uint8_t) n; 58 | n >>= 8; 59 | } 60 | break; 61 | default: 62 | usage(argv[0]); 63 | exit(EXIT_FAILURE); 64 | } 65 | } 66 | // Remaining args, if any, are in argv[optind .. (argc-1)] 67 | 68 | nfc_connstring devices[8]; 69 | size_t device_count; 70 | 71 | nfc_context *context; 72 | nfc_init(&context); 73 | if (context == NULL) 74 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 75 | 76 | device_count = nfc_list_devices(context, devices, 8); 77 | if (device_count <= 0) 78 | errx(EXIT_FAILURE, "No NFC device found."); 79 | 80 | for (size_t d = 0; (!error) && (d < device_count); d++) { 81 | device = nfc_open(context, devices[d]); 82 | if (!device) { 83 | warnx("nfc_open() failed."); 84 | error = EXIT_FAILURE; 85 | continue; 86 | } 87 | 88 | tags = freefare_get_tags(device); 89 | if (!tags) { 90 | nfc_close(device); 91 | errx(EXIT_FAILURE, "Error listing Mifare DESFire tags."); 92 | } 93 | 94 | for (int i = 0; (!error) && tags[i]; i++) { 95 | if (MIFARE_DESFIRE != freefare_get_tag_type(tags[i])) 96 | continue; 97 | 98 | char *tag_uid = freefare_get_tag_uid(tags[i]); 99 | char buffer[BUFSIZ]; 100 | 101 | printf("Found %s with UID %s. ", freefare_get_tag_friendly_name(tags[i]), tag_uid); 102 | bool format = true; 103 | if (format_options.interactive) { 104 | printf("Format [yN] "); 105 | fgets(buffer, BUFSIZ, stdin); 106 | format = ((buffer[0] == 'y') || (buffer[0] == 'Y')); 107 | } else { 108 | printf("\n"); 109 | } 110 | 111 | if (format) { 112 | int res; 113 | 114 | res = mifare_desfire_connect(tags[i]); 115 | if (res < 0) { 116 | warnx("Can't connect to Mifare DESFire target."); 117 | error = EXIT_FAILURE; 118 | break; 119 | } 120 | 121 | MifareDESFireKey key_picc = mifare_desfire_des_key_new_with_version(key_data_picc); 122 | res = mifare_desfire_authenticate(tags[i], 0, key_picc); 123 | if (res < 0) { 124 | warnx("Can't authenticate on Mifare DESFire target."); 125 | error = EXIT_FAILURE; 126 | break; 127 | } 128 | mifare_desfire_key_free(key_picc); 129 | 130 | // Send Mifare DESFire ChangeKeySetting to change the PICC master key settings into : 131 | // bit7-bit4 equal to 0000b 132 | // bit3 equal to 1b, the configuration of the PICC master key MAY be changeable or frozen 133 | // bit2 equal to 1b, CreateApplication and DeleteApplication commands are allowed without PICC master key authentication 134 | // bit1 equal to 1b, GetApplicationIDs, and GetKeySettings are allowed without PICC master key authentication 135 | // bit0 equal to 1b, PICC masterkey MAY be frozen or changeable 136 | res = mifare_desfire_change_key_settings(tags[i], 0x0F); 137 | if (res < 0) 138 | errx(EXIT_FAILURE, "ChangeKeySettings failed"); 139 | res = mifare_desfire_format_picc(tags[i]); 140 | if (res < 0) { 141 | warn("Can't format PICC."); 142 | error = EXIT_FAILURE; 143 | break; 144 | } 145 | 146 | mifare_desfire_disconnect(tags[i]); 147 | } 148 | 149 | free(tag_uid); 150 | } 151 | 152 | freefare_free_tags(tags); 153 | nfc_close(device); 154 | } 155 | nfc_exit(context); 156 | exit(error); 157 | } /* main() */ 158 | 159 | -------------------------------------------------------------------------------- /examples/mifare-desfire-info.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | int 11 | main(int argc, char *argv[]) 12 | { 13 | int error = EXIT_SUCCESS; 14 | nfc_device *device = NULL; 15 | FreefareTag *tags = NULL; 16 | 17 | if (argc > 1) 18 | errx(EXIT_FAILURE, "usage: %s", argv[0]); 19 | 20 | nfc_connstring devices[8]; 21 | size_t device_count; 22 | 23 | nfc_context *context; 24 | nfc_init(&context); 25 | if (context == NULL) 26 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 27 | 28 | device_count = nfc_list_devices(context, devices, 8); 29 | if (device_count <= 0) 30 | errx(EXIT_FAILURE, "No NFC device found."); 31 | 32 | for (size_t d = 0; d < device_count; d++) { 33 | device = nfc_open(context, devices[d]); 34 | if (!device) { 35 | warnx("nfc_open() failed."); 36 | error = EXIT_FAILURE; 37 | continue; 38 | } 39 | 40 | tags = freefare_get_tags(device); 41 | if (!tags) { 42 | nfc_close(device); 43 | errx(EXIT_FAILURE, "Error listing tags."); 44 | } 45 | 46 | for (int i = 0; (!error) && tags[i]; i++) { 47 | if (MIFARE_DESFIRE != freefare_get_tag_type(tags[i])) 48 | continue; 49 | 50 | int res; 51 | char *tag_uid = freefare_get_tag_uid(tags[i]); 52 | 53 | struct mifare_desfire_version_info info; 54 | 55 | res = mifare_desfire_connect(tags[i]); 56 | if (res < 0) { 57 | warnx("Can't connect to Mifare DESFire target."); 58 | error = 1; 59 | break; 60 | } 61 | 62 | res = mifare_desfire_get_version(tags[i], &info); 63 | if (res < 0) { 64 | freefare_perror(tags[i], "mifare_desfire_get_version"); 65 | error = 1; 66 | break; 67 | } 68 | 69 | printf("===> Version information for tag %s:\n", tag_uid); 70 | printf("UID: 0x%02x%02x%02x%02x%02x%02x%02x\n", info.uid[0], info.uid[1], info.uid[2], info.uid[3], info.uid[4], info.uid[5], info.uid[6]); 71 | printf("Batch number: 0x%02x%02x%02x%02x%02x\n", info.batch_number[0], info.batch_number[1], info.batch_number[2], info.batch_number[3], info.batch_number[4]); 72 | printf("Production date: week %x, 20%02x\n", info.production_week, info.production_year); 73 | printf("Hardware Information:\n"); 74 | printf(" Vendor ID: 0x%02x\n", info.hardware.vendor_id); 75 | printf(" Type: 0x%02x\n", info.hardware.type); 76 | printf(" Subtype: 0x%02x\n", info.hardware.subtype); 77 | printf(" Version: %d.%d\n", info.hardware.version_major, info.hardware.version_minor); 78 | printf(" Storage size: 0x%02x (%s%d bytes)\n", info.hardware.storage_size, (info.hardware.storage_size & 1) ? ">" : "=", 1 << (info.hardware.storage_size >> 1)); 79 | printf(" Protocol: 0x%02x\n", info.hardware.protocol); 80 | printf("Software Information:\n"); 81 | printf(" Vendor ID: 0x%02x\n", info.software.vendor_id); 82 | printf(" Type: 0x%02x\n", info.software.type); 83 | printf(" Subtype: 0x%02x\n", info.software.subtype); 84 | printf(" Version: %d.%d\n", info.software.version_major, info.software.version_minor); 85 | printf(" Storage size: 0x%02x (%s%d bytes)\n", info.software.storage_size, (info.software.storage_size & 1) ? ">" : "=", 1 << (info.software.storage_size >> 1)); 86 | printf(" Protocol: 0x%02x\n", info.software.protocol); 87 | 88 | uint8_t settings; 89 | uint8_t max_keys; 90 | res = mifare_desfire_get_key_settings(tags[i], &settings, &max_keys); 91 | if (res == 0) { 92 | printf("Master Key settings (0x%02x):\n", settings); 93 | printf(" 0x%02x configuration changeable;\n", settings & 0x08); 94 | printf(" 0x%02x PICC Master Key not required for create / delete;\n", settings & 0x04); 95 | printf(" 0x%02x Free directory list access without PICC Master Key;\n", settings & 0x02); 96 | printf(" 0x%02x Allow changing the Master Key;\n", settings & 0x01); 97 | } else if (AUTHENTICATION_ERROR == mifare_desfire_last_picc_error(tags[i])) { 98 | printf("Master Key settings: LOCKED\n"); 99 | } else { 100 | freefare_perror(tags[i], "mifare_desfire_get_key_settings"); 101 | error = 1; 102 | break; 103 | } 104 | 105 | uint8_t version; 106 | mifare_desfire_get_key_version(tags[i], 0, &version); 107 | printf("Master Key version: %d (0x%02x)\n", version, version); 108 | 109 | uint32_t size; 110 | res = mifare_desfire_free_mem(tags[i], &size); 111 | printf("Free memory: "); 112 | if (0 == res) { 113 | printf("%d bytes\n", size); 114 | } else { 115 | printf("unknown\n"); 116 | } 117 | 118 | printf("Use random UID: %s\n", (strlen(tag_uid) / 2 == 4) ? "yes" : "no"); 119 | 120 | free(tag_uid); 121 | 122 | mifare_desfire_disconnect(tags[i]); 123 | } 124 | 125 | freefare_free_tags(tags); 126 | nfc_close(device); 127 | } 128 | nfc_exit(context); 129 | exit(error); 130 | } /* main() */ 131 | 132 | -------------------------------------------------------------------------------- /examples/mifare-ultralight-info.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | int 9 | main(int argc, char *argv[]) 10 | { 11 | int error = EXIT_SUCCESS; 12 | nfc_device *device = NULL; 13 | FreefareTag *tags = NULL; 14 | 15 | if (argc > 1) 16 | errx(EXIT_FAILURE, "usage: %s", argv[0]); 17 | 18 | nfc_connstring devices[8]; 19 | size_t device_count; 20 | 21 | nfc_context *context; 22 | nfc_init(&context); 23 | if (context == NULL) 24 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 25 | 26 | device_count = nfc_list_devices(context, devices, sizeof(devices) / sizeof(*devices)); 27 | if (device_count <= 0) 28 | errx(EXIT_FAILURE, "No NFC device found"); 29 | 30 | for (size_t d = 0; d < device_count; d++) { 31 | if (!(device = nfc_open(context, devices[d]))) { 32 | warnx("nfc_open() failed."); 33 | error = EXIT_FAILURE; 34 | continue; 35 | } 36 | 37 | if (!(tags = freefare_get_tags(device))) { 38 | nfc_close(device); 39 | errx(EXIT_FAILURE, "Error listing tags."); 40 | } 41 | 42 | for (int i = 0; (!error) && tags[i]; i++) { 43 | switch (freefare_get_tag_type(tags[i])) { 44 | case MIFARE_ULTRALIGHT: 45 | case MIFARE_ULTRALIGHT_C: 46 | break; 47 | default: 48 | continue; 49 | } 50 | 51 | char *tag_uid = freefare_get_tag_uid(tags[i]); 52 | printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name(tags[i])); 53 | if (freefare_get_tag_type(tags[i]) == MIFARE_ULTRALIGHT_C) { 54 | FreefareTag tag = tags[i]; 55 | int res; 56 | MifareDESFireKey key; 57 | uint8_t key1_3des_data[16] = { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }; 58 | key = mifare_desfire_3des_key_new(key1_3des_data); 59 | if (mifare_ultralight_connect(tag) < 0) 60 | errx(EXIT_FAILURE, "Error connecting to tag."); 61 | res = mifare_ultralightc_authenticate(tag, key); 62 | if (res != 0) { 63 | MifareDESFireKey diversified_key = NULL; 64 | MifareKeyDeriver deriver = mifare_key_deriver_new_an10922(key, MIFARE_KEY_2K3DES, AN10922_FLAG_DEFAULT); 65 | 66 | mifare_key_deriver_begin(deriver); 67 | mifare_key_deriver_update_uid(deriver, tag); 68 | diversified_key = mifare_key_deriver_end(deriver); 69 | 70 | // Disconnect and reconnect. 71 | mifare_ultralight_disconnect(tag); 72 | if (mifare_ultralight_connect(tag) < 0) 73 | errx(EXIT_FAILURE, "Error connecting to tag."); 74 | 75 | res = mifare_ultralightc_authenticate(tag, diversified_key); 76 | 77 | printf("Authentication with default key: %s\n", res ? "fail" : "success (diversified)"); 78 | 79 | mifare_desfire_key_free(diversified_key); 80 | mifare_key_deriver_free(deriver); 81 | } else { 82 | printf("Authentication with default key: success\n"); 83 | } 84 | mifare_desfire_key_free(key); 85 | mifare_ultralight_disconnect(tag); 86 | } 87 | free(tag_uid); 88 | } 89 | 90 | freefare_free_tags(tags); 91 | nfc_close(device); 92 | } 93 | 94 | nfc_exit(context); 95 | exit(error); 96 | } 97 | -------------------------------------------------------------------------------- /examples/mifare-ultralightc-diversify.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | static int 10 | swap_keys(FreefareTag tag, MifareDESFireKey new_key, MifareDESFireKey old_key) 11 | { 12 | int res; 13 | res = mifare_ultralightc_authenticate(tag, old_key); 14 | MifareUltralightPage data; 15 | 16 | if (res != 0) { 17 | mifare_ultralight_disconnect(tag); 18 | mifare_ultralight_connect(tag); 19 | } 20 | 21 | return mifare_ultralightc_set_key(tag, new_key); 22 | } 23 | 24 | int 25 | main(int argc, char *argv[]) 26 | { 27 | int error = EXIT_SUCCESS; 28 | nfc_device *device = NULL; 29 | FreefareTag *tags = NULL; 30 | uint8_t key1_3des_data[16] = { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }; 31 | MifareDESFireKey master_key = mifare_desfire_3des_key_new(key1_3des_data); 32 | MifareDESFireKey derived_key = NULL; 33 | MifareKeyDeriver deriver = mifare_key_deriver_new_an10922(master_key, MIFARE_KEY_2K3DES, AN10922_FLAG_DEFAULT); 34 | bool undiversify = (argc == 2 && strcmp("--undiversify",argv[1]) == 0); 35 | 36 | if (argc > 2 || (argc == 2 && strcmp("--undiversify",argv[1]) != 0)) { 37 | errx(EXIT_FAILURE, "usage: %s [--undiversify]", argv[0]); 38 | } 39 | 40 | nfc_connstring devices[8]; 41 | size_t device_count; 42 | 43 | nfc_context *context; 44 | nfc_init(&context); 45 | if (context == NULL) 46 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 47 | 48 | device_count = nfc_list_devices(context, devices, sizeof(devices) / sizeof(*devices)); 49 | if (device_count <= 0) 50 | errx(EXIT_FAILURE, "No NFC device found"); 51 | 52 | for (size_t d = 0; d < device_count; d++) { 53 | if (!(device = nfc_open(context, devices[d]))) { 54 | warnx("nfc_open() failed."); 55 | error = EXIT_FAILURE; 56 | continue; 57 | } 58 | 59 | if (!(tags = freefare_get_tags(device))) { 60 | nfc_close(device); 61 | errx(EXIT_FAILURE, "Error listing tags."); 62 | } 63 | 64 | for (int i = 0; (!error) && tags[i]; i++) { 65 | int res; 66 | FreefareTag tag = tags[i]; 67 | char *tag_uid = freefare_get_tag_uid(tag); 68 | 69 | switch (freefare_get_tag_type(tag)) { 70 | case MIFARE_ULTRALIGHT_C: 71 | if (mifare_ultralight_connect(tag) < 0) { 72 | errx(EXIT_FAILURE, "Error connecting to tag %s.", tag_uid); 73 | } 74 | break; 75 | default: 76 | continue; 77 | } 78 | 79 | if (mifare_key_deriver_begin(deriver) < 0) { 80 | errx(EXIT_FAILURE, "Error starting key diversification"); 81 | } 82 | 83 | if (mifare_key_deriver_update_uid(deriver, tag) < 0) { 84 | errx(EXIT_FAILURE, "Error with key diversification"); 85 | } 86 | 87 | if ((derived_key = mifare_key_deriver_end(deriver)) == NULL) { 88 | errx(EXIT_FAILURE, "Error with key diversification"); 89 | } 90 | 91 | if (undiversify) { 92 | res = swap_keys(tag, master_key, derived_key); 93 | } else { 94 | res = swap_keys(tag, derived_key, master_key); 95 | } 96 | 97 | printf("%siversification of tag with UID %s %s.\n", undiversify?"Und":"D", tag_uid, res?"FAILED":"succeded"); 98 | 99 | mifare_desfire_key_free(derived_key); 100 | mifare_ultralight_disconnect(tag); 101 | free(tag_uid); 102 | } 103 | 104 | freefare_free_tags(tags); 105 | nfc_close(device); 106 | } 107 | 108 | mifare_desfire_key_free(master_key); 109 | mifare_key_deriver_free(deriver); 110 | nfc_exit(context); 111 | exit(error); 112 | } 113 | -------------------------------------------------------------------------------- /examples/ntag-detect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | int 9 | main(int argc, char *argv[]) 10 | { 11 | int error = EXIT_SUCCESS; 12 | nfc_device *device = NULL; 13 | FreefareTag *tags = NULL; 14 | 15 | if (argc > 1) 16 | errx(EXIT_FAILURE, "usage: %s", argv[0]); 17 | 18 | nfc_connstring devices[8]; 19 | size_t device_count; 20 | 21 | nfc_context *context; 22 | nfc_init(&context); 23 | if (context == NULL) 24 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 25 | 26 | device_count = nfc_list_devices(context, devices, sizeof(devices) / sizeof(*devices)); 27 | if (device_count <= 0) 28 | errx(EXIT_FAILURE, "No NFC device found"); 29 | 30 | for (size_t d = 0; d < device_count; d++) { 31 | if (!(device = nfc_open(context, devices[d]))) { 32 | warnx("nfc_open() failed."); 33 | error = EXIT_FAILURE; 34 | continue; 35 | } 36 | 37 | if (!(tags = freefare_get_tags(device))) { 38 | nfc_close(device); 39 | errx(EXIT_FAILURE, "Error listing tags."); 40 | } 41 | 42 | for (int i = 0; (!error) && tags[i]; i++) { 43 | char *tag_uid = freefare_get_tag_uid(tags[i]); 44 | printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name(tags[i])); 45 | free(tag_uid); 46 | } 47 | freefare_free_tags(tags); 48 | nfc_close(device); 49 | } 50 | nfc_exit(context); 51 | exit(error); 52 | } 53 | -------------------------------------------------------------------------------- /examples/ntag-removeauth.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | int 10 | main(int argc, char *argv[]) 11 | { 12 | int error = EXIT_SUCCESS; 13 | nfc_device *device = NULL; 14 | FreefareTag *tags = NULL; 15 | 16 | if (argc > 1) 17 | errx(EXIT_FAILURE, "usage: %s", argv[0]); 18 | 19 | nfc_connstring devices[8]; 20 | size_t device_count; 21 | 22 | nfc_context *context; 23 | nfc_init(&context); 24 | if (context == NULL) 25 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 26 | 27 | device_count = nfc_list_devices(context, devices, sizeof(devices) / sizeof(*devices)); 28 | if (device_count <= 0) 29 | errx(EXIT_FAILURE, "No NFC device found"); 30 | 31 | for (size_t d = 0; d < device_count; d++) { 32 | if (!(device = nfc_open(context, devices[d]))) { 33 | warnx("nfc_open() failed."); 34 | error = EXIT_FAILURE; 35 | continue; 36 | } 37 | 38 | if (!(tags = freefare_get_tags(device))) { 39 | nfc_close(device); 40 | errx(EXIT_FAILURE, "Error listing tags."); 41 | } 42 | 43 | for (int i = 0; (!error) && tags[i]; i++) { 44 | switch (freefare_get_tag_type(tags[i])) { 45 | case NTAG_21x: 46 | break; 47 | default: 48 | continue; 49 | } 50 | 51 | char *tag_uid = freefare_get_tag_uid(tags[i]); 52 | printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name(tags[i])); 53 | FreefareTag tag = tags[i]; 54 | int res; 55 | if (ntag21x_connect(tag) < 0) 56 | errx(EXIT_FAILURE, "Error connecting to tag."); 57 | 58 | uint8_t pwd[4] = {0xff, 0xff, 0xff, 0xff}; 59 | uint8_t pack[2] = {0xaa, 0xaa}; 60 | uint8_t pack_old[2] = {0x00, 0x00}; 61 | 62 | NTAG21xKey key; 63 | NTAG21xKey key_old; 64 | key = ntag21x_key_new(pwd, pack); // Creating key 65 | key_old = ntag21x_key_new(pwd, pack_old); // Creating key 66 | 67 | uint8_t auth0 = 0x00; // Buffer for auth0 byte 68 | 69 | switch (true) { 70 | case true: 71 | /* 72 | Get information about tag 73 | MUST do, because here we are recognizing tag subtype (NTAG213,NTAG215,NTAG216), and gathering all parameters 74 | */ 75 | res = ntag21x_get_info(tag); 76 | if (res < 0) { 77 | printf("Error getting info from tag\n"); 78 | break; 79 | } 80 | // Authenticate with tag 81 | res = ntag21x_authenticate(tag, key); 82 | if (res < 0) { 83 | printf("Error getting info from tag\n"); 84 | break; 85 | } 86 | // Get auth byte from tag 87 | res = ntag21x_get_auth(tag, &auth0); 88 | if (res < 0) { 89 | printf("Error getting auth0 byte from tag\n"); 90 | break; 91 | } 92 | printf("Old auth0: %#02x\n", auth0); 93 | // Set old key 94 | res = ntag21x_set_key(tag, key_old); 95 | if (res < 0) { 96 | printf("Error setting key tag\n"); 97 | break; 98 | } 99 | // Disable password protection (when auth0 byte > last page) 100 | res = ntag21x_set_auth(tag, 0xff); 101 | if (res < 0) { 102 | printf("Error setting auth0 byte \n"); 103 | break; 104 | } 105 | // Disable read & write pwd protection -> (default: write only protection) 106 | res = ntag21x_access_disable(tag, NTAG_PROT); 107 | if (res < 0) { 108 | printf("Error setting access byte \n"); 109 | break; 110 | } 111 | // Get auth byte from tag 112 | res = ntag21x_get_auth(tag, &auth0); 113 | if (res < 0) { 114 | printf("Error getting auth0 byte from tag\n"); 115 | break; 116 | } 117 | printf("New auth0: %#02x\n", auth0); 118 | } 119 | 120 | ntag21x_disconnect(tag); 121 | ntag21x_key_free(key); // Delete key 122 | ntag21x_key_free(key_old); // Delete key 123 | free(tag_uid); 124 | } 125 | freefare_free_tags(tags); 126 | nfc_close(device); 127 | } 128 | nfc_exit(context); 129 | exit(error); 130 | } 131 | -------------------------------------------------------------------------------- /examples/ntag-setauth.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | int 10 | main(int argc, char *argv[]) 11 | { 12 | int error = EXIT_SUCCESS; 13 | nfc_device *device = NULL; 14 | FreefareTag *tags = NULL; 15 | 16 | if (argc > 1) 17 | errx(EXIT_FAILURE, "usage: %s", argv[0]); 18 | 19 | nfc_connstring devices[8]; 20 | size_t device_count; 21 | 22 | nfc_context *context; 23 | nfc_init(&context); 24 | if (context == NULL) 25 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 26 | 27 | device_count = nfc_list_devices(context, devices, sizeof(devices) / sizeof(*devices)); 28 | if (device_count <= 0) 29 | errx(EXIT_FAILURE, "No NFC device found"); 30 | 31 | for (size_t d = 0; d < device_count; d++) { 32 | if (!(device = nfc_open(context, devices[d]))) { 33 | warnx("nfc_open() failed."); 34 | error = EXIT_FAILURE; 35 | continue; 36 | } 37 | 38 | if (!(tags = freefare_get_tags(device))) { 39 | nfc_close(device); 40 | errx(EXIT_FAILURE, "Error listing tags."); 41 | } 42 | 43 | for (int i = 0; (!error) && tags[i]; i++) { 44 | switch (freefare_get_tag_type(tags[i])) { 45 | case NTAG_21x: 46 | break; 47 | default: 48 | continue; 49 | } 50 | 51 | char *tag_uid = freefare_get_tag_uid(tags[i]); 52 | printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name(tags[i])); 53 | FreefareTag tag = tags[i]; 54 | int res; 55 | if (ntag21x_connect(tag) < 0) 56 | errx(EXIT_FAILURE, "Error connecting to tag."); 57 | 58 | uint8_t pwd[4] = {0xff, 0xff, 0xff, 0xff}; 59 | uint8_t pack[2] = {0xaa, 0xaa}; 60 | 61 | NTAG21xKey key; 62 | key = ntag21x_key_new(pwd, pack); // Creating key 63 | 64 | uint8_t auth0 = 0x00; // Buffer for auth0 byte 65 | uint8_t authlim = 0x00; 66 | switch (true) { 67 | case true: 68 | /* 69 | Get information about tag 70 | MUST do, because here we are recognizing tag subtype (NTAG213,NTAG215,NTAG216), and gathering all parameters 71 | */ 72 | res = ntag21x_get_info(tag); 73 | if (res < 0) { 74 | printf("Error getting info from tag\n"); 75 | break; 76 | } 77 | // Get auth byte from tag 78 | res = ntag21x_get_auth(tag, &auth0); 79 | if (res < 0) { 80 | printf("Error getting auth0 byte from tag\n"); 81 | break; 82 | } 83 | printf("Old auth0: %#02x\n", auth0); 84 | res = ntag21x_get_authentication_limit(tag, &authlim); 85 | if (res < 0) { 86 | printf("Error getting auth0 byte from tag\n"); 87 | break; 88 | } 89 | printf("Authlim: %#02x\n", authlim); 90 | // Check if auth is required to set pwd and pack 91 | if (auth0 < ntag21x_get_last_page(tag) - 2) { // Check if last 2 pages are protected 92 | printf("Error: pwd and PACK sections are protected with unknown password\n"); 93 | break; 94 | } 95 | // Set key 96 | res = ntag21x_set_key(tag, key); 97 | if (res < 0) { 98 | printf("Error setting key tag\n"); 99 | break; 100 | } 101 | // Protect last 6 pages !! It can be hacked if you don't protect last 4 pages where auth0 byte is located 102 | res = ntag21x_set_auth(tag, ntag21x_get_last_page(tag) - 5); 103 | if (res < 0) { 104 | printf("Error setting auth0 byte \n"); 105 | break; 106 | } 107 | // Enable read & write pwd protection (default: write only protection) 108 | res = ntag21x_access_enable(tag, NTAG_PROT); 109 | if (res < 0) { 110 | printf("Error setting access byte \n"); 111 | break; 112 | } 113 | // Get auth byte from tag 114 | res = ntag21x_get_auth(tag, &auth0); 115 | if (res < 0) { 116 | printf("Error getting auth0 byte from tag\n"); 117 | break; 118 | } 119 | printf("New auth0: %#02x\n", auth0); 120 | } 121 | ntag21x_disconnect(tag); 122 | ntag21x_key_free(key); // Delete key 123 | free(tag_uid); 124 | } 125 | freefare_free_tags(tags); 126 | nfc_close(device); 127 | } 128 | nfc_exit(context); 129 | exit(error); 130 | } 131 | -------------------------------------------------------------------------------- /examples/ntag-write.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | int 10 | main(int argc, char *argv[]) 11 | { 12 | int error = EXIT_SUCCESS; 13 | nfc_device *device = NULL; 14 | FreefareTag *tags = NULL; 15 | 16 | if (argc > 1) 17 | errx(EXIT_FAILURE, "usage: %s", argv[0]); 18 | 19 | nfc_connstring devices[8]; 20 | size_t device_count; 21 | 22 | nfc_context *context; 23 | nfc_init(&context); 24 | if (context == NULL) 25 | errx(EXIT_FAILURE, "Unable to init libnfc (malloc)"); 26 | 27 | device_count = nfc_list_devices(context, devices, sizeof(devices) / sizeof(*devices)); 28 | if (device_count <= 0) 29 | errx(EXIT_FAILURE, "No NFC device found"); 30 | 31 | for (size_t d = 0; d < device_count; d++) { 32 | if (!(device = nfc_open(context, devices[d]))) { 33 | warnx("nfc_open() failed."); 34 | error = EXIT_FAILURE; 35 | continue; 36 | } 37 | 38 | if (!(tags = freefare_get_tags(device))) { 39 | nfc_close(device); 40 | errx(EXIT_FAILURE, "Error listing tags."); 41 | } 42 | 43 | for (int i = 0; (!error) && tags[i]; i++) { 44 | switch (freefare_get_tag_type(tags[i])) { 45 | case NTAG_21x: 46 | break; 47 | default: 48 | continue; 49 | } 50 | 51 | char *tag_uid = freefare_get_tag_uid(tags[i]); 52 | printf("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name(tags[i])); 53 | FreefareTag tag = tags[i]; 54 | int res; 55 | if (ntag21x_connect(tag) < 0) 56 | errx(EXIT_FAILURE, "Error connecting to tag."); 57 | 58 | uint8_t data [4] = {0xfa, 0xca, 0xac, 0xad}; // Data to write on tag 59 | uint8_t read[4]; // Buffer for reading data from tag 60 | 61 | bool flag_match = true; 62 | switch (true) { 63 | case true: 64 | /* 65 | Get information about tag 66 | MUST do, because here we are recognizing tag subtype (NTAG213,NTAG215,NTAG216), and gathering all parameters 67 | */ 68 | res = ntag21x_get_info(tag); 69 | if (res < 0) { 70 | printf("Error getting info from tag\n"); 71 | break; 72 | } 73 | 74 | // writing to tag 4 bytes on page 0x27 (check specs for NTAG21x before changing page number !!!) 75 | res = ntag21x_write(tag, 0x27, data); 76 | if (res < 0) { 77 | printf("Error writing to tag\n"); 78 | break; 79 | } 80 | res = ntag21x_fast_read4(tag, 0x27, read); // Reading page from tag (4 bytes), you can also use ntag21x_read4 or ntag21x_read (16 bytes) or ntag21x_fast_read (start_page to end_page) 81 | if (res < 0) { 82 | printf("Error reading tag\n"); 83 | break; 84 | } 85 | for (int i = 0; i < 4; i++) // Checking if we can read what we have written earlyer 86 | if (data[i] != read[i]) { 87 | flag_match = false; 88 | break; 89 | } 90 | if (!flag_match) 91 | printf("Data don't match\n"); 92 | else 93 | printf("Data match\n"); 94 | } 95 | ntag21x_disconnect(tag); 96 | free(tag_uid); 97 | } 98 | freefare_free_tags(tags); 99 | nfc_close(device); 100 | } 101 | nfc_exit(context); 102 | exit(error); 103 | } 104 | -------------------------------------------------------------------------------- /libfreefare.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libfreefare 7 | Description: MIFARE contactless tag access library 8 | Version: @VERSION@ 9 | URL: http://code.google.com/p/nfc-tools 10 | Requires: @PKG_CONFIG_REQUIRES@ 11 | Libs: -L${libdir} -lfreefare 12 | Cflags: -I${includedir} 13 | -------------------------------------------------------------------------------- /libfreefare/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LIBRARY_SOURCES 2 | felica 3 | freefare 4 | freefare_internal 5 | mad 6 | mifare_application 7 | mifare_classic 8 | mifare_desfire 9 | mifare_desfire_aid 10 | mifare_desfire_crypto 11 | mifare_desfire_error 12 | mifare_desfire_key 13 | mifare_key_deriver 14 | mifare_ultralight 15 | ntag21x 16 | ntag21x_error 17 | tlv 18 | ../contrib/libutil/hexdump 19 | ) 20 | 21 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 22 | 23 | add_library(freefare SHARED ${LIBRARY_SOURCES}) 24 | target_link_libraries(freefare ${LIBS}) 25 | 26 | set(installheaders freefare.h) 27 | install(FILES ${installheaders} DESTINATION ${INCLUDE_INSTALL_DIR}/freefare COMPONENT headers) 28 | 29 | if(WIN32) 30 | # On Windows the shared (runtime) library should be either in the same 31 | # directory as the excutables or in the path, we add it to same directory 32 | install(TARGETS freefare RUNTIME DESTINATION bin COMPONENT libraries) 33 | 34 | # At compile time we need the .LIB file, we place it in the lib directory 35 | install(TARGETS freefare ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT headers) 36 | else(WIN32) 37 | install(TARGETS freefare LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) 38 | endif(WIN32) 39 | -------------------------------------------------------------------------------- /libfreefare/felica.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This implementation was written based on information provided by the 3 | * following documents: 4 | * 5 | * FeliCa Lite User's Manual 6 | * Version 1.2 7 | * No. M624-E01-20 8 | */ 9 | 10 | #if defined(HAVE_CONFIG_H) 11 | #include "config.h" 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #ifdef WITH_DEBUG 22 | #include 23 | #endif 24 | 25 | #include 26 | #include "freefare_internal.h" 27 | 28 | #define MAX_BLOCK_COUNT 8 29 | 30 | inline static 31 | ssize_t felica_transceive(FreefareTag tag, uint8_t *data_in, uint8_t *data_out, size_t data_out_length) 32 | { 33 | DEBUG_XFER(data_in, data_in[0], "===> "); 34 | ssize_t res = nfc_initiator_transceive_bytes(tag->device, data_in, data_in[0], data_out, data_out_length, 0); 35 | DEBUG_XFER(data_out, res, "<=== "); 36 | return res; 37 | } 38 | 39 | bool 40 | felica_taste(nfc_device *device, nfc_target target) 41 | { 42 | (void) device; 43 | return target.nm.nmt == NMT_FELICA; 44 | } 45 | 46 | FreefareTag 47 | felica_tag_new(nfc_device *device, nfc_target target) 48 | { 49 | FreefareTag tag; 50 | 51 | if ((tag = malloc(sizeof(struct felica_tag)))) { 52 | tag->type = FELICA; 53 | tag->free_tag = felica_tag_free; 54 | tag->device = device; 55 | tag->info = target; 56 | tag->active = 0; 57 | } 58 | 59 | return tag; 60 | } 61 | 62 | void 63 | felica_tag_free(FreefareTag tag) 64 | { 65 | free(tag); 66 | } 67 | 68 | 69 | 70 | ssize_t 71 | felica_read_ex(FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length) 72 | { 73 | assert(block_count <= MAX_BLOCK_COUNT); 74 | assert(length == 16 * block_count); 75 | 76 | DEBUG_FUNCTION(); 77 | 78 | uint8_t cmd[1 + 1 + 8 + 1 + 2 + 1 + 2 * MAX_BLOCK_COUNT] = { 79 | 0x00, /* Length */ 80 | 0x06, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 | 0x01, 83 | 0x00, 0x00, /* Service */ 84 | 0x00, 85 | /* Block ... */ 86 | }; 87 | 88 | uint8_t res[100]; 89 | 90 | cmd[0] = 14 + 2 * block_count; 91 | memcpy(cmd + 2, tag->info.nti.nfi.abtId, 8); 92 | cmd[11] = service; 93 | cmd[12] = service >> 8; 94 | cmd[13] = block_count; 95 | 96 | for (int i = 0; i < block_count; i++) { 97 | cmd[14 + 2 * i] = 0x80; 98 | cmd[14 + 2 * i + 1] = blocks[i]; 99 | } 100 | 101 | int cnt = felica_transceive(tag, cmd, res, sizeof(res)); 102 | if (cnt != 1 + 1 + 8 + 1 + 1 + 1 + 16 * block_count) { 103 | return -1; 104 | } 105 | size_t len = MIN(res[12] * 16, length); 106 | memcpy(data, res + 13, len); 107 | 108 | return len; 109 | } 110 | 111 | ssize_t 112 | felica_read(FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length) 113 | { 114 | uint8_t blocks[] = { 115 | block 116 | }; 117 | 118 | return felica_read_ex(tag, service, 1, blocks, data, length); 119 | } 120 | 121 | ssize_t 122 | felica_write_ex(FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length) 123 | { 124 | DEBUG_FUNCTION(); 125 | 126 | assert(block_count <= MAX_BLOCK_COUNT); 127 | assert(length == 16 * block_count); 128 | 129 | uint8_t cmd[1 + 1 + 8 + 1 + 2 + 1 + 2 + 16 * MAX_BLOCK_COUNT] = { 130 | 0x00, /* Length */ 131 | 0x08, 132 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 133 | 0x01, 134 | 0x00, 0x00, /* Service */ 135 | 0x00, 136 | /* Block ... */ 137 | /* n * 16 */ 138 | }; 139 | 140 | uint8_t res[12]; 141 | 142 | cmd[0] = 1 + 1 + 8 + 1 + 2 * 1 + 1 + 2 * 1 + 16 * block_count; 143 | memcpy(cmd + 2, tag->info.nti.nfi.abtId, 8); 144 | cmd[11] = service; 145 | cmd[12] = service >> 8; 146 | cmd[13] = block_count; 147 | 148 | for (int i = 0; i < block_count; i++) { 149 | cmd[14 + 2 * i] = 0x80; 150 | cmd[14 + 2 * i + 1] = blocks[i]; 151 | } 152 | 153 | memcpy(cmd + 14 + 2 * block_count, data, length); 154 | 155 | ssize_t cnt = felica_transceive(tag, cmd, res, sizeof(res)); 156 | 157 | if (cnt != sizeof(res)) 158 | return -1; 159 | 160 | return res[10] == 0 ? 0 : -1; 161 | } 162 | 163 | ssize_t 164 | felica_write(FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length) 165 | { 166 | uint8_t blocks[] = { 167 | block 168 | }; 169 | 170 | return felica_write_ex(tag, service, 1, blocks, data, length); 171 | } 172 | -------------------------------------------------------------------------------- /libfreefare/freefare.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010 Romain Tartiere 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd March 30, 2010 17 | .Dt FREEFARE 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm freefare_get_tags , 27 | .Nm freefare_get_tag_type , 28 | .Nm freefare_get_tag_friendly_name , 29 | .Nm freefare_get_tag_uid , 30 | .Nm freefare_set_tag_timeout , 31 | .Nm freefare_free_tag , 32 | .Nm freefare_free_tags , 33 | .Nm freefare_version 34 | .Nd Generic target manipulation functions 35 | .\" _ _ _ 36 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 37 | .\" | | | | '_ \| '__/ _` | '__| | | | 38 | .\" | |___| | |_) | | | (_| | | | |_| | 39 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 40 | .\" |___/ 41 | .Sh LIBRARY 42 | Mifare card manipulation library (libfreefare, \-lfreefare) 43 | .\" ____ _ 44 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 45 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 46 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 47 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 48 | .\" |___/ |_| 49 | .Sh SYNOPSIS 50 | .In freefare.h 51 | .Ft "FreefareTag *" 52 | .Fn freefare_get_tags "nfc_device_t *device" 53 | .Bd -literal 54 | enum freefare_tag_type { 55 | FELICA, 56 | MIFARE_MINI 57 | MIFARE_CLASSIC_1K, 58 | MIFARE_CLASSIC_4K, 59 | MIFARE_DESFIRE, 60 | MIFARE_ULTRALIGHT, 61 | MIFARE_ULTRALIGHT_C, 62 | }; 63 | .Ed 64 | .Ft "enum freefare_tag_type" 65 | .Fn freefare_get_tag_type "FreefareTag tag" 66 | .Ft "const char *" 67 | .Fn freefare_get_tag_friendly_name "FreefareTag tag" 68 | .Ft "char *" 69 | .Fn freefare_get_tag_uid "FreefareTag tag" 70 | .Ft "void" 71 | .Fn freefare_set_tag_timeout "FreefareTag tag" "int timeout" 72 | .Ft "void" 73 | .Fn freefare_free_tag "FreefareTag tags" 74 | .Ft "void" 75 | .Fn freefare_free_tags "FreefareTag *tags" 76 | .Ft "const char *" 77 | .Fn freefare_version 78 | .\" ____ _ _ _ 79 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 80 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 81 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 82 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 83 | .\" |_| 84 | .Sh DESCRIPTION 85 | The 86 | .Fn freefare_* 87 | family of functions allow agnostic access to the 88 | .Vt FreefareTag 89 | present on a given NFC device. 90 | .Pp 91 | .Fn freefare_get_tags 92 | returns a NULL-terminated list of 93 | .Vt FreefareTag 94 | present on 95 | .Vt device . 96 | This list has to be freed after usage by either: 97 | .Bl -hyphen 98 | .It 99 | calling the 100 | .Fn freefare_free_tags 101 | function. All tags in the list are automatically freed; 102 | .It 103 | calling the 104 | .Fn freefare_free_tag 105 | function to free each tag in the list individually, and freeing the list itself 106 | using the 107 | .Fn free 108 | function. 109 | .El 110 | .Pp 111 | Because of the nature of the target detection process, any previously detected 112 | target will be in an inconsistent state after a call to 113 | .Fn freefare_get_tags . 114 | It is the programmer's responsibility to free these targets before calling the 115 | .Fn freefare_get_tags 116 | function. 117 | .Pp 118 | Information about a given 119 | .Vt FreefareTag 120 | can be gathered using the 121 | .Fn freefare_get_tag_type , 122 | .Fn freefare_get_tag_uid 123 | and 124 | .Fn freefare_get_tag_friendly_name 125 | functions. 126 | .Pp 127 | The 128 | .Fn freefare_set_tag_timeout 129 | function is used to set the maximum duration for a single NFC operation to 130 | .Fa timeout 131 | mili-seconds. Setting 132 | .Fa timeout 133 | to 0 disables the timeout feature. By default, a timeout of 2000 is configured. 134 | .Fn freefare_version 135 | function returns the version of the library. 136 | .\" ____ _ _ 137 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 138 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 139 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 140 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 141 | .\" 142 | .Sh RETURN VALUES 143 | Unless stated otherwise, all functions return a value greater than or equal to 144 | .Va 0 145 | on success or 146 | .Va -1 147 | on failure. 148 | .\" ____ _ 149 | .\" / ___| ___ ___ __ _| |___ ___ 150 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 151 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 152 | .\" |____/ \___|\___| \__,_|_|___/\___/ 153 | .\" 154 | .Sh SEE ALSO 155 | .Xr free 3 , 156 | .Xr mifare_classic 3 , 157 | .Xr mifare_ultralight 3 158 | .\" _ _ _ 159 | .\" / \ _ _| |_| |__ ___ _ __ ___ 160 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 161 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 162 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 163 | .\" 164 | .Sh AUTHORS 165 | .An Romain Tartiere Aq romain@blogreen.org 166 | .An Romuald Conty Aq romuald@libnfc.org 167 | -------------------------------------------------------------------------------- /libfreefare/freefare_error.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010 Romain Tartiere 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd September 28, 2010 17 | .Dt FREEFARE_ERROR 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm freefare_strerror , 27 | .Nm freefare_strerror_r , 28 | .Nm freefare_perror , 29 | .Nm mifare_desfire_last_picc_error 30 | .Nd Error Reporting Functions. 31 | .\" _ _ _ 32 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 33 | .\" | | | | '_ \| '__/ _` | '__| | | | 34 | .\" | |___| | |_) | | | (_| | | | |_| | 35 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 36 | .\" |___/ 37 | .Sh LIBRARY 38 | Mifare card manipulation library (libfreefare, \-lfreefare) 39 | .\" ____ _ 40 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 41 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 42 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 43 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 44 | .\" |___/ |_| 45 | .Sh SYNOPSIS 46 | .In freefare.h 47 | .Ft "const char *" 48 | .Fn freefare_strerror "FreefareTag tag" 49 | .Ft "int" 50 | .Fn freefare_strerror_r "FreefareTag tag" "char *buffer" "size_t len" 51 | .Ft "void" 52 | .Fn freefare_strerror "FreefareTag tag" "char *string" 53 | .Ft "uint8_t" 54 | .Fn mifare_desfire_last_pcd_error "FreefareTag tag" 55 | .Ft "uint8_t" 56 | .Fn mifare_desfire_last_picc_error "FreefareTag tag" 57 | .\" ____ _ _ _ 58 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 59 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 60 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 61 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 62 | .\" |_| 63 | .Sh DESCRIPTION 64 | The 65 | .Fn freefare_strerror 66 | functions returns the error string corresponding to the last PCD or PICC error 67 | encounred using 68 | .Vt tag . 69 | .Pp 70 | The 71 | .Fn freefare_strerror_r 72 | functions does the same as 73 | .Fn freefare_strerror 74 | but the error message is copied into 75 | .Vt buffer 76 | for a maximum size of 77 | .Vt len 78 | chars. 79 | .Pp 80 | The 81 | .Fn freefare_strerror 82 | function displays the last PCD or PICC error encounred using 83 | .Vt tag 84 | to stderr. 85 | .Pp 86 | The 87 | .Fn mifare_desfire_last_pcd_error 88 | function returns the error code of the last function call from the library. 89 | .Pp 90 | The 91 | .Fn mifare_desfire_last_picc_error 92 | function returns the error code returned by the last command run on 93 | .Vt tag . 94 | .\" ____ _ _ 95 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 96 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 97 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 98 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 99 | .\" 100 | .Sh RETURN VALUES 101 | .Fn freefare_strerror 102 | returns the error message, 103 | .Fn freefare_strerror_r 104 | returns 0 on success, \-1 on failure; 105 | .Fn mifare_desfire_last_pcd_error 106 | and 107 | .Fn mifare_desfire_last_picc_error 108 | return an error code or 0 if no error occured or if 109 | .Vt tag 110 | is not a Mifare DESFire target. 111 | .\" ____ _ 112 | .\" / ___| ___ ___ __ _| |___ ___ 113 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 114 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 115 | .\" |____/ \___|\___| \__,_|_|___/\___/ 116 | .\" 117 | .Sh SEE ALSO 118 | .Xr freefare 3 , 119 | .\" _ _ _ 120 | .\" / \ _ _| |_| |__ ___ _ __ ___ 121 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 122 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 123 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 124 | .\" 125 | .Sh AUTHORS 126 | .An Romain Tartiere Aq romain@il4p.org 127 | -------------------------------------------------------------------------------- /libfreefare/mad.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010 Romain Tartiere 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd March 30, 2010 17 | .Dt MAD 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm mad_new , 27 | .Nm mad_read , 28 | .Nm mad_write , 29 | .Nm mad_get_version , 30 | .Nm mad_set_version , 31 | .Nm mad_get_card_publisher_sector , 32 | .Nm mad_set_card_publisher_sector , 33 | .Nm mad_get_aid , 34 | .Nm mad_set_aid , 35 | .Nm mad_free , 36 | .Nd "Mifare Application Directory (MAD) Manipulation Functions" 37 | .\" _ _ _ 38 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 39 | .\" | | | | '_ \| '__/ _` | '__| | | | 40 | .\" | |___| | |_) | | | (_| | | | |_| | 41 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 42 | .\" |___/ 43 | .Sh LIBRARY 44 | Mifare card manipulation library (libfreefare, \-lfreefare) 45 | .\" ____ _ 46 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 47 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 48 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 49 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 50 | .\" |___/ |_| 51 | .Sh SYNOPSIS 52 | .In freefare.h 53 | .Ft "Mad" 54 | .Fn mad_new "uint8_t version" 55 | .Ft "Mad" 56 | .Fn mad_read "FreefareTag tag" 57 | .Ft "int" 58 | .Fn mad_write "FreefareTag tag" "Mad mad" "MifareClassicKey key_b_sector_00" "MifareClassicKey key_b_sector_10" 59 | .Ft "int" 60 | .Fn mad_get_version "Mad mad" 61 | .Ft "void" 62 | .Fn mad_set_version "Mad mad" "uint8_t version" 63 | .Ft "MifareClassicSectorNumber" 64 | .Fn mad_get_card_publisher_sector "Mad mad" 65 | .Ft "int" 66 | .Fn mad_set_card_publisher_sector "Mad mad" "MifareClassicSectorNumber cps" 67 | .Ft "int" 68 | .Fn mad_get_aid "Mad mad" "MifareClassicSectorNumber sector" "MadAid *aid" 69 | .Ft "int" 70 | .Fn mad_set_aid "Mad mad" "MifareClassicSectorNumber sector" "MadAid aid" 71 | .Ft "void" 72 | .Fn mad_free "Mad mad" 73 | .\" ____ _ _ _ 74 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 75 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 76 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 77 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 78 | .\" |_| 79 | .Sh DESCRIPTION 80 | Mifare Application Directories (MAD) can be easily manipulated using the 81 | .Fn mad_* 82 | set of functions. 83 | .Pp 84 | A 85 | .Vt mad 86 | can be loaded form a Mifare Classic 87 | .Vt tag 88 | using 89 | .Fn mad_read 90 | or generated from scratch using 91 | .Fn mad_new 92 | and providing the 93 | .Vt version 94 | of the 95 | .Vt mad 96 | to generate. After using a 97 | .Vt mad , 98 | the memory can be reclaimed using 99 | .Fn mad_free . 100 | .Pp 101 | A 102 | .Vt mad 103 | can be written to a Mifare Classic 104 | .Vt tag 105 | using 106 | .Fn mad_write 107 | and providing the B keys required for writing to sectors 0, 108 | .Vt key_b_sector_00, 109 | and the one required for writing to sectors 10, 110 | .Vt key_b_sector_10 . 111 | When writing a MAD version 1 112 | .Vt mad , 113 | the 114 | .Vt key_b_sector_10 . 115 | .Pp 116 | The 117 | .Vt version 118 | of a MAD 119 | .Vt mad 120 | can be read using 121 | .Fn mad_get_version 122 | and changed using 123 | .Fn mad_set_version . 124 | .Pp 125 | The card publisher sector number 126 | .Vt cps 127 | can be read read using 128 | .Fn mad_get_card_publisher_sector 129 | and writen using 130 | .Fn mad_set_card_publisher_sector . 131 | .Pp 132 | Sectors allocation in the 133 | .Vt mad 134 | is handled by the 135 | .Fn mad_get_aid 136 | and 137 | .Fn mad_set_aid 138 | functions. These functions fill-in or read the Application Identifier, 139 | .Vt aid 140 | for the given 141 | .Vt sector . 142 | .\" ___ _ _ _ _ _ 143 | .\" |_ _|_ __ ___ _ __ | | ___ _ __ ___ ___ _ __ | |_ __ _| |_(_) ___ _ __ _ __ ___ | |_ ___ ___ 144 | .\" | || '_ ` _ \| '_ \| |/ _ \ '_ ` _ \ / _ \ '_ \| __/ _` | __| |/ _ \| '_ \ | '_ \ / _ \| __/ _ \/ __| 145 | .\" | || | | | | | |_) | | __/ | | | | | __/ | | | || (_| | |_| | (_) | | | | | | | | (_) | || __/\__ \ 146 | .\" |___|_| |_| |_| .__/|_|\___|_| |_| |_|\___|_| |_|\__\__,_|\__|_|\___/|_| |_| |_| |_|\___/ \__\___||___/ 147 | .\" |_| 148 | .\".Sh IMPLEMENTATION NOTES 149 | .\" ____ _ _ 150 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 151 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 152 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 153 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 154 | .\" 155 | .Sh RETURN VALUES 156 | The 157 | .Fn mad_new 158 | function return 159 | .Va NULL 160 | on failure and allocates memory that has to be freed using 161 | .Fn mad_free 162 | on success. 163 | Unless stated otherwise, all other functions return a value greater than or equal to 164 | .Va 0 165 | on success or 166 | .Va -1 167 | on failure. 168 | .\" ____ _ 169 | .\" / ___| ___ ___ __ _| |___ ___ 170 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 171 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 172 | .\" |____/ \___|\___| \__,_|_|___/\___/ 173 | .\" 174 | .Sh SEE ALSO 175 | .Xr freefare 3 , 176 | .Xr mifare_application 3 , 177 | .Xr mifare_classic 3 178 | .\" _ _ _ 179 | .\" / \ _ _| |_| |__ ___ _ __ ___ 180 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 181 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 182 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 183 | .\" 184 | .Sh AUTHORS 185 | .An Romain Tartiere Aq romain@blogreen.org 186 | .An Romuald Conty Aq romuald@libnfc.org 187 | -------------------------------------------------------------------------------- /libfreefare/mifare_application.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010 Romain Tartiere 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd March 30, 2010 17 | .Dt MIFARE_APPLICATION 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm mifare_application_alloc , 27 | .Nm mifare_application_find , 28 | .Nm mifare_application_free , 29 | .Nm mifare_application_read , 30 | .Nm mifare_application_write 31 | .Nd Mifare Applications Manipulation Functions 32 | .\" _ _ _ 33 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 34 | .\" | | | | '_ \| '__/ _` | '__| | | | 35 | .\" | |___| | |_) | | | (_| | | | |_| | 36 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 37 | .\" |___/ 38 | .Sh LIBRARY 39 | Mifare card manipulation library (libfreefare, \-lfreefare) 40 | .\" ____ _ 41 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 42 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 43 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 44 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 45 | .\" |___/ |_| 46 | .Sh SYNOPSIS 47 | .In freefare.h 48 | .Ft "MifareClassicSectorNumber *" 49 | .Fn mifare_application_alloc "Mad mad" "MadAid aid" "size_t size" 50 | .Ft "void" 51 | .Fn mifare_application_free "Mad mad" "MadAid aid" 52 | .Ft "MifareClassicSectorNumber *" 53 | .Fn mifare_application_find "Mad mad" "MadAid aid" 54 | .Ft "ssize_t" 55 | .Fn mifare_application_read "FreefareTag tag" "Mad mad" "MadAid aid" "void *buf" "size_t nbytes" "MifareClassicKey key" "MifareClassicKeyType key_type" 56 | .Ft "ssize_t" 57 | .Fn mifare_application_write "FreefareTag tag" "Mad mad" "MadAid aid" "const void *buf" "size_t nbytes" "MifareClassicKey key" "MifareClassicKeyType key_type" 58 | .\" ____ _ _ _ 59 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 60 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 61 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 62 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 63 | .\" |_| 64 | .Sh DESCRIPTION 65 | The 66 | .Fn mifare_application_* 67 | functions facilitate management of applications in a Mifare Application 68 | Directory. 69 | .Pp 70 | The 71 | .Fn mifare_application_alloc 72 | function allocates enought sectors to store 73 | .Vt size 74 | bytes for the Application Identifier 75 | .Vt aid 76 | and returns the list of allocated sectors. 77 | .Pp 78 | The list of the sectors previously allocated for 79 | .Vt aid 80 | in a 81 | .Vt mad 82 | can be requested using 83 | .Fn mifare_application_find . 84 | .Pp 85 | An application can be removed from a 86 | .Vt mad 87 | using 88 | .Fn mifare_application_free . 89 | .Pp 90 | The 91 | .Fn mifare_application_read 92 | reads at most 93 | .Vt nbytes 94 | of the application identified by 95 | .Vt aid 96 | in the 97 | .Vt mad 98 | on the 99 | .Vt tag 100 | and copy them into 101 | .Vt buf. 102 | The function returns the amount of data it copied, or \-1 on error. 103 | .Pp 104 | The 105 | .Fn mifare_application_write 106 | functions writes at most 107 | .Vt nbytes 108 | of 109 | .Vt buf 110 | in the application identified by 111 | .Vt aid 112 | on the 113 | .Vt mad 114 | of the 115 | .Vt tag 116 | and returns the quantity of data written, or \-1 on error. 117 | .\" ___ _ _ _ _ _ 118 | .\" |_ _|_ __ ___ _ __ | | ___ _ __ ___ ___ _ __ | |_ __ _| |_(_) ___ _ __ _ __ ___ | |_ ___ ___ 119 | .\" | || '_ ` _ \| '_ \| |/ _ \ '_ ` _ \ / _ \ '_ \| __/ _` | __| |/ _ \| '_ \ | '_ \ / _ \| __/ _ \/ __| 120 | .\" | || | | | | | |_) | | __/ | | | | | __/ | | | || (_| | |_| | (_) | | | | | | | | (_) | || __/\__ \ 121 | .\" |___|_| |_| |_| .__/|_|\___|_| |_| |_|\___|_| |_|\__\__,_|\__|_|\___/|_| |_| |_| |_|\___/ \__\___||___/ 122 | .\" |_| 123 | .Sh IMPLEMENTATION NOTES 124 | The 125 | .Fn mifare_application_alloc 126 | function will try to avoid wasting space and might not allocate sectors 127 | sequentially if a large amount of space is requested and the target has sectors 128 | of different size. 129 | .Pp 130 | The 131 | .Vt nbytes 132 | argument of 133 | .Fn mifare_application_read 134 | and 135 | .Fn mifare_application_write 136 | does not need to be aligned on blocks not sectors. 137 | .\" ____ _ _ 138 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 139 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 140 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 141 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 142 | .\" 143 | .Sh RETURN VALUES 144 | Unless stated otherwise, all functions return a value greater than or equal to 145 | .Va 0 146 | on success or 147 | .Va -1 148 | on failure. 149 | .\" ____ _ 150 | .\" / ___| ___ ___ __ _| |___ ___ 151 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 152 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 153 | .\" |____/ \___|\___| \__,_|_|___/\___/ 154 | .\" 155 | .Sh SEE ALSO 156 | .Xr mad 3 , 157 | .Xr mifare_classic 3 158 | .\" _ _ _ 159 | .\" / \ _ _| |_| |__ ___ _ __ ___ 160 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 161 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 162 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 163 | .\" 164 | .Sh AUTHORS 165 | .An Romain Tartiere Aq romain@blogreen.org 166 | .An Romuald Conty Aq romuald@libnfc.org 167 | -------------------------------------------------------------------------------- /libfreefare/mifare_desfire_aid.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010 Romain Tartiere 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd September 3, 2010 17 | .Dt MIFARE_DESFIRE_AID 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm mifare_desfire_aid_new , 27 | .Nm mifare_desfire_aid_new_with_mad_aid , 28 | .Nm mifare_desfire_aid_get_aid 29 | .Nd Mifare DESFire AID Manipulation Functions 30 | .\" _ _ _ 31 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 32 | .\" | | | | '_ \| '__/ _` | '__| | | | 33 | .\" | |___| | |_) | | | (_| | | | |_| | 34 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 35 | .\" |___/ 36 | .Sh LIBRARY 37 | Mifare card manipulation library (libfreefare, \-lfreefare) 38 | .\" ____ _ 39 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 40 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 41 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 42 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 43 | .\" |___/ |_| 44 | .Sh SYNOPSIS 45 | .In freefare.h 46 | .Ft MifareDESFireAID 47 | .Fn mifare_desfire_aid_new "uint32_t aid" 48 | .Ft MifareDESFireAID 49 | .Fn mifare_desfire_aid_new_with_mad_aid "MadAid mad_aid" "uint8_t n" 50 | .Ft uint32_t 51 | .Fn mifare_desfire_aid_get_aid "MifareDESFireAID aid" 52 | .\" ____ _ _ _ 53 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 54 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 55 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 56 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 57 | .\" |_| 58 | .Sh DESCRIPTION 59 | The 60 | .Fn mifare_desfire_aid_* 61 | functions allows management of Mifare DESFire AIDs. The 62 | .Fn mifare_desfire_aid_new 63 | function returns a new Mifare DESFire AID of value 64 | .Vt aid . 65 | .Pp 66 | The 67 | .Fn mifare_desfire_aid_new_with_mad_aid 68 | functions returns a new Mifare DESFire AID using a Mifare Classic AID 69 | .Vt mad_aid 70 | and 71 | .Vt n 72 | as the last nibble of the new AID. 73 | .Pp 74 | Both 75 | .Fn mifare_desfire_aid_new 76 | and 77 | .Fn mifare_desfire_aid_new_with_mad_aid 78 | allocates memory that should be reclaimed using 79 | .Xr free 3 . 80 | .Pp 81 | The 82 | .Fn mifare_desfire_aid_get_aid 83 | function returns the 84 | .Vt aid 85 | of the provided Mifare DESFire AID. 86 | .\" ____ _ _ 87 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 88 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 89 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 90 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 91 | .\" 92 | .Sh RETURN VALUES 93 | The allocation functions returns the allocated AID on success, 94 | .Va NULL 95 | otherwise. 96 | .\" ____ _ 97 | .\" / ___| ___ ___ __ _| |___ ___ 98 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 99 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 100 | .\" |____/ \___|\___| \__,_|_|___/\___/ 101 | .\" 102 | .Sh SEE ALSO 103 | .Xr freefare 3 , 104 | .Xr mifare_classic 3 , 105 | .Xr free 3 106 | .\" _ _ _ 107 | .\" / \ _ _| |_| |__ ___ _ __ ___ 108 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 109 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 110 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 111 | .\" 112 | .Sh AUTHORS 113 | .An Romain Tartiere Aq romain@il4p.org 114 | -------------------------------------------------------------------------------- /libfreefare/mifare_desfire_aid.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This implementation was written based on information provided by the 3 | * following document: 4 | * 5 | * Mifare DESFire Specification by LASSeO 6 | * Version 1.0 - 29'th September 2009 7 | * http://www.scnf.org.uk/smartstore/LASSeO%20docs/DESFIRE%20Specification%20V1%200.pdf 8 | */ 9 | 10 | #if defined(HAVE_CONFIG_H) 11 | #include "config.h" 12 | #endif 13 | 14 | #if defined(HAVE_SYS_TYPES_H) 15 | #include 16 | #endif 17 | 18 | #if defined(HAVE_SYS_ENDIAN_H) 19 | #include 20 | #endif 21 | 22 | #if defined(HAVE_ENDIAN_H) 23 | #include 24 | #endif 25 | 26 | #if defined(HAVE_COREFOUNDATION_COREFOUNDATION_H) 27 | #include 28 | #endif 29 | 30 | #if defined(HAVE_BYTESWAP_H) 31 | #include 32 | #endif 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include "freefare_internal.h" 40 | 41 | // Theorically, it should be an uint24_t ... 42 | MifareDESFireAID 43 | mifare_desfire_aid_new(uint32_t aid) 44 | { 45 | if (aid > 0x00ffffff) 46 | return errno = EINVAL, NULL; 47 | 48 | MifareDESFireAID res; 49 | uint32_t aid_le = htole32(aid); 50 | 51 | if ((res = malloc(sizeof(*res)))) { 52 | memcpy(res->data, ((uint8_t *)&aid_le), 3); 53 | } 54 | 55 | return res; 56 | } 57 | 58 | // This function ease the MifareDESFireAID creation using a Mifare Classic AID (see MIFARE Application Directory document - section 3.10 MAD and MIFARE DESFire) 59 | MifareDESFireAID 60 | mifare_desfire_aid_new_with_mad_aid(MadAid mad_aid, uint8_t n) 61 | { 62 | if (n > 0x0f) 63 | return errno = EINVAL, NULL; 64 | 65 | return mifare_desfire_aid_new(0xf00000 | (mad_aid.function_cluster_code << 12) | (mad_aid.application_code << 4) | n); 66 | } 67 | 68 | uint32_t 69 | mifare_desfire_aid_get_aid(MifareDESFireAID aid) 70 | { 71 | return aid->data[0] | (aid->data[1] << 8) | (aid->data[2] << 16); 72 | } 73 | -------------------------------------------------------------------------------- /libfreefare/mifare_desfire_error.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "freefare_internal.h" 8 | 9 | #define EM(e) { e, #e } 10 | 11 | static struct error_message { 12 | uint8_t code; 13 | const char *message; 14 | } error_messages[] = { 15 | EM(OPERATION_OK), 16 | EM(NO_CHANGES), 17 | EM(OUT_OF_EEPROM_ERROR), 18 | EM(ILLEGAL_COMMAND_CODE), 19 | EM(INTEGRITY_ERROR), 20 | EM(NO_SUCH_KEY), 21 | EM(LENGTH_ERROR), 22 | EM(PERMISSION_ERROR), 23 | EM(PARAMETER_ERROR), 24 | EM(APPLICATION_NOT_FOUND), 25 | EM(APPL_INTEGRITY_ERROR), 26 | EM(AUTHENTICATION_ERROR), 27 | EM(ADDITIONAL_FRAME), 28 | EM(BOUNDARY_ERROR), 29 | EM(PICC_INTEGRITY_ERROR), 30 | EM(COMMAND_ABORTED), 31 | EM(PICC_DISABLED_ERROR), 32 | EM(COUNT_ERROR), 33 | EM(DUPLICATE_ERROR), 34 | EM(EEPROM_ERROR), 35 | EM(FILE_NOT_FOUND), 36 | EM(FILE_INTEGRITY_ERROR), 37 | EM(CRYPTO_ERROR), 38 | { 0, NULL } 39 | }; 40 | 41 | const char * 42 | mifare_desfire_error_lookup(uint8_t code) 43 | { 44 | struct error_message *e = error_messages; 45 | while (e->message) { 46 | if (e->code == code) 47 | return (e->message); 48 | e++; 49 | } 50 | 51 | return "Invalid error code"; 52 | } 53 | 54 | uint8_t 55 | mifare_desfire_last_pcd_error(FreefareTag tag) 56 | { 57 | if (tag->type != MIFARE_DESFIRE) 58 | return 0; 59 | 60 | return MIFARE_DESFIRE(tag)->last_pcd_error; 61 | } 62 | 63 | uint8_t 64 | mifare_desfire_last_picc_error(FreefareTag tag) 65 | { 66 | if (tag->type != MIFARE_DESFIRE) 67 | return 0; 68 | 69 | return MIFARE_DESFIRE(tag)->last_picc_error; 70 | } 71 | -------------------------------------------------------------------------------- /libfreefare/mifare_desfire_key.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010 Romain Tartiere 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd July 20, 2010 17 | .Dt MIFARE_DESFIRE_KEY 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm mifare_desfire_des_key_new , 27 | .Nm mifare_desfire_3des_key_new , 28 | .Nm mifare_desfire_3k3des_key_new , 29 | .Nm mifare_desfire_aes_key_new , 30 | .Nm mifare_desfire_des_key_new_with_version , 31 | .Nm mifare_desfire_3des_key_new_with_version , 32 | .Nm mifare_desfire_3k3des_key_new_with_version , 33 | .Nm mifare_desfire_aes_key_new _with_version, 34 | .Nm mifare_desfire_key_get_version , 35 | .Nm mifare_desfire_key_set_version , 36 | .Nm mifare_desfire_key_free 37 | .Nd Mifare DESFire keys Manipulation Functions 38 | .\" _ _ _ 39 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 40 | .\" | | | | '_ \| '__/ _` | '__| | | | 41 | .\" | |___| | |_) | | | (_| | | | |_| | 42 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 43 | .\" |___/ 44 | .Sh LIBRARY 45 | Mifare card manipulation library (libfreefare, \-lfreefare) 46 | .\" ____ _ 47 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 48 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 49 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 50 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 51 | .\" |___/ |_| 52 | .Sh SYNOPSIS 53 | .In freefare.h 54 | .Ft MifareDESFireKey 55 | .Fn mifare_desfire_des_key_new "uint8_t value[8]" 56 | .Ft MifareDESFireKey 57 | .Fn mifare_desfire_3des_key_new "uint8_t value[16]" 58 | .Ft MifareDESFireKey 59 | .Fn mifare_desfire_3k3des_key_new "uint8_t value[24]" 60 | .Ft MifareDESFireKey 61 | .Fn mifare_desfire_aes_key_new "uint8_t value[16]" 62 | .Ft MifareDESFireKey 63 | .Fn mifare_desfire_des_key_new_with_version "uint8_t value[8]" 64 | .Ft MifareDESFireKey 65 | .Fn mifare_desfire_3des_key_new_with_version "uint8_t value[16]" 66 | .Ft MifareDESFireKey 67 | .Fn mifare_desfire_3k3des_key_new_with_version "uint8_t value[24]" 68 | .Ft MifareDESFireKey 69 | .Fn mifare_desfire_aes_key_new_with_version "uint8_t value[16]" "uint8_t version" 70 | .Ft uint8_t 71 | .Fn mifare_desfire_key_get_version "MifareDESFireKey key" 72 | .Ft void 73 | .Fn mifare_desfire_key_set_version "MifareDESFireKey key" "uint8_t version" 74 | .Ft void 75 | .Fn mifare_desfire_key_free "MifareDESFireKey key" 76 | .\" ____ _ _ _ 77 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 78 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 79 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 80 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 81 | .\" |_| 82 | .Sh DESCRIPTION 83 | The 84 | .Fn mifare_desfire_key_* 85 | family of functions allows management of Mifare DESFire keys. 86 | .Pp 87 | The 88 | .Fn mifare_desfire_des_key_new , 89 | .Fn mifare_desfire_3des_key_new , 90 | .Fn mifare_desfire_3k3des_key_new 91 | and 92 | .Fn mifare_desfire_ades_key_new 93 | alocate a new key with the provided data 94 | .Va value . 95 | The key version is set to 96 | .Va 0 . 97 | .Pp 98 | The 99 | .Fn mifare_desfire_des_key_new_with_version , 100 | .Fn mifare_desfire_3des_key_new_with_version , 101 | .Fn mifare_desfire_3k3des_key_new_with_version 102 | and 103 | .Fn mifare_desfire_aes_key_new_with_version 104 | functions are equivalent to the previous functions except that the key version 105 | is read from 106 | .Va value 107 | (DES, 3DES, 3K3DES) or set to 108 | .Va version 109 | (AES). 110 | .Pp 111 | The version of a 112 | .Vt MifareDESFireKey 113 | can be extracted using 114 | .Fn mifare_desfire_key_get_version 115 | and changed using 116 | .Fn mifare_desfire_key_set_version. 117 | .Pp 118 | The 119 | .Fn mifare_desfire_key_free 120 | has to be called for each 121 | .Va MifareDESFireKey 122 | after usage to reclaim memory. 123 | .\" ____ _ _ 124 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 125 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 126 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 127 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 128 | .\" 129 | .Sh RETURN VALUES 130 | Key allocations functions return the allocaed key of 131 | .Va NULL 132 | on failure. 133 | .\" ____ _ 134 | .\" / ___| ___ ___ __ _| |___ ___ 135 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 136 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 137 | .\" |____/ \___|\___| \__,_|_|___/\___/ 138 | .\" 139 | .Sh SEE ALSO 140 | .Xr mifare_desfire 3 141 | .\" _ _ _ 142 | .\" / \ _ _| |_| |__ ___ _ __ ___ 143 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 144 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 145 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 146 | .\" 147 | .Sh AUTHORS 148 | .An Romain Tartiere Aq romain@il4p.org 149 | -------------------------------------------------------------------------------- /libfreefare/mifare_desfire_key.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include "freefare_internal.h" 8 | 9 | static inline void update_key_schedules(MifareDESFireKey key); 10 | 11 | static inline void 12 | update_key_schedules(MifareDESFireKey key) 13 | { 14 | DES_set_key((DES_cblock *)key->data, &(key->ks1)); 15 | DES_set_key((DES_cblock *)(key->data + 8), &(key->ks2)); 16 | if (MIFARE_KEY_3K3DES == key->type) { 17 | DES_set_key((DES_cblock *)(key->data + 16), &(key->ks3)); 18 | } 19 | } 20 | 21 | MifareDESFireKey 22 | mifare_desfire_des_key_new(const uint8_t value[8]) 23 | { 24 | uint8_t data[8]; 25 | memcpy(data, value, 8); 26 | for (int n = 0; n < 8; n++) 27 | data[n] &= 0xfe; 28 | return mifare_desfire_des_key_new_with_version(data); 29 | } 30 | 31 | MifareDESFireKey 32 | mifare_desfire_des_key_new_with_version(const uint8_t value[8]) 33 | { 34 | MifareDESFireKey key; 35 | 36 | if ((key = malloc(sizeof(struct mifare_desfire_key)))) { 37 | key->type = MIFARE_KEY_DES; 38 | memcpy(key->data, value, 8); 39 | memcpy(key->data + 8, value, 8); 40 | update_key_schedules(key); 41 | } 42 | return key; 43 | } 44 | 45 | MifareDESFireKey 46 | mifare_desfire_3des_key_new(const uint8_t value[16]) 47 | { 48 | uint8_t data[16]; 49 | memcpy(data, value, 16); 50 | for (int n = 0; n < 8; n++) 51 | data[n] &= 0xfe; 52 | for (int n = 8; n < 16; n++) 53 | data[n] |= 0x01; 54 | return mifare_desfire_3des_key_new_with_version(data); 55 | } 56 | 57 | MifareDESFireKey 58 | mifare_desfire_3des_key_new_with_version(const uint8_t value[16]) 59 | { 60 | MifareDESFireKey key; 61 | 62 | if ((key = malloc(sizeof(struct mifare_desfire_key)))) { 63 | key->type = MIFARE_KEY_2K3DES; 64 | memcpy(key->data, value, 16); 65 | update_key_schedules(key); 66 | } 67 | return key; 68 | } 69 | 70 | MifareDESFireKey 71 | mifare_desfire_3k3des_key_new(const uint8_t value[24]) 72 | { 73 | uint8_t data[24]; 74 | memcpy(data, value, 24); 75 | for (int n = 0; n < 8; n++) 76 | data[n] &= 0xfe; 77 | return mifare_desfire_3k3des_key_new_with_version(data); 78 | } 79 | 80 | MifareDESFireKey 81 | mifare_desfire_3k3des_key_new_with_version(const uint8_t value[24]) 82 | { 83 | MifareDESFireKey key; 84 | 85 | if ((key = malloc(sizeof(struct mifare_desfire_key)))) { 86 | key->type = MIFARE_KEY_3K3DES; 87 | memcpy(key->data, value, 24); 88 | update_key_schedules(key); 89 | } 90 | return key; 91 | } 92 | 93 | MifareDESFireKey 94 | mifare_desfire_aes_key_new(const uint8_t value[16]) 95 | { 96 | return mifare_desfire_aes_key_new_with_version(value, 0); 97 | } 98 | 99 | MifareDESFireKey 100 | mifare_desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version) 101 | { 102 | MifareDESFireKey key; 103 | 104 | if ((key = malloc(sizeof(struct mifare_desfire_key)))) { 105 | memcpy(key->data, value, 16); 106 | key->type = MIFARE_KEY_AES128; 107 | key->aes_version = version; 108 | } 109 | return key; 110 | } 111 | 112 | uint8_t 113 | mifare_desfire_key_get_version(MifareDESFireKey key) 114 | { 115 | uint8_t version = 0; 116 | 117 | if (key->type == MIFARE_KEY_AES128) 118 | return key->aes_version; 119 | 120 | for (int n = 0; n < 8; n++) { 121 | version |= ((key->data[n] & 1) << (7 - n)); 122 | } 123 | 124 | return version; 125 | } 126 | 127 | void 128 | mifare_desfire_key_set_version(MifareDESFireKey key, uint8_t version) 129 | { 130 | if (key->type == MIFARE_KEY_AES128) { 131 | key->aes_version = version; 132 | return; 133 | } 134 | 135 | for (int n = 0; n < 8; n++) { 136 | uint8_t version_bit = ((version & (1 << (7 - n))) >> (7 - n)); 137 | key->data[n] &= 0xfe; 138 | key->data[n] |= version_bit; 139 | switch (key->type) { 140 | case MIFARE_KEY_DES: 141 | // DESFire cards always treat DES keys as special cases of 2K3DES 142 | // keys. The DESFire functional specification explicitly points 143 | // out that if the subkeys of a 2K3DES key are exactly identical 144 | // (including parity bits), then (and only then) is the key treated 145 | // as a DES key for authentication purposes. Specifically, the 146 | // version/parity bits must be idential, as well as the rest of the 147 | // key, otherwise the PICC will treat it as a 2K3DES key. This 148 | // next line ensure that. 149 | key->data[n + 8] = key->data[n]; 150 | break; 151 | case MIFARE_KEY_2K3DES: 152 | // But what if we really did want the PICC to treat the key as a 153 | // real 2K3DES key, even if the actual 56 bits of the subkeys did 154 | // match? To ensure that such as case still works (largely because 155 | // the datasheet implies authentication would behave differently 156 | // otherwise), we need to ensure that the parity bits on the subkeys 157 | // explicitly do not match. The easiest way to ensure that is to 158 | // always write the bits of `~version` to the parity bits of the 159 | // second subkey. Note that this would only have an effect at the 160 | // PICC level if the subkeys were otherwise identical. 161 | key->data[n + 8] &= 0xfe; 162 | key->data[n + 8] |= !version_bit; 163 | break; 164 | default: 165 | break; 166 | } 167 | } 168 | } 169 | 170 | MifareDESFireKey 171 | mifare_desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], MifareDESFireKey authentication_key) 172 | { 173 | MifareDESFireKey key = NULL; 174 | 175 | uint8_t buffer[24]; 176 | 177 | switch (authentication_key->type) { 178 | case MIFARE_KEY_DES: 179 | memcpy(buffer, rnda, 4); 180 | memcpy(buffer + 4, rndb, 4); 181 | key = mifare_desfire_des_key_new_with_version(buffer); 182 | break; 183 | case MIFARE_KEY_2K3DES: 184 | memcpy(buffer, rnda, 4); 185 | memcpy(buffer + 4, rndb, 4); 186 | memcpy(buffer + 8, rnda + 4, 4); 187 | memcpy(buffer + 12, rndb + 4, 4); 188 | key = mifare_desfire_3des_key_new_with_version(buffer); 189 | break; 190 | case MIFARE_KEY_3K3DES: 191 | memcpy(buffer, rnda, 4); 192 | memcpy(buffer + 4, rndb, 4); 193 | memcpy(buffer + 8, rnda + 6, 4); 194 | memcpy(buffer + 12, rndb + 6, 4); 195 | memcpy(buffer + 16, rnda + 12, 4); 196 | memcpy(buffer + 20, rndb + 12, 4); 197 | key = mifare_desfire_3k3des_key_new(buffer); 198 | break; 199 | case MIFARE_KEY_AES128: 200 | memcpy(buffer, rnda, 4); 201 | memcpy(buffer + 4, rndb, 4); 202 | memcpy(buffer + 8, rnda + 12, 4); 203 | memcpy(buffer + 12, rndb + 12, 4); 204 | key = mifare_desfire_aes_key_new(buffer); 205 | break; 206 | } 207 | 208 | return key; 209 | } 210 | 211 | void 212 | mifare_desfire_key_free(MifareDESFireKey key) 213 | { 214 | free(key); 215 | } 216 | -------------------------------------------------------------------------------- /libfreefare/mifare_key_deriver.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2018 Robert Quattlebaum 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd January 4, 2018 17 | .Dt MIFARE_KEY_DERIVER 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm mifare_key_deriver_new_an10922 , 27 | .Nm mifare_key_deriver_begin , 28 | .Nm mifare_key_deriver_update_data , 29 | .Nm mifare_key_deriver_update_uid , 30 | .Nm mifare_key_deriver_update_aid , 31 | .Nm mifare_key_deriver_update_cstr , 32 | .Nm mifare_key_deriver_end , 33 | .Nm mifare_key_deriver_end_raw , 34 | .Nm mifare_key_deriver_free , 35 | .Nd Mifare Key Derivation Functions 36 | .\" _ _ _ 37 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 38 | .\" | | | | '_ \| '__/ _` | '__| | | | 39 | .\" | |___| | |_) | | | (_| | | | |_| | 40 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 41 | .\" |___/ 42 | .Sh LIBRARY 43 | Mifare card manipulation library (libfreefare, \-lfreefare) 44 | .\" ____ _ 45 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 46 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 47 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 48 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 49 | .\" |___/ |_| 50 | .Sh SYNOPSIS 51 | .In freefare.h 52 | .Ft MifareKeyDeriver 53 | .Fn mifare_key_deriver_new_an10922 "MifareDESFireKey master_key" "MifareKeyType output_key_type" "int flags" 54 | .Ft int 55 | .Fn mifare_key_deriver_begin "MifareKeyDeriver deriver" 56 | .Ft int 57 | .Fn mifare_key_deriver_update_data "MifareKeyDeriver deriver" "const uint8_t *data" "size_t len" 58 | .Ft int 59 | .Fn mifare_key_deriver_update_uid "MifareKeyDeriver deriver" "FreefareTag tag" 60 | .Ft int 61 | .Fn mifare_key_deriver_update_aid "MifareKeyDeriver deriver" "MifareDESFireAID aid" 62 | .Ft int 63 | .Fn mifare_key_deriver_update_cstr "MifareKeyDeriver deriver" "const char *cstr" 64 | .Ft MifareDESFireKey 65 | .Fn mifare_key_deriver_end "MifareKeyDeriver deriver" 66 | .Ft int 67 | .Fn mifare_key_deriver_end_raw "MifareKeyDeriver deriver" "uint8_t* derived_data" "size_t data_max_len" 68 | .Ft void 69 | .Fn mifare_key_deriver_free "MifareKeyDeriver deriver" 70 | .\" ____ _ _ _ 71 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 72 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 73 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 74 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 75 | .\" |_| 76 | .Sh DESCRIPTION 77 | The 78 | .Fn mifare_key_deriver_* 79 | family of functions allows for the diversification of Mifare DESFire keys. 80 | .Pp 81 | The 82 | .Fn mifare_key_deriver_new_an10922 83 | function alocates a new key deriver object which can be used to generate 84 | diversified keys from 85 | .Va master_key 86 | in accordinance with AN10922 when the flags field is is set to AN10922_FLAG_DEFAULT. 87 | When the flags field is set to AN10922_FLAG_EMULATE_ISSUE_91, the resulting key 88 | deriver will use the non-AN10922-compliant key derivation that was originally being 89 | used by this API. All new deployments should use AN10922_FLAG_DEFAULT. See issue #91 for 90 | more information. 91 | .Pp 92 | The 93 | .Fn mifare_key_deriver_begin 94 | function marks the start of the derivation of a new diversified key. 95 | .Pp 96 | The 97 | .Fn mifare_key_deriver_update_data , 98 | .Fn mifare_key_deriver_update_uid , 99 | .Fn mifare_key_deriver_update_aid 100 | and 101 | .Fn mifare_key_deriver_update_cstr 102 | functions are used to specify the information that should be used to derive 103 | the diversified key from the master key. 104 | .Pp 105 | The 106 | .Fn mifare_key_deriver_end 107 | function marks the end of the derivation and returns the new diversified key. 108 | It is the responsibility of the caller to to free the returned key by calling 109 | .Fn mifare_desfire_key_free . 110 | .Fn mifare_key_deriver_end_raw 111 | is a variant used to directly fetch the raw bytes of the derived key. 112 | .Pp 113 | .\" ____ _ _ 114 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 115 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 116 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 117 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 118 | .\" 119 | .Sh RETURN VALUES 120 | .Fn mifare_key_deriver_new_an10922 121 | returns the allocated key deriver or 122 | .Va NULL 123 | on failure. 124 | .Pp 125 | The 126 | .Fn mifare_key_deriver_begin , 127 | .Fn mifare_key_deriver_update_data , 128 | .Fn mifare_key_deriver_update_uid , 129 | .Fn mifare_key_deriver_update_aid 130 | and 131 | .Fn mifare_key_deriver_update_cstr 132 | functions return 133 | .Va 0 134 | on success and 135 | .Va -1 136 | on failure. 137 | .Pp 138 | The 139 | .Fn mifare_key_deriver_end 140 | function returns the new diversified key on success and 141 | .Va NULL 142 | on failure. It is the responsibility of the 143 | caller to to free the returned key by calling 144 | .Fn mifare_desfire_key_free . 145 | .Pp 146 | The 147 | .Fn mifare_key_deriver_end_raw 148 | function returns 149 | .Va -1 150 | on failure. On success, it returns the number of bytes that were derived. If 151 | .Va data_max_len 152 | is smaller than the return value, then no bytes were written to 153 | .Va derived_data . 154 | .Pp 155 | Upon failure, all methods update 156 | .Va errno 157 | with the appropriate error code. 158 | .\" ____ _ 159 | .\" / ___| ___ ___ __ _| |___ ___ 160 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 161 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 162 | .\" |____/ \___|\___| \__,_|_|___/\___/ 163 | .\" 164 | .Sh SEE ALSO 165 | .Xr mifare_desfire_key 3 166 | .\" _ _ _ 167 | .\" / \ _ _| |_| |__ ___ _ __ ___ 168 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 169 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 170 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 171 | .\" 172 | .Sh AUTHORS 173 | .An Robert Quattlebaum darco@deepdarc.com 174 | -------------------------------------------------------------------------------- /libfreefare/mifare_ultralight.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010 Romain Tartiere 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd March 30, 2010 17 | .Dt MIFARE_ULTRALIGHT 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm mifare_ultralight_connect , 27 | .Nm mifare_ultralight_disconnect , 28 | .Nm mifare_ultralight_read , 29 | .Nm mifare_ultralight_write , 30 | .Nd Mifare UltraLight Manipulation Functions 31 | .\" _ _ _ 32 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 33 | .\" | | | | '_ \| '__/ _` | '__| | | | 34 | .\" | |___| | |_) | | | (_| | | | |_| | 35 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 36 | .\" |___/ 37 | .Sh LIBRARY 38 | Mifare card manipulation library (libfreefare, \-lfreefare) 39 | .\" ____ _ 40 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 41 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 42 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 43 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 44 | .\" |___/ |_| 45 | .Sh SYNOPSIS 46 | .In freefare.h 47 | .Ft int 48 | .Fn mifare_ultralight_connect "FreefareTag tag" 49 | .Ft int 50 | .Fn mifare_ultralight_disconnect "FreefareTag tag" 51 | .Ft int 52 | .Fn mifare_ultralight_read "FreefareTag tag" "const MifareUltralightPageNumber page" "MifareUltralightPage *data" 53 | .Ft int 54 | .Fn mifare_ultralight_write "FreefareTag tag" "const MifareUltralightPageNumber page" "const MifareUltralightPage data" 55 | .\" ____ _ _ _ 56 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 57 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 58 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 59 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 60 | .\" |_| 61 | .Sh DESCRIPTION 62 | The 63 | .Fn mifare_ultralight_* 64 | functions allows management of Mifare UltraLight tags. 65 | .Pp 66 | The 67 | .Fn mifare_ultralight_connect 68 | function activates the specified 69 | .Vt tag . 70 | .Pp 71 | A 72 | .Vt page 73 | of 74 | .Vt data 75 | can be read from a 76 | .Vt tag 77 | using 78 | .Fn mifare_ultralight_read , 79 | and written 80 | using 81 | .Fn mifare_ultralight_write . 82 | .Pp 83 | After usage, a 84 | .Vt tag 85 | is deactivated using 86 | .Fn mifare_ultralight_disconnect . 87 | .\" ____ _ _ 88 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 89 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 90 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 91 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 92 | .\" 93 | .Sh RETURN VALUES 94 | Unless stated otherwise, all functions return a value greater than or equal to 95 | .Va 0 96 | on success or 97 | .Va -1 98 | on failure. 99 | .\" ____ _ 100 | .\" / ___| ___ ___ __ _| |___ ___ 101 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 102 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 103 | .\" |____/ \___|\___| \__,_|_|___/\___/ 104 | .\" 105 | .Sh SEE ALSO 106 | .Xr freefare 3 107 | .\" _ _ _ 108 | .\" / \ _ _| |_| |__ ___ _ __ ___ 109 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 110 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 111 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 112 | .\" 113 | .Sh AUTHORS 114 | .An Romain Tartiere Aq romain@blogreen.org 115 | .An Romuald Conty Aq romuald@libnfc.org 116 | -------------------------------------------------------------------------------- /libfreefare/ntag21x.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010, 2017 Romain Tartiere, Martin Dagarin (SloCompTech) 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd February 26, 2017 17 | .Dt NTAG_21x 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm ntag21x_connect , 27 | .Nm ntag21x_disconnect , 28 | .Nm ntag21x_read , 29 | .Nm ntag21x_read4 , 30 | .Nm ntag21x_fast_read , 31 | .Nm ntag21x_fast_read4 , 32 | .Nm ntag21x_write , 33 | .Nm ntag21x_compatibility_write , 34 | .Nd NTAG 213/215/216 Manipulation Functions 35 | .\" _ _ _ 36 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 37 | .\" | | | | '_ \| '__/ _` | '__| | | | 38 | .\" | |___| | |_) | | | (_| | | | |_| | 39 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 40 | .\" |___/ 41 | .Sh LIBRARY 42 | Mifare card manipulation library (libfreefare, \-lfreefare) 43 | .\" ____ _ 44 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 45 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 46 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 47 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 48 | .\" |___/ |_| 49 | .Sh SYNOPSIS 50 | .In freefare.h 51 | .Ft int 52 | .Fn ntag21x_connect "FreefareTag tag" 53 | .Ft int 54 | .Fn ntag21x_disconnect "FreefareTag tag" 55 | .Ft int 56 | .Fn ntag21x_read "FreefareTag tag" "uint8_t page" "uint8_t *data" 57 | .Ft int 58 | .Fn ntag21x_read4 "FreefareTag tag" "uint8_t page" "uint8_t *data" 59 | .Ft int 60 | .Fn ntag21x_fast_read "FreefareTag tag" "uint8_t start_page" "uint8_t end_page" "uint8_t *data" 61 | .Ft int 62 | .Fn ntag21x_fast_read4 "FreefareTag tag" "uint8_t page" "uint8_t *data" 63 | .Ft int 64 | .Fn ntag21x_write "FreefareTag tag" "uint8_t page" "uint8_t data[4]" 65 | .Ft int 66 | .Fn ntag21x_compatibility_write "FreefareTag tag" "uint8_t page" "uint8_t data[4]" 67 | .\" ____ _ _ _ 68 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 69 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 70 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 71 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 72 | .\" |_| 73 | .Sh DESCRIPTION 74 | The 75 | .Fn ntag21x_* 76 | functions allows management of NTAG213/215/216 tags. 77 | .Pp 78 | The 79 | .Fn ntag21x_connect 80 | function activates the specified 81 | .Vt tag . 82 | .Pp 83 | A 84 | .Vt page 85 | of 86 | .Vt data 87 | can be read from a 88 | .Vt tag 89 | using 90 | .Fn ntag21x_read , 91 | .Fn ntag21x_read4, 92 | .Fn ntag21x_fast_read, 93 | .Fn ntag21x_fast_read4, 94 | and written 95 | using 96 | .Fn ntag21_write , 97 | .Fn ntag21x_compatibility_write . 98 | .Pp 99 | After usage, a 100 | .Vt tag 101 | is deactivated using 102 | .Fn ntag21x_disconnect . 103 | .\" ____ _ _ 104 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 105 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 106 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 107 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 108 | .\" 109 | .Sh RETURN VALUES 110 | Unless stated otherwise, all functions return a value greater than or equal to 111 | .Va 0 112 | on success or 113 | .Va -1 114 | on failure. 115 | .\" ____ _ 116 | .\" / ___| ___ ___ __ _| |___ ___ 117 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 118 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 119 | .\" |____/ \___|\___| \__,_|_|___/\___/ 120 | .\" 121 | .Sh SEE ALSO 122 | .Xr freefare 3 123 | .\" _ _ _ 124 | .\" / \ _ _| |_| |__ ___ _ __ ___ 125 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 126 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 127 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 128 | .\" 129 | .Sh AUTHORS 130 | .An Romain Tartiere Aq romain@blogreen.org 131 | .An Romuald Conty Aq romuald@libnfc.org 132 | .An Martin Dagarin Aq SloCompTech@gmail.com 133 | -------------------------------------------------------------------------------- /libfreefare/ntag21x_error.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "freefare_internal.h" 8 | 9 | #define EM(e) { e, #e } 10 | 11 | static struct ntag21x_error_message { 12 | uint8_t code; 13 | const char *message; 14 | } ntag21x_error_messages[] = { 15 | EM(OPERATION_OK), 16 | EM(TAG_INFO_MISSING_ERROR), 17 | EM(UNKNOWN_TAG_TYPE_ERROR), 18 | { 0, NULL } 19 | }; 20 | 21 | const char * 22 | ntag21x_error_lookup(uint8_t code) 23 | { 24 | struct ntag21x_error_message *e = ntag21x_error_messages; 25 | while (e->message) { 26 | if (e->code == code) 27 | return (e->message); 28 | e++; 29 | } 30 | 31 | return "Invalid error code"; 32 | } 33 | 34 | uint8_t 35 | ntag21x_last_error(FreefareTag tag) 36 | { 37 | if (tag->type != NTAG_21x) 38 | return 0; 39 | 40 | return NTAG_21x(tag)->last_error; 41 | } 42 | -------------------------------------------------------------------------------- /libfreefare/tlv.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (C) 2010 Romain Tartiere 2 | .\" 3 | .\" This program is free software: you can redistribute it and/or modify it 4 | .\" under the terms of the GNU Lesser General Public License as published by the 5 | .\" Free Software Foundation, either version 3 of the License, or (at your 6 | .\" option) any later version. 7 | .\" 8 | .\" This program is distributed in the hope that it will be useful, but WITHOUT 9 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | .\" more details. 12 | .\" 13 | .\" You should have received a copy of the GNU Lesser General Public License 14 | .\" along with this program. If not, see 15 | .\" 16 | .Dd March 30, 2010 17 | .Dt TLV 3 18 | .Os 19 | .\" _ _ 20 | .\" | \ | | __ _ _ __ ___ ___ 21 | .\" | \| |/ _` | '_ ` _ \ / _ \ 22 | .\" | |\ | (_| | | | | | | __/ 23 | .\" |_| \_|\__,_|_| |_| |_|\___| 24 | .\" 25 | .Sh NAME 26 | .Nm tlv_encode , 27 | .Nm tlv_decode 28 | .Nd TLV Manipulation Functions 29 | .\" _ _ _ 30 | .\" | | (_) |__ _ __ __ _ _ __ _ _ 31 | .\" | | | | '_ \| '__/ _` | '__| | | | 32 | .\" | |___| | |_) | | | (_| | | | |_| | 33 | .\" |_____|_|_.__/|_| \__,_|_| \__, | 34 | .\" |___/ 35 | .Sh LIBRARY 36 | Mifare card manipulation library (libfreefare, \-lfreefare) 37 | .\" ____ _ 38 | .\" / ___| _ _ _ __ ___ _ __ ___(_)___ 39 | .\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __| 40 | .\" ___) | |_| | | | | (_) | |_) \__ \ \__ \ 41 | .\" |____/ \__, |_| |_|\___/| .__/|___/_|___/ 42 | .\" |___/ |_| 43 | .Sh SYNOPSIS 44 | .In freefare.h 45 | .Ft "uint8_t *" 46 | .Fn tlv_encode "const uint8_t type" "const uint8_t *istream" "uint16_t isize" "size_t *osize" 47 | .Ft "uint8_t *" 48 | .Fn tlv_decode "const uint8_t *istream" "uint8_t *type" "uint16_t *size" 49 | .\" ____ _ _ _ 50 | .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ 51 | .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ 52 | .\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | | 53 | .\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_| 54 | .\" |_| 55 | .Sh DESCRIPTION 56 | The 57 | .Fn tlv_encode 58 | and 59 | .Fn tlv_decode 60 | functions are helpers to manipulate TLV (Text-Length-Value) data. 61 | .Pp 62 | The 63 | .Fn tlv_encode 64 | function converts the 65 | .Ar isize 66 | bytes long 67 | .Ar istream 68 | message into a TLV stream of type 69 | .Ar type 70 | and set the value of 71 | .Ar osize 72 | to the length of the returned stream. 73 | .Pp 74 | The 75 | .Fn tlv_decode 76 | function converts the 77 | .Ar istream 78 | TLV stream and set the 79 | .Ar type 80 | argument according to the type of the stream, and set the 81 | .Ar size 82 | argument to the length of the returned stream. 83 | .\" ____ _ _ 84 | .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ 85 | .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| 86 | .\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \ 87 | .\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/ 88 | .\" 89 | .Sh RETURN VALUES 90 | Both functions return memory allocated using 91 | .Xr malloc 3 92 | which should be reclaimed using 93 | .Xr free 3 94 | after usage. 95 | .\" ____ _ 96 | .\" / ___| ___ ___ __ _| |___ ___ 97 | .\" \___ \ / _ \/ _ \ / _` | / __|/ _ \ 98 | .\" ___) | __/ __/ | (_| | \__ \ (_) | 99 | .\" |____/ \___|\___| \__,_|_|___/\___/ 100 | .\" 101 | .Sh SEE ALSO 102 | .Xr freefare 3 , 103 | .Xr malloc 3 , 104 | .Xr free 3 105 | .\" _ _ _ 106 | .\" / \ _ _| |_| |__ ___ _ __ ___ 107 | .\" / _ \| | | | __| '_ \ / _ \| '__/ __| 108 | .\" / ___ \ |_| | |_| | | | (_) | | \__ \ 109 | .\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/ 110 | .\" 111 | .Sh AUTHORS 112 | .An Romain Tartiere Aq romain@blogreen.org 113 | .An Romuald Conty Aq romuald@libnfc.org 114 | -------------------------------------------------------------------------------- /libfreefare/tlv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This implementation was written based on information provided by the 3 | * following documents: 4 | * 5 | * NFC Forum - Type 1 Tag Operation Specification 6 | * NFCForum-TS-Type-1-Tag_1.0 7 | * 2007-07-09 8 | */ 9 | 10 | #if defined(HAVE_CONFIG_H) 11 | #include "config.h" 12 | #endif 13 | 14 | #if defined(HAVE_SYS_TYPES_H) 15 | #include 16 | #endif 17 | 18 | #if defined(HAVE_SYS_ENDIAN_H) 19 | #include 20 | #endif 21 | 22 | #if defined(HAVE_ENDIAN_H) 23 | #include 24 | #endif 25 | 26 | #if defined(HAVE_COREFOUNDATION_COREFOUNDATION_H) 27 | #include 28 | #endif 29 | 30 | #if defined(HAVE_BYTESWAP_H) 31 | #include 32 | #endif 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include "freefare_internal.h" 40 | 41 | #define TLV_TERMINATOR 0xFE 42 | 43 | size_t tlv_record_length(const uint8_t *stream, size_t *field_length_size, size_t *field_value_size); 44 | uint8_t *tlv_next(uint8_t *stream); 45 | size_t tlv_sequence_length(uint8_t *stream); 46 | 47 | /* 48 | * TLV (Type Length Value) Manipulation Functions. 49 | */ 50 | 51 | /* 52 | * Encode data stream into TLV. 53 | */ 54 | uint8_t * 55 | tlv_encode(const uint8_t type, const uint8_t *istream, uint16_t isize, size_t *osize) 56 | { 57 | uint8_t *res; 58 | off_t n = 0; 59 | 60 | if (osize) 61 | *osize = 0; 62 | 63 | if (isize == 0xffff) /* RFU */ 64 | return NULL; 65 | 66 | if ((res = malloc(1 + ((isize > 254) ? 3 : 1) + isize + 1))) { 67 | /* type + size + payload + terminator */ 68 | res[n++] = type; 69 | 70 | if (isize > 254) { 71 | res[n++] = 0xff; 72 | uint16_t size_be = htobe16(isize); 73 | memcpy(res + n, &size_be, sizeof(uint16_t)); 74 | n += 2; 75 | } else { 76 | res[n++] = (uint8_t)isize; 77 | } 78 | 79 | memcpy(res + n, istream, isize); 80 | 81 | n += isize; 82 | res[n++] = TLV_TERMINATOR; 83 | 84 | if (osize) 85 | *osize = n; 86 | } 87 | return res; 88 | } 89 | 90 | /* 91 | * Decode TLV from data stream. 92 | */ 93 | uint8_t * 94 | tlv_decode(const uint8_t *istream, uint8_t *type, uint16_t *size) 95 | { 96 | size_t fls = 0; 97 | size_t fvs = 0; 98 | uint8_t *res = NULL; 99 | 100 | if (type) 101 | *type = istream[0]; 102 | 103 | tlv_record_length(istream, &fls, &fvs); 104 | 105 | if (size) { 106 | *size = fvs; 107 | } 108 | 109 | if ((res = malloc(fvs))) { 110 | memcpy(res, istream + 1 + fls, fvs); 111 | } 112 | return res; 113 | } 114 | 115 | /* 116 | * Length of a TLV field 117 | */ 118 | size_t 119 | tlv_record_length(const uint8_t *stream, size_t *field_length_size, size_t *field_value_size) 120 | { 121 | size_t fls = 0; 122 | size_t fvs = 0; 123 | 124 | switch (stream[0]) { 125 | case 0x00: 126 | case 0xfe: 127 | break; 128 | case 0x01: 129 | case 0x02: 130 | case 0x03: 131 | default: // FIXME Not supported. 132 | if (stream[1] == 0xff) { 133 | uint16_t be_size; 134 | memcpy(&be_size, stream + 2, sizeof(uint16_t)); 135 | fls = 3; 136 | fvs = be16toh(be_size); 137 | } else { 138 | fls = 1; 139 | fvs = stream[1]; 140 | } 141 | break; 142 | } 143 | 144 | if (field_length_size) 145 | *field_length_size = fls; 146 | 147 | if (field_value_size) 148 | *field_value_size = fvs; 149 | 150 | return 1 + fls + fvs; 151 | } 152 | 153 | /* 154 | * Get a pointer to the next record in the provided TLV sequence. 155 | * | 0x03 | 0x02 | 0xbe | 0xef | 0x00 | 0x00 | 0xfe | 156 | * First call ---' | | 157 | * Second call -------------------------------' | 158 | * Third call --------------------------------------' 159 | * Fourth call NULL 160 | */ 161 | uint8_t * 162 | tlv_next(uint8_t *stream) 163 | { 164 | uint8_t *res = NULL; 165 | if (stream[0] != TLV_TERMINATOR) 166 | res = stream + tlv_record_length(stream, NULL, NULL); 167 | 168 | return res; 169 | } 170 | 171 | /* 172 | * Full-length of all TLV fields. 173 | */ 174 | size_t 175 | tlv_sequence_length(uint8_t *stream) 176 | { 177 | size_t res = 0; 178 | 179 | do { 180 | res += tlv_record_length(stream, NULL, NULL); 181 | } while ((stream = tlv_next(stream))); 182 | 183 | return res; 184 | } 185 | 186 | 187 | /* 188 | * Append two TLV. Acts like realloc(3). 189 | */ 190 | uint8_t * 191 | tlv_append(uint8_t *a, uint8_t *b) 192 | { 193 | size_t a_size = tlv_sequence_length(a); 194 | size_t b_size = tlv_sequence_length(b); 195 | size_t new_size = a_size + b_size - 1; 196 | 197 | if ((a = realloc(a, new_size))) { 198 | memcpy(a + a_size - 1, b, b_size); 199 | } 200 | 201 | return a; 202 | } 203 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = $(CUTTER_CFLAGS) -I$(top_srcdir)/libfreefare 2 | LIBS = $(CUTTER_LIBS) 3 | 4 | SUBDIRS = common . 5 | 6 | AM_CFLAGS = @LIBNFC_CFLAGS@ 7 | 8 | if WITH_CUTTER 9 | 10 | TESTS = run-test.sh 11 | TESTS_ENVIRONMENT = NO_MAKE=yes CUTTER="$(CUTTER)" 12 | 13 | cutter_unit_test_libs = \ 14 | test_felica.la \ 15 | test_freefare.la \ 16 | test_mad.la \ 17 | test_mifare_application.la \ 18 | test_mifare_classic.la \ 19 | test_mifare_classic_create_trailer_block.la \ 20 | test_mifare_classic_sector_boundaries.la \ 21 | test_mifare_desfire.la \ 22 | test_mifare_desfire_aes.la \ 23 | test_mifare_desfire_aid.la \ 24 | test_mifare_desfire_des.la \ 25 | test_mifare_desfire_ev1.la \ 26 | test_mifare_desfire_key.la \ 27 | test_mifare_key_deriver_an10922.la \ 28 | test_mifare_ultralight.la \ 29 | test_tlv.la 30 | 31 | if WITH_DEBUG 32 | noinst_LTLIBRARIES = $(cutter_unit_test_libs) 33 | else 34 | check_LTLIBRARIES = $(cutter_unit_test_libs) 35 | endif 36 | 37 | AM_LDFLAGS = -module -rpath $(libdir) -avoid-version -no-undefined 38 | 39 | test_felica_la_SOURCES = test_felica.c \ 40 | felica_fixture.c \ 41 | fixture.h 42 | test_felica_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 43 | 44 | test_freefare_la_SOURCES = test_freefare.c 45 | test_freefare_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 46 | 47 | test_mad_la_SOURCES = test_mad.c 48 | test_mad_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 49 | 50 | test_mifare_application_la_SOURCES = test_mifare_application.c 51 | test_mifare_application_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 52 | 53 | test_mifare_classic_la_SOURCES = test_mifare_classic.c \ 54 | test_mifare_classic_mad.c \ 55 | mifare_classic_fixture.c \ 56 | fixture.h 57 | test_mifare_classic_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 58 | 59 | test_mifare_classic_create_trailer_block_la_SOURCES = test_mifare_classic_create_trailer_block.c 60 | test_mifare_classic_create_trailer_block_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 61 | 62 | test_mifare_classic_sector_boundaries_la_SOURCES = test_mifare_classic_sector_boundaries.c 63 | test_mifare_classic_sector_boundaries_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 64 | 65 | test_mifare_desfire_la_SOURCES = test_mifare_desfire.c \ 66 | mifare_desfire_fixture.c \ 67 | fixture.h 68 | test_mifare_desfire_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la \ 69 | $(top_builddir)/test/common/libtestcommon.la 70 | 71 | test_mifare_desfire_aes_la_SOURCES = test_mifare_desfire_aes.c 72 | test_mifare_desfire_aes_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 73 | 74 | test_mifare_desfire_aid_la_SOURCES = test_mifare_desfire_aid.c 75 | test_mifare_desfire_aid_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 76 | 77 | test_mifare_desfire_des_la_SOURCES = test_mifare_desfire_des.c 78 | test_mifare_desfire_des_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 79 | 80 | test_mifare_desfire_ev1_la_SOURCES = test_mifare_desfire_ev1.c \ 81 | test_mifare_desfire_ev1_3des.c \ 82 | test_mifare_desfire_ev1_3k3des.c \ 83 | test_mifare_desfire_ev1_aes.c \ 84 | test_mifare_desfire_ev1_iso.c \ 85 | mifare_desfire_ev1_fixture.c \ 86 | fixture.h 87 | test_mifare_desfire_ev1_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la \ 88 | $(top_builddir)/test/common/libtestcommon.la 89 | 90 | test_mifare_desfire_key_la_SOURCES = test_mifare_desfire_key.c 91 | test_mifare_desfire_key_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 92 | 93 | test_mifare_key_deriver_an10922_la_SOURCES = test_mifare_key_deriver_an10922.c 94 | test_mifare_key_deriver_an10922_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 95 | 96 | test_mifare_ultralight_la_SOURCES = test_mifare_ultralight.c \ 97 | mifare_ultralight_fixture.c \ 98 | fixture.h 99 | test_mifare_ultralight_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 100 | 101 | test_tlv_la_SOURCES = test_tlv.c 102 | test_tlv_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la 103 | 104 | echo-cutter: 105 | @echo $(CUTTER) 106 | 107 | EXTRA_DIST = run-test.sh 108 | CLEANFILES = *.gcno 109 | 110 | endif 111 | -------------------------------------------------------------------------------- /test/common/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = $(CUTTER_CFLAGS) -I$(top_srcdir)/libfreefare 2 | AM_CFLAGS = @LIBNFC_CFLAGS@ 3 | 4 | if WITH_CUTTER 5 | 6 | cutter_unit_test_libs = \ 7 | libtestcommon.la 8 | 9 | if WITH_DEBUG 10 | noinst_LTLIBRARIES = $(cutter_unit_test_libs) 11 | else 12 | check_LTLIBRARIES = $(cutter_unit_test_libs) 13 | endif 14 | 15 | libtestcommon_la_SOURCES = mifare_desfire_auto_authenticate.c \ 16 | mifare_desfire_auto_authenticate.h 17 | 18 | endif 19 | -------------------------------------------------------------------------------- /test/common/mifare_desfire_auto_authenticate.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "mifare_desfire_auto_authenticate.h" 6 | 7 | uint8_t key_data_null[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 8 | uint8_t key_data_des[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' }; 9 | uint8_t key_data_3des[16] = { 'C', 'a', 'r', 'd', ' ', 'M', 'a', 's', 't', 'e', 'r', ' ', 'K', 'e', 'y', '!' }; 10 | uint8_t key_data_aes[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 11 | uint8_t key_data_3k3des[24] = { 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 12 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 13 | }; 14 | 15 | const uint8_t key_data_aes_version = 0x42; 16 | 17 | void 18 | mifare_desfire_auto_authenticate(FreefareTag tag, uint8_t key_no) 19 | { 20 | /* Determine which key is currently the master one */ 21 | uint8_t key_version; 22 | int res = mifare_desfire_get_key_version(tag, key_no, &key_version); 23 | cut_assert_equal_int(0, res, cut_message("mifare_desfire_get_key_version()")); 24 | 25 | MifareDESFireKey key; 26 | 27 | switch (key_version) { 28 | case 0x00: 29 | key = mifare_desfire_des_key_new_with_version(key_data_null); 30 | break; 31 | case 0x42: 32 | key = mifare_desfire_aes_key_new_with_version(key_data_aes, key_data_aes_version); 33 | break; 34 | case 0xAA: 35 | key = mifare_desfire_des_key_new_with_version(key_data_des); 36 | break; 37 | case 0xC7: 38 | key = mifare_desfire_3des_key_new_with_version(key_data_3des); 39 | break; 40 | case 0x55: 41 | key = mifare_desfire_3k3des_key_new_with_version(key_data_3k3des); 42 | break; 43 | default: 44 | cut_fail("Unknown master key."); 45 | } 46 | 47 | cut_assert_not_null(key, cut_message("Cannot allocate key")); 48 | 49 | /* Authenticate with this key */ 50 | switch (key_version) { 51 | case 0x00: 52 | case 0xAA: 53 | case 0xC7: 54 | res = mifare_desfire_authenticate(tag, key_no, key); 55 | break; 56 | case 0x55: 57 | res = mifare_desfire_authenticate_iso(tag, key_no, key); 58 | break; 59 | case 0x42: 60 | res = mifare_desfire_authenticate_aes(tag, key_no, key); 61 | break; 62 | } 63 | cut_assert_equal_int(0, res, cut_message("mifare_desfire_authenticate()")); 64 | 65 | mifare_desfire_key_free(key); 66 | } 67 | -------------------------------------------------------------------------------- /test/common/mifare_desfire_auto_authenticate.h: -------------------------------------------------------------------------------- 1 | #ifndef _MIFARE_DESFIRE_AUTO_AUTHENTICATE_H 2 | #define _MIFARE_DESFIRE_AUTO_AUTHENTICATE_H 3 | 4 | extern uint8_t key_data_null[8]; 5 | extern uint8_t key_data_des[8]; 6 | extern uint8_t key_data_3des[16]; 7 | extern uint8_t key_data_aes[16]; 8 | extern uint8_t key_data_3k3des[24]; 9 | extern const uint8_t key_data_aes_version; 10 | 11 | void mifare_desfire_auto_authenticate(FreefareTag tag, uint8_t key_no); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /test/felica_fixture.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fixture.h" 5 | 6 | static nfc_context *context; 7 | static nfc_device *device = NULL; 8 | static FreefareTag *tags = NULL; 9 | FreefareTag tag = NULL; 10 | 11 | void 12 | cut_setup(void) 13 | { 14 | int res; 15 | nfc_connstring devices[8]; 16 | size_t device_count; 17 | 18 | nfc_init(&context); 19 | cut_assert_not_null(context, cut_message("Unable to init libnfc (malloc)")); 20 | 21 | device_count = nfc_list_devices(context, devices, 8); 22 | if (device_count <= 0) 23 | cut_omit("No device found"); 24 | 25 | for (size_t i = 0; i < device_count; i++) { 26 | device = nfc_open(context, devices[i]); 27 | if (!device) 28 | cut_omit("nfc_open() failed."); 29 | 30 | tags = freefare_get_tags(device); 31 | cut_assert_not_null(tags, cut_message("freefare_get_tags() failed")); 32 | 33 | tag = NULL; 34 | for (int i = 0; tags[i]; i++) { 35 | if (freefare_get_tag_type(tags[i]) == FELICA) { 36 | tag = tags[i]; 37 | return; 38 | } 39 | } 40 | nfc_close(device); 41 | device = NULL; 42 | freefare_free_tags(tags); 43 | tags = NULL; 44 | } 45 | cut_omit("No FeliCa tag on NFC device"); 46 | } 47 | 48 | void 49 | cut_teardown(void) 50 | { 51 | if (tags) { 52 | freefare_free_tags(tags); 53 | tags = NULL; 54 | } 55 | 56 | if (device) 57 | nfc_close(device); 58 | 59 | nfc_exit(context); 60 | } 61 | -------------------------------------------------------------------------------- /test/fixture.h: -------------------------------------------------------------------------------- 1 | #ifndef _FIXTURE_H 2 | #define _FIXTURE_H 3 | 4 | extern FreefareTag tag; 5 | 6 | #endif /* _FIXTURE_H */ 7 | -------------------------------------------------------------------------------- /test/mifare_classic_fixture.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fixture.h" 5 | 6 | static nfc_context *context; 7 | static nfc_device *device = NULL; 8 | static FreefareTag *tags = NULL; 9 | FreefareTag tag = NULL; 10 | 11 | void 12 | cut_setup(void) 13 | { 14 | int res; 15 | nfc_connstring devices[8]; 16 | size_t device_count; 17 | 18 | nfc_init(&context); 19 | cut_assert_not_null(context, cut_message("Unable to init libnfc (malloc)")); 20 | 21 | device_count = nfc_list_devices(context, devices, 8); 22 | if (device_count <= 0) 23 | cut_omit("No device found"); 24 | 25 | for (size_t i = 0; i < device_count; i++) { 26 | device = nfc_open(context, devices[i]); 27 | if (!device) 28 | cut_omit("nfc_open() failed."); 29 | 30 | tags = freefare_get_tags(device); 31 | cut_assert_not_null(tags, cut_message("freefare_get_tags() failed")); 32 | 33 | tag = NULL; 34 | for (int i = 0; tags[i]; i++) { 35 | if ((freefare_get_tag_type(tags[i]) == MIFARE_CLASSIC_1K) || 36 | (freefare_get_tag_type(tags[i]) == MIFARE_CLASSIC_4K)) { 37 | tag = tags[i]; 38 | res = mifare_classic_connect(tag); 39 | cut_assert_equal_int(0, res, cut_message("mifare_classic_connect() failed")); 40 | return; 41 | } 42 | } 43 | nfc_close(device); 44 | device = NULL; 45 | freefare_free_tags(tags); 46 | tags = NULL; 47 | } 48 | cut_omit("No MIFARE Classic tag on NFC device"); 49 | } 50 | 51 | void 52 | cut_teardown(void) 53 | { 54 | if (tag) 55 | mifare_classic_disconnect(tag); 56 | 57 | if (tags) { 58 | freefare_free_tags(tags); 59 | tags = NULL; 60 | } 61 | 62 | if (device) 63 | nfc_close(device); 64 | 65 | nfc_exit(context); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /test/mifare_desfire_ev1_fixture.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fixture.h" 5 | 6 | static nfc_context *context; 7 | static nfc_device *device = NULL; 8 | static FreefareTag *tags = NULL; 9 | FreefareTag tag = NULL; 10 | 11 | void 12 | cut_setup(void) 13 | { 14 | int res; 15 | nfc_connstring devices[8]; 16 | size_t device_count; 17 | 18 | nfc_init(&context); 19 | cut_assert_not_null(context, cut_message("Unable to init libnfc (malloc)")); 20 | 21 | device_count = nfc_list_devices(context, devices, 8); 22 | if (device_count <= 0) 23 | cut_omit("No device found"); 24 | 25 | for (size_t i = 0; i < device_count; i++) { 26 | 27 | device = nfc_open(context, devices[i]); 28 | if (!device) 29 | cut_omit("nfc_open() failed."); 30 | 31 | tags = freefare_get_tags(device); 32 | cut_assert_not_null(tags, cut_message("freefare_get_tags() failed")); 33 | 34 | tag = NULL; 35 | for (int i = 0; tags[i]; i++) { 36 | if (freefare_get_tag_type(tags[i]) == MIFARE_DESFIRE) { 37 | tag = tags[i]; 38 | res = mifare_desfire_connect(tag); 39 | cut_assert_equal_int(0, res, cut_message("mifare_desfire_connect() failed")); 40 | 41 | struct mifare_desfire_version_info version_info; 42 | res = mifare_desfire_get_version(tag, &version_info); 43 | cut_assert_equal_int(0, res, cut_message("mifare_desfire_get_version")); 44 | 45 | if (version_info.hardware.storage_size < 0x18) { 46 | cut_omit("DESFire EV1 tests require at least a 4K card"); 47 | } 48 | 49 | if ((version_info.hardware.version_major >= 1) && 50 | (version_info.software.version_major >= 1)) { 51 | return; 52 | } 53 | 54 | mifare_desfire_disconnect(tag); 55 | } 56 | } 57 | nfc_close(device); 58 | device = NULL; 59 | freefare_free_tags(tags); 60 | tags = NULL; 61 | } 62 | cut_omit("No MIFARE DESFire EV1 tag on NFC device"); 63 | } 64 | 65 | void 66 | cut_teardown(void) 67 | { 68 | if (tag) 69 | mifare_desfire_disconnect(tag); 70 | 71 | if (tags) { 72 | freefare_free_tags(tags); 73 | tags = NULL; 74 | } 75 | 76 | if (device) 77 | nfc_close(device); 78 | 79 | nfc_exit(context); 80 | } 81 | 82 | -------------------------------------------------------------------------------- /test/mifare_desfire_fixture.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fixture.h" 5 | 6 | static nfc_context *context; 7 | static nfc_device *device = NULL; 8 | static FreefareTag *tags = NULL; 9 | FreefareTag tag = NULL; 10 | 11 | void 12 | cut_setup(void) 13 | { 14 | int res; 15 | nfc_connstring devices[8]; 16 | size_t device_count; 17 | 18 | nfc_init(&context); 19 | cut_assert_not_null(context, cut_message("Unable to init libnfc (malloc)")); 20 | 21 | device_count = nfc_list_devices(context, devices, 8); 22 | if (device_count <= 0) 23 | cut_omit("No device found"); 24 | 25 | for (size_t i = 0; i < device_count; i++) { 26 | 27 | device = nfc_open(context, devices[i]); 28 | if (!device) 29 | cut_omit("nfc_open() failed."); 30 | 31 | tags = freefare_get_tags(device); 32 | cut_assert_not_null(tags, cut_message("freefare_get_tags() failed")); 33 | 34 | tag = NULL; 35 | for (int i = 0; tags[i]; i++) { 36 | if (freefare_get_tag_type(tags[i]) == MIFARE_DESFIRE) { 37 | tag = tags[i]; 38 | res = mifare_desfire_connect(tag); 39 | cut_assert_equal_int(0, res, cut_message("mifare_desfire_connect() failed")); 40 | 41 | struct mifare_desfire_version_info version_info; 42 | res = mifare_desfire_get_version(tag, &version_info); 43 | cut_assert_equal_int(0, res, cut_message("mifare_desfire_get_version")); 44 | 45 | if (version_info.hardware.storage_size < 0x18) { 46 | cut_omit("DESFire tests require at least a 4K card"); 47 | } 48 | 49 | return; 50 | } 51 | } 52 | nfc_close(device); 53 | device = NULL; 54 | freefare_free_tags(tags); 55 | tags = NULL; 56 | } 57 | cut_omit("No MIFARE DESFire tag on NFC device"); 58 | } 59 | 60 | void 61 | cut_teardown(void) 62 | { 63 | if (tag) 64 | mifare_desfire_disconnect(tag); 65 | 66 | if (tags) { 67 | freefare_free_tags(tags); 68 | tags = NULL; 69 | } 70 | 71 | if (device) 72 | nfc_close(device); 73 | 74 | nfc_exit(context); 75 | } 76 | 77 | -------------------------------------------------------------------------------- /test/mifare_ultralight_fixture.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fixture.h" 5 | 6 | static nfc_context *context; 7 | static nfc_device *device = NULL; 8 | static FreefareTag *tags = NULL; 9 | FreefareTag tag = NULL; 10 | 11 | void 12 | cut_setup(void) 13 | { 14 | int res; 15 | nfc_connstring devices[8]; 16 | size_t device_count; 17 | 18 | nfc_init(&context); 19 | cut_assert_not_null(context, cut_message("Unable to init libnfc (malloc)")); 20 | 21 | device_count = nfc_list_devices(context, devices, 8); 22 | if (device_count <= 0) 23 | cut_omit("No device found"); 24 | 25 | for (size_t i = 0; i < device_count; i++) { 26 | 27 | device = nfc_open(context, devices[i]); 28 | if (!device) 29 | cut_omit("nfc_open() failed."); 30 | 31 | tags = freefare_get_tags(device); 32 | cut_assert_not_null(tags, cut_message("freefare_get_tags() failed")); 33 | 34 | tag = NULL; 35 | for (int i = 0; tags[i]; i++) { 36 | if ((freefare_get_tag_type(tags[i]) == MIFARE_ULTRALIGHT) || 37 | (freefare_get_tag_type(tags[i]) == MIFARE_ULTRALIGHT_C)) { 38 | tag = tags[i]; 39 | res = mifare_ultralight_connect(tag); 40 | cut_assert_equal_int(0, res, cut_message("mifare_ultralight_connect() failed")); 41 | return; 42 | } 43 | } 44 | nfc_close(device); 45 | device = NULL; 46 | freefare_free_tags(tags); 47 | tags = NULL; 48 | } 49 | 50 | cut_omit("No MIFARE UltraLight tag on NFC device"); 51 | } 52 | 53 | void 54 | cut_teardown(void) 55 | { 56 | if (tag) 57 | mifare_ultralight_disconnect(tag); 58 | 59 | if (tags) { 60 | freefare_free_tags(tags); 61 | tags = NULL; 62 | } 63 | 64 | if (device) 65 | nfc_close(device); 66 | 67 | nfc_exit(context); 68 | } 69 | 70 | -------------------------------------------------------------------------------- /test/run-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -n "${SKIP_TESTS}" ]; then 4 | exit 0 5 | fi 6 | 7 | export BASE_DIR="`dirname $0`" 8 | 9 | if test -z "$NO_MAKE"; then 10 | make -C "$BASE_DIR/../" > /dev/null || exit 1 11 | fi 12 | 13 | if test -z "$CUTTER"; then 14 | CUTTER="`make -s -C "$BASE_DIR" echo-cutter`" 15 | fi 16 | 17 | "$CUTTER" --keep-opening-modules -s "$BASE_DIR" "$@" "$BASE_DIR" 18 | # ^^^^^^^^^^^^^^^^^^^^^^ 19 | # FIXME: Remove this workaround once cutter has been fixed upstream. 20 | # Bug report: 21 | # http://sourceforge.net/mailarchive/forum.php?thread_name=20100626123941.GA258%40blogreen.org&forum_name=cutter-users-en 22 | -------------------------------------------------------------------------------- /test/test_felica.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "fixture.h" 6 | 7 | void 8 | test_felica_read_without_encryption(void) 9 | { 10 | uint8_t buffer[64]; 11 | 12 | int res = felica_read(tag, FELICA_SC_RO, 0x00, buffer, 16); 13 | cut_assert_equal_int(16, res); 14 | 15 | uint8_t blocks[] = { 16 | 0x02, 17 | 0x03, 18 | 0x04, 19 | }; 20 | 21 | res = felica_read_ex(tag, FELICA_SC_RO, 3, blocks, buffer, 3 * 16); 22 | cut_assert_equal_int(3 * 16, res); 23 | } 24 | 25 | void 26 | test_felica_write_without_encryption(void) 27 | { 28 | uint8_t buffer[16] = { 29 | 0x00, 0x01, 0x02, 0x03, 30 | 0x03, 0x04, 0x05, 0x06, 31 | 0x07, 0x08, 0x09, 0x0a, 32 | 0x0b, 0x0c, 0x0d, 0x0e, 33 | }; 34 | 35 | int res = felica_write(tag, FELICA_SC_RW, 0x0a, buffer, sizeof(buffer)); 36 | 37 | cut_assert_equal_int(0, res); 38 | } 39 | -------------------------------------------------------------------------------- /test/test_freefare.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "freefare_internal.h" 5 | 6 | void 7 | test_is_mifare_ultralight(void) 8 | { 9 | FreefareTag tag; 10 | nfc_target target; 11 | 12 | tag = mifare_ultralight_tag_new(NULL, target); 13 | cut_assert_true(is_mifare_ultralight(tag)); 14 | mifare_ultralight_tag_free(tag); 15 | } 16 | 17 | void 18 | test_is_mifare_ultralightc(void) 19 | { 20 | FreefareTag tag; 21 | nfc_target target; 22 | 23 | tag = mifare_ultralightc_tag_new(NULL, target); 24 | cut_assert_true(is_mifare_ultralightc(tag)); 25 | mifare_ultralightc_tag_free(tag); 26 | } 27 | -------------------------------------------------------------------------------- /test/test_mifare_application.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | void 6 | test_mifare_application(void) 7 | { 8 | /* Card publisher part */ 9 | 10 | MadAid aid = { 0x22, 0x42 }; 11 | Mad mad = mad_new(2); 12 | 13 | int i; 14 | 15 | cut_assert_not_null(mad, cut_message("mad_new() failed")); 16 | 17 | MifareClassicSectorNumber *s_alloc = mifare_application_alloc(mad, aid, 3 * 3 * 16); 18 | cut_assert_not_null(s_alloc, cut_message("mifare_application_alloc() failed")); 19 | 20 | MifareClassicSectorNumber *s_found = mifare_application_find(mad, aid); 21 | cut_assert_not_null(s_found, cut_message("mifare_application_alloc() failed")); 22 | 23 | for (i = 0; s_alloc[i]; i++) { 24 | cut_assert_equal_int(s_alloc[i], s_found[i], cut_message("Allocated and found blocks don't match at position %d", i)); 25 | } 26 | 27 | cut_assert_equal_int(0, s_alloc[i], cut_message("Invalid size")); 28 | cut_assert_equal_int(0, s_found[i], cut_message("Invalid size")); 29 | 30 | mifare_application_free(mad, aid); 31 | 32 | free(s_alloc); 33 | free(s_found); 34 | 35 | s_found = mifare_application_find(mad, aid); 36 | cut_assert_null(s_found, cut_message("mifare_application_free() failed")); 37 | 38 | s_alloc = mifare_application_alloc(mad, aid, 15 * 16 + 1 * 16 + 1); 39 | cut_assert_not_null(s_alloc, cut_message("mifare_application_alloc() failed")); 40 | 41 | s_found = mifare_application_find(mad, aid); 42 | cut_assert_not_null(s_found, cut_message("mifare_application_alloc() failed")); 43 | 44 | 45 | 46 | for (i = 0; s_alloc[i]; i++) { 47 | cut_assert_equal_int(s_alloc[i], s_found[i], cut_message("Allocated and found blocks don't match at position %d", i)); 48 | } 49 | 50 | cut_assert_equal_int(0, s_alloc[i], cut_message("Invalid size")); 51 | cut_assert_equal_int(0, s_found[i], cut_message("Invalid size")); 52 | 53 | 54 | mifare_application_free(mad, aid); 55 | 56 | free(s_alloc); 57 | free(s_found); 58 | 59 | s_found = mifare_application_find(mad, aid); 60 | cut_assert_null(s_found, cut_message("mifare_application_free() failed")); 61 | 62 | mad_free(mad); 63 | } 64 | -------------------------------------------------------------------------------- /test/test_mifare_classic_create_trailer_block.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | void 6 | test_mifare_classic_create_trailer_block(void) 7 | { 8 | MifareClassicBlock data; 9 | 10 | MifareClassicKey key_a = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 11 | MifareClassicKey key_b = { 0xde, 0xad, 0xbe, 0xef, 0xff, 0xff }; 12 | 13 | mifare_classic_trailer_block(&data, key_a, 0, 0, 0, 4, 0x42, key_b); 14 | 15 | cut_assert_equal_memory(data, sizeof(data), "\xff\xff\xff\xff\xff\xff\xff\x07\x80\x42\xde\xad\xbe\xef\xff\xff", sizeof(data), cut_message("Wrong generated block")); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /test/test_mifare_classic_sector_boundaries.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "freefare_internal.h" 5 | 6 | void 7 | test_mifare_classic_sector_boundaries(void) 8 | { 9 | for (int i = 0; i < 32; i++) { 10 | for (int j = 0; j < 4; j++) { 11 | cut_assert_equal_int(4 * i, mifare_classic_sector_first_block(mifare_classic_block_sector(4 * i)), cut_message("Wrong first block number for block %d", i)); 12 | cut_assert_equal_int(4 * i + 3, mifare_classic_sector_last_block(mifare_classic_block_sector(4 * i + j)), cut_message("Wrong last block number for block %d", i)); 13 | } 14 | } 15 | 16 | for (int i = 0; i < 8; i++) { 17 | for (int j = 0; j < 16; j++) { 18 | cut_assert_equal_int(128 + 16 * i, mifare_classic_sector_first_block(mifare_classic_block_sector(128 + 16 * i)), cut_message("Wrong last block number for block %d", i)); 19 | cut_assert_equal_int(128 + 16 * i + 15, mifare_classic_sector_last_block(mifare_classic_block_sector(128 + 16 * i + j)), cut_message("Wrong last block number for block %d", i)); 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /test/test_mifare_desfire_aes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * These tests implement examples provided in the following documents: 3 | * 4 | * NIST Special Publication 800-38B 5 | * Recommendation for Block Cipher Modes of Operation: The CMAC Mode for Authentication 6 | * May 2005 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include "freefare_internal.h" 14 | 15 | uint8_t key_data[] = { 16 | 0x2b, 0x7e, 0x15, 0x16, 17 | 0x28, 0xae, 0xd2, 0xa6, 18 | 0xab, 0xf7, 0x15, 0x88, 19 | 0x09, 0xcf, 0x4f, 0x3c 20 | }; 21 | 22 | 23 | void 24 | test_mifare_desfire_aes_generate_subkeys(void) 25 | { 26 | uint8_t sk1[] = { 27 | 0xfb, 0xee, 0xd6, 0x18, 28 | 0x35, 0x71, 0x33, 0x66, 29 | 0x7c, 0x85, 0xe0, 0x8f, 30 | 0x72, 0x36, 0xa8, 0xde 31 | }; 32 | 33 | uint8_t sk2[] = { 34 | 0xf7, 0xdd, 0xac, 0x30, 35 | 0x6a, 0xe2, 0x66, 0xcc, 36 | 0xf9, 0x0b, 0xc1, 0x1e, 37 | 0xe4, 0x6d, 0x51, 0x3b 38 | }; 39 | 40 | MifareDESFireKey key = mifare_desfire_aes_key_new(key_data); 41 | cmac_generate_subkeys(key); 42 | 43 | cut_assert_equal_memory(sk1, 16, key->cmac_sk1, 16, cut_message("Wrong sub-key 1")); 44 | cut_assert_equal_memory(sk2, 16, key->cmac_sk2, 16, cut_message("Wrong sub-key 2")); 45 | 46 | mifare_desfire_key_free(key); 47 | } 48 | 49 | void 50 | test_mifare_desfire_aes_cmac_empty(void) 51 | { 52 | MifareDESFireKey key = mifare_desfire_aes_key_new(key_data); 53 | cmac_generate_subkeys(key); 54 | 55 | uint8_t ivect[16]; 56 | memset(ivect, 0, sizeof(ivect)); 57 | 58 | uint8_t expected_cmac[] = { 59 | 0xbb, 0x1d, 0x69, 0x29, 60 | 0xe9, 0x59, 0x37, 0x28, 61 | 0x7f, 0xa3, 0x7d, 0x12, 62 | 0x9b, 0x75, 0x67, 0x46 63 | }; 64 | 65 | uint8_t my_cmac[16]; 66 | cmac(key, ivect, NULL, 0, my_cmac); 67 | 68 | cut_assert_equal_memory(expected_cmac, 16, my_cmac, 16, cut_message("Wrong CMAC")); 69 | 70 | mifare_desfire_key_free(key); 71 | } 72 | 73 | void 74 | test_mifare_desfire_aes_cmac_128(void) 75 | { 76 | MifareDESFireKey key = mifare_desfire_aes_key_new(key_data); 77 | cmac_generate_subkeys(key); 78 | 79 | uint8_t ivect[16]; 80 | memset(ivect, 0, sizeof(ivect)); 81 | 82 | uint8_t message[] = { 83 | 0x6b, 0xc1, 0xbe, 0xe2, 84 | 0x2e, 0x40, 0x9f, 0x96, 85 | 0xe9, 0x3d, 0x7e, 0x11, 86 | 0x73, 0x93, 0x17, 0x2a 87 | }; 88 | 89 | uint8_t expected_cmac[] = { 90 | 0x07, 0x0a, 0x16, 0xb4, 91 | 0x6b, 0x4d, 0x41, 0x44, 92 | 0xf7, 0x9b, 0xdd, 0x9d, 93 | 0xd0, 0x4a, 0x28, 0x7c 94 | }; 95 | 96 | uint8_t my_cmac[16]; 97 | cmac(key, ivect, message, 16, my_cmac); 98 | 99 | cut_assert_equal_memory(expected_cmac, 16, my_cmac, sizeof(message), cut_message("Wrong CMAC")); 100 | 101 | mifare_desfire_key_free(key); 102 | } 103 | 104 | void 105 | test_mifare_desfire_aes_cmac_320(void) 106 | { 107 | MifareDESFireKey key = mifare_desfire_aes_key_new(key_data); 108 | cmac_generate_subkeys(key); 109 | 110 | uint8_t ivect[16]; 111 | memset(ivect, 0, sizeof(ivect)); 112 | 113 | uint8_t message[] = { 114 | 0x6b, 0xc1, 0xbe, 0xe2, 115 | 0x2e, 0x40, 0x9f, 0x96, 116 | 0xe9, 0x3d, 0x7e, 0x11, 117 | 0x73, 0x93, 0x17, 0x2a, 118 | 0xae, 0x2d, 0x8a, 0x57, 119 | 0x1e, 0x03, 0xac, 0x9c, 120 | 0x9e, 0xb7, 0x6f, 0xac, 121 | 0x45, 0xaf, 0x8e, 0x51, 122 | 0x30, 0xc8, 0x1c, 0x46, 123 | 0xa3, 0x5c, 0xe4, 0x11 124 | }; 125 | 126 | uint8_t expected_cmac[] = { 127 | 0xdf, 0xa6, 0x67, 0x47, 128 | 0xde, 0x9a, 0xe6, 0x30, 129 | 0x30, 0xca, 0x32, 0x61, 130 | 0x14, 0x97, 0xc8, 0x27 131 | }; 132 | 133 | uint8_t my_cmac[16]; 134 | cmac(key, ivect, message, sizeof(message), my_cmac); 135 | 136 | cut_assert_equal_memory(expected_cmac, 16, my_cmac, 16, cut_message("Wrong CMAC")); 137 | 138 | mifare_desfire_key_free(key); 139 | } 140 | 141 | void 142 | test_mifare_desfire_aes_cmac_512(void) 143 | { 144 | MifareDESFireKey key = mifare_desfire_aes_key_new(key_data); 145 | cmac_generate_subkeys(key); 146 | 147 | uint8_t ivect[16]; 148 | memset(ivect, 0, sizeof(ivect)); 149 | 150 | uint8_t message[] = { 151 | 0x6b, 0xc1, 0xbe, 0xe2, 152 | 0x2e, 0x40, 0x9f, 0x96, 153 | 0xe9, 0x3d, 0x7e, 0x11, 154 | 0x73, 0x93, 0x17, 0x2a, 155 | 0xae, 0x2d, 0x8a, 0x57, 156 | 0x1e, 0x03, 0xac, 0x9c, 157 | 0x9e, 0xb7, 0x6f, 0xac, 158 | 0x45, 0xaf, 0x8e, 0x51, 159 | 0x30, 0xc8, 0x1c, 0x46, 160 | 0xa3, 0x5c, 0xe4, 0x11, 161 | 0xe5, 0xfb, 0xc1, 0x19, 162 | 0x1a, 0x0a, 0x52, 0xef, 163 | 0xf6, 0x9f, 0x24, 0x45, 164 | 0xdf, 0x4f, 0x9b, 0x17, 165 | 0xad, 0x2b, 0x41, 0x7b, 166 | 0xe6, 0x6c, 0x37, 0x10 167 | }; 168 | 169 | uint8_t expected_cmac[] = { 170 | 0x51, 0xf0, 0xbe, 0xbf, 171 | 0x7e, 0x3b, 0x9d, 0x92, 172 | 0xfc, 0x49, 0x74, 0x17, 173 | 0x79, 0x36, 0x3c, 0xfe 174 | }; 175 | 176 | uint8_t my_cmac[16]; 177 | cmac(key, ivect, message, sizeof(message), my_cmac); 178 | 179 | cut_assert_equal_memory(expected_cmac, 16, my_cmac, 16, cut_message("Wrong CMAC")); 180 | 181 | mifare_desfire_key_free(key); 182 | } 183 | -------------------------------------------------------------------------------- /test/test_mifare_desfire_aid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "freefare_internal.h" 5 | 6 | void 7 | test_mifare_desfire_aid(void) 8 | { 9 | /* 10 | * <-- LSB MSB --> 11 | * | MIFARE DESFire AID Byte 0 | MIFARE DESFire AID Byte 1 | MIFARE DESFire AID Byte 2 | 12 | * | Nible 0 | Nible 1 | Nible 2 | Nible 3 | Nible 4 | Nible 5 | 13 | * | 0xF | MIFARE Classic AID | 0x0...0xF | 14 | * | Function-Cluster | Application code | 15 | * <-- MSB LSB--> 16 | * 17 | * 0xF21438 -> 0x83412F 18 | */ 19 | MifareDESFireAID desfire_aid = mifare_desfire_aid_new(0x00f12ab8); 20 | MadAid mad_aid = { 21 | .function_cluster_code = 0x12, 22 | .application_code = 0xab, 23 | }; 24 | MifareDESFireAID desfire_aid2 = mifare_desfire_aid_new_with_mad_aid(mad_aid, 8); 25 | 26 | cut_assert_equal_memory(desfire_aid->data, 3, desfire_aid2->data, 3, cut_message("wrong aid")); 27 | 28 | cut_assert_equal_int(mifare_desfire_aid_get_aid(desfire_aid), 0x00f12ab8, cut_message("wrong aid")); 29 | 30 | free(desfire_aid); 31 | free(desfire_aid2); 32 | } 33 | -------------------------------------------------------------------------------- /test/test_mifare_desfire_des.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "freefare_internal.h" 4 | 5 | void 6 | test_mifare_rol(void) 7 | { 8 | uint8_t data[8] = "01234567"; 9 | rol(data, 8); 10 | cut_assert_equal_memory("12345670", 8, data, 8, cut_message("Wrong data")); 11 | 12 | uint8_t data2[16] = "0123456789abcdef"; 13 | rol(data2, 16); 14 | cut_assert_equal_memory(data2, 16, "123456789abcdef0", 16, cut_message("Wrong data")); 15 | } 16 | 17 | void 18 | test_mifare_desfire_des_receive(void) 19 | { 20 | uint8_t null_ivect[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 21 | 22 | uint8_t data[8] = { 0xd6, 0x59, 0xe1, 0x70, 0x43, 0xa8, 0x40, 0x68 }; 23 | uint8_t key_data[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; 24 | MifareDESFireKey key = mifare_desfire_des_key_new_with_version(key_data); 25 | 26 | uint8_t expected_data[8] = { 0x73, 0x0d, 0xdf, 0xad, 0xa4, 0xd2, 0x07, 0x89 }; 27 | uint8_t expected_key[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; 28 | 29 | mifare_cypher_blocks_chained(NULL, key, null_ivect, data, 8, MCD_RECEIVE, MCO_DECYPHER); 30 | 31 | cut_assert_equal_memory(&expected_data, 8, &data, 8, cut_message("Wrong data")); 32 | cut_assert_equal_memory(&expected_key, 8, key->data, 8, cut_message("Wrong key")); 33 | 34 | mifare_desfire_key_free(key); 35 | } 36 | 37 | 38 | void 39 | test_mifare_desfire_des_send(void) 40 | { 41 | uint8_t null_ivect[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 42 | 43 | uint8_t data[8] = { 0x73, 0x0d, 0xdf, 0xad, 0xa4, 0xd2, 0x07, 0x89 }; 44 | uint8_t key_data[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; 45 | MifareDESFireKey key = mifare_desfire_des_key_new_with_version(key_data); 46 | 47 | uint8_t expected_data[8] = { 0xd6, 0x59, 0xe1, 0x70, 0x43, 0xa8, 0x40, 0x68 }; 48 | uint8_t expected_key[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; 49 | 50 | mifare_cypher_blocks_chained(NULL, key, null_ivect, data, 8, MCD_SEND, MCO_DECYPHER); 51 | 52 | cut_assert_equal_memory(&expected_data, 8, &data, 8, cut_message("Wrong data")); 53 | cut_assert_equal_memory(&expected_key, 8, key->data, 8, cut_message("Wrong key")); 54 | 55 | mifare_desfire_key_free(key); 56 | } 57 | 58 | void 59 | test_mifare_desfire_padded_data_length(void) 60 | { 61 | size_t res; 62 | 63 | res = padded_data_length(0, 8); 64 | cut_assert_equal_int(res, 8, cut_message("Invalid size")); 65 | res = padded_data_length(1, 8); 66 | cut_assert_equal_int(res, 8, cut_message("Invalid size")); 67 | res = padded_data_length(8, 8); 68 | cut_assert_equal_int(res, 8, cut_message("Invalid size")); 69 | res = padded_data_length(9, 8); 70 | cut_assert_equal_int(res, 16, cut_message("Invalid size")); 71 | res = padded_data_length(0, 16); 72 | cut_assert_equal_int(res, 16, cut_message("Invalid size")); 73 | res = padded_data_length(33, 16); 74 | cut_assert_equal_int(res, 48, cut_message("Invalid size")); 75 | } 76 | -------------------------------------------------------------------------------- /test/test_mifare_desfire_ev1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include "freefare_internal.h" 8 | 9 | #include "fixture.h" 10 | #include "common/mifare_desfire_auto_authenticate.h" 11 | 12 | #define cut_assert_success(last_command) \ 13 | do { \ 14 | cut_assert_equal_int (OPERATION_OK, mifare_desfire_last_picc_error (tag), cut_message ("PICC replied %s", mifare_desfire_error_lookup (mifare_desfire_last_picc_error (tag)))); \ 15 | cut_assert_not_equal_int (-1, res, cut_message ("Wrong return value")); \ 16 | } while (0) 17 | 18 | void 19 | test_mifare_desfire_ev1_aes2(void) 20 | { 21 | int res; 22 | MifareDESFireKey key; 23 | 24 | mifare_desfire_auto_authenticate(tag, 0); 25 | 26 | // Setup the AES key 27 | key = mifare_desfire_aes_key_new_with_version(key_data_aes, key_data_aes_version); 28 | res = mifare_desfire_change_key(tag, 0x80, key, NULL); 29 | cut_assert_success("mifare_desfire_change_key"); 30 | mifare_desfire_key_free(key); 31 | 32 | // Authenticate with the AES key 33 | key = mifare_desfire_aes_key_new_with_version(key_data_aes, key_data_aes_version); 34 | res = mifare_desfire_authenticate_aes(tag, 0, key); 35 | cut_assert_success("mifare_desfire_authenticate"); 36 | mifare_desfire_key_free(key); 37 | 38 | res = mifare_desfire_format_picc(tag); 39 | cut_assert_success("mifare_desfire_format_picc()"); 40 | 41 | key = mifare_desfire_aes_key_new_with_version(key_data_aes, key_data_aes_version); 42 | res = mifare_desfire_authenticate_aes(tag, 0, key); 43 | cut_assert_success("mifare_desfire_authenticate"); 44 | mifare_desfire_key_free(key); 45 | 46 | uint32_t size; 47 | res = mifare_desfire_free_mem(tag, &size); 48 | cut_assert_success("mifare_desfire_free_mem"); 49 | 50 | // Do some commands to check CMAC is properly handled 51 | res = mifare_desfire_free_mem(tag, &size); 52 | cut_assert_success("mifare_desfire_free_mem"); 53 | 54 | struct mifare_desfire_version_info info; 55 | res = mifare_desfire_get_version(tag, &info); 56 | cut_assert_success("mifare_desfire_get_version"); 57 | 58 | res = mifare_desfire_change_key_settings(tag, 0x0F); 59 | cut_assert_success("mifare_desfire_change_key_settings"); 60 | 61 | res = mifare_desfire_free_mem(tag, &size); 62 | cut_assert_success("mifare_desfire_free_mem"); 63 | 64 | MifareDESFireAID aid = mifare_desfire_aid_new(0x112233); 65 | 66 | mifare_desfire_delete_application(tag, aid); 67 | 68 | res = mifare_desfire_create_application(tag, aid, 0xff, 0x81); 69 | cut_assert_success("mifare_desfire_create_application"); 70 | 71 | res = mifare_desfire_select_application(tag, aid); 72 | cut_assert_success("mifare_desfire_select_application"); 73 | 74 | key = mifare_desfire_aes_key_new(key_data_aes); 75 | res = mifare_desfire_authenticate_aes(tag, 0, key); 76 | cut_assert_success("mifare_desfire_authenticate"); 77 | free(key); 78 | 79 | key = mifare_desfire_aes_key_new_with_version(key_data_aes, key_data_aes_version); 80 | res = mifare_desfire_change_key(tag, 0x00, key, NULL); 81 | cut_assert_success("mifare_desfire_change_key"); 82 | mifare_desfire_key_free(key); 83 | 84 | key = mifare_desfire_aes_key_new(key_data_aes); 85 | res = mifare_desfire_authenticate_aes(tag, 0, key); 86 | cut_assert_success("mifare_desfire_authenticate"); 87 | free(key); 88 | 89 | res = mifare_desfire_create_std_data_file(tag, 1, MDCM_MACED, 0x0000, 512); 90 | if ((mifare_desfire_last_picc_error(tag) != DUPLICATE_ERROR) && (mifare_desfire_last_picc_error(tag) != OPERATION_OK)) 91 | cut_assert_success("mifare_desfire_create_std_data_file"); 92 | 93 | char sample_data[] = "Hello World! I'm a string that is probably too long " 94 | "to feet in a single frame. For this reason, it will be split and like" 95 | "ly, some failure in the algorirthm should trigger an error in this uni" 96 | "t test."; 97 | res = mifare_desfire_write_data_ex(tag, 1, 0, strlen(sample_data), sample_data, MDCM_MACED); 98 | cut_assert_success("mifare_desfire_write_data"); 99 | 100 | char buffer[1024]; 101 | 102 | res = mifare_desfire_read_data_ex(tag, 1, 0, 27, buffer, MDCM_MACED); 103 | cut_assert_success("mifare_desfire_read_data"); 104 | cut_assert_equal_memory(buffer, res, sample_data, 27, cut_message("AES crypto failed")); 105 | 106 | char canaries[] = "Canaries Canaries Canaries Canaries Canaries"; 107 | 108 | res = mifare_desfire_read_data_ex(tag, 1, 0, 1, canaries, MDCM_MACED); 109 | cut_assert_success("mifare_desfire_read_data"); 110 | cut_assert_equal_int(1, res, cut_message("Reading 1 byte should return 1 byte")); 111 | cut_assert_equal_memory(canaries, 44, "Hanaries Canaries Canaries Canaries Canaries", 44, cut_message("Canaries got smashed!")); 112 | 113 | uint8_t s, c; 114 | res = mifare_desfire_get_key_settings(tag, &s, &c); 115 | cut_assert_success("mifare_desfire_get__key_settings"); 116 | 117 | res = mifare_desfire_read_data_ex(tag, 1, 27, 27, buffer, MDCM_MACED); 118 | cut_assert_success("mifare_desfire_read_data"); 119 | cut_assert_equal_memory(buffer, res, sample_data + 27, 27, cut_message("AES crypto failed")); 120 | 121 | res = mifare_desfire_read_data_ex(tag, 1, 0, 0, buffer, MDCM_MACED); 122 | cut_assert_success("mifare_desfire_read_data"); 123 | cut_assert_equal_memory(buffer, strlen(buffer), sample_data, strlen(sample_data), cut_message("AES crypto failed")); 124 | 125 | // Revert to the default DES key 126 | res = mifare_desfire_select_application(tag, NULL); 127 | cut_assert_success("mifare_desfire_select_application"); 128 | 129 | key = mifare_desfire_aes_key_new_with_version(key_data_aes, key_data_aes_version); 130 | res = mifare_desfire_authenticate_aes(tag, 0, key); 131 | cut_assert_success("mifare_desfire_authenticate"); 132 | mifare_desfire_key_free(key); 133 | 134 | key = mifare_desfire_des_key_new(key_data_null); 135 | res = mifare_desfire_change_key(tag, 0x00, key, NULL); 136 | cut_assert_success("mifare_desfire_change_key"); 137 | mifare_desfire_key_free(key); 138 | } 139 | -------------------------------------------------------------------------------- /test/test_mifare_desfire_ev1_iso.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "freefare_internal.h" 5 | 6 | #include "fixture.h" 7 | #include "common/mifare_desfire_auto_authenticate.h" 8 | 9 | #define cut_assert_success(last_command) \ 10 | do { \ 11 | cut_assert_equal_int (OPERATION_OK, mifare_desfire_last_picc_error (tag), cut_message ("PICC replied %s", mifare_desfire_error_lookup (mifare_desfire_last_picc_error (tag)))); \ 12 | cut_assert_not_equal_int (-1, res, cut_message ("Wrong return value")); \ 13 | } while (0) 14 | 15 | void 16 | test_mifare_desfire_ev1_iso(void) 17 | { 18 | int res; 19 | 20 | mifare_desfire_auto_authenticate(tag, 0); 21 | 22 | res = mifare_desfire_format_picc(tag); 23 | cut_assert_equal_int(res, 0, cut_message("mifare_desfire_format_picc()")); 24 | 25 | MifareDESFireDF *dfs; 26 | size_t count; 27 | res = mifare_desfire_get_df_names(tag, &dfs, &count); 28 | cut_assert_equal_int(res, 0, cut_message("mifare_desfire_get_df_names()")); 29 | cut_assert_equal_int(count, 0, cut_message("Wrong DF count")); 30 | cut_assert_null(dfs, cut_message("DF should be NULL")); 31 | 32 | MifareDESFireAID aid = mifare_desfire_aid_new(0x111110); 33 | res = mifare_desfire_create_application_iso(tag, aid, 0xFF, 1, 0, 0x111F, NULL, 0); 34 | cut_assert_success("mifare_desfire_create_application_iso"); 35 | free(aid); 36 | 37 | uint8_t app2[] = "App2"; 38 | aid = mifare_desfire_aid_new(0x222220); 39 | res = mifare_desfire_create_application_iso(tag, aid, 0xFF, 1, 0, 0x222F, app2, sizeof(app2)); 40 | cut_assert_success("mifare_desfire_create_application_iso"); 41 | free(aid); 42 | 43 | uint8_t app3[] = "App3"; 44 | aid = mifare_desfire_aid_new(0x333330); 45 | res = mifare_desfire_create_application_iso(tag, aid, 0xFF, 1, 0, 0x333F, app3, sizeof(app3)); 46 | cut_assert_success("mifare_desfire_create_application_iso"); 47 | free(aid); 48 | 49 | aid = mifare_desfire_aid_new(0x444440); 50 | res = mifare_desfire_create_application_iso(tag, aid, 0xFF, 1, 0, 0x111F, NULL, 0); 51 | cut_assert_equal_int(-1, res, cut_message("Should fail")); 52 | cut_assert_equal_int(DUPLICATE_ERROR, mifare_desfire_last_picc_error(tag), cut_message("Should be a duplicate error")); 53 | 54 | res = mifare_desfire_create_application_iso(tag, aid, 0xFF, 1, 0, 0x444F, app2, sizeof(app2)); 55 | cut_assert_equal_int(-1, res, cut_message("Should fail")); 56 | cut_assert_equal_int(DUPLICATE_ERROR, mifare_desfire_last_picc_error(tag), cut_message("Should be a duplicate error")); 57 | free(aid); 58 | 59 | 60 | res = mifare_desfire_get_df_names(tag, &dfs, &count); 61 | cut_assert_equal_int(0, res, cut_message("mifare_desfire_get_df_names()")); 62 | cut_assert_equal_int(3, count, cut_message("Wrong DF count")); 63 | cut_assert_not_null(dfs, cut_message("DF should not be NULL")); 64 | 65 | cut_assert_equal_int(0x111110, dfs[0].aid, cut_message("Wrong value")); 66 | cut_assert_equal_int(0x111F, dfs[0].fid, cut_message("Wrong value")); 67 | cut_assert_equal_int(0, dfs[0].df_name_len, cut_message("Wrong value")); 68 | 69 | cut_assert_equal_int(0x222220, dfs[1].aid, cut_message("Wrong value")); 70 | cut_assert_equal_int(0x222F, dfs[1].fid, cut_message("Wrong value")); 71 | cut_assert_equal_int(sizeof(app2), dfs[1].df_name_len, cut_message("Wrong value")); 72 | cut_assert_equal_memory(app2, sizeof(app2), dfs[1].df_name, dfs[1].df_name_len, cut_message("Wrong value")); 73 | 74 | cut_assert_equal_int(0x333330, dfs[2].aid, cut_message("Wrong value")); 75 | cut_assert_equal_int(0x333F, dfs[2].fid, cut_message("Wrong value")); 76 | cut_assert_equal_int(sizeof(app3), dfs[2].df_name_len, cut_message("Wrong value")); 77 | cut_assert_equal_memory(app3, sizeof(app3), dfs[2].df_name, dfs[2].df_name_len, cut_message("Wrong value")); 78 | free(dfs); 79 | 80 | aid = mifare_desfire_aid_new(0x555550); 81 | res = mifare_desfire_create_application_iso(tag, aid, 0xff, 1, 1, 0x555F, NULL, 0); 82 | cut_assert_success("mifare_desfire_create_application_iso"); 83 | 84 | res = mifare_desfire_select_application(tag, aid); 85 | cut_assert_success("mifare_desfire_select_application"); 86 | 87 | res = mifare_desfire_create_std_data_file_iso(tag, 1, MDCM_PLAIN, 0xEEEE, 32, 0x1234); 88 | cut_assert_success("mifare_desfire_create_std_data_file_iso"); 89 | 90 | res = mifare_desfire_create_backup_data_file_iso(tag, 2, MDCM_PLAIN, 0xEEEE, 32, 0x2345); 91 | cut_assert_success("mifare_desfire_create_std_data_file_iso"); 92 | 93 | res = mifare_desfire_create_linear_record_file_iso(tag, 3, MDCM_PLAIN, 0xEEEE, 32, 10, 0x3456); 94 | cut_assert_success("mifare_desfire_create_linear_record_file_iso"); 95 | 96 | res = mifare_desfire_create_cyclic_record_file_iso(tag, 4, MDCM_PLAIN, 0xEEEE, 32, 10, 0x4567); 97 | cut_assert_success("mifare_desfire_create_cyclic_record_file_iso"); 98 | 99 | uint16_t *ids; 100 | res = mifare_desfire_get_iso_file_ids(tag, &ids, &count); 101 | cut_assert_success("mifare_desfire_get_iso_file_ids"); 102 | 103 | cut_assert_equal_int(4, count, cut_message("Invalid file count")); 104 | cut_assert_equal_int(0x1234, ids[0], cut_message("Wrong file ID")); 105 | cut_assert_equal_int(0x2345, ids[1], cut_message("Wrong file ID")); 106 | cut_assert_equal_int(0x3456, ids[2], cut_message("Wrong file ID")); 107 | cut_assert_equal_int(0x4567, ids[3], cut_message("Wrong file ID")); 108 | free(ids); 109 | 110 | free(aid); 111 | 112 | } 113 | -------------------------------------------------------------------------------- /test/test_tlv.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | const uint8_t shortdata[8] = "elephant"; 6 | const uint8_t eshortdata[11] = "\x03" "\x08" "elephant" "\xfe"; 7 | 8 | /* 9 | * Many thanks to Charles Baudelaire for helping me 10 | * test things and helping you realize your f**king 11 | * OS / compiler does not support UTF-8 ;-) 12 | */ 13 | const uint8_t longdata[660] = "Dans une terre grasse et pleine d'escargots\n" \ 14 | "Je veux creuser moi-même une fosse profonde,\n" \ 15 | "Où je puisse à loisir étaler mes vieux os\n" \ 16 | "Et dormir dans l'oubli comme un requin dans l'onde.\n" \ 17 | "Je hais les testaments et je hais les tombeaux;\n" \ 18 | "Plutôt que d'implorer une larme du monde,\n" \ 19 | "Vivant, j'aimerais mieux inviter les corbeaux\n" \ 20 | "À saigner tous les bouts de ma carcasse immonde.\n" \ 21 | "Ô vers! noirs compagnons sans oreille et sans yeux,\n" \ 22 | "Voyez venir à vous un mort libre et joyeux;\n" \ 23 | "Philosophes viveurs, fils de la pourriture,\n" \ 24 | "À travers ma ruine allez donc sans remords,\n" \ 25 | "Et dites-moi s'il est encor quelque torture\n" \ 26 | "Pour ce vieux corps sans âme et mort parmi les morts!\n"; 27 | 28 | const uint8_t elongdata[665] = "\x07" "\xff\x02\x94" \ 29 | "Dans une terre grasse et pleine d'escargots\n" \ 30 | "Je veux creuser moi-même une fosse profonde,\n" \ 31 | "Où je puisse à loisir étaler mes vieux os\n" \ 32 | "Et dormir dans l'oubli comme un requin dans l'onde.\n" \ 33 | "Je hais les testaments et je hais les tombeaux;\n" \ 34 | "Plutôt que d'implorer une larme du monde,\n" \ 35 | "Vivant, j'aimerais mieux inviter les corbeaux\n" \ 36 | "À saigner tous les bouts de ma carcasse immonde.\n" \ 37 | "Ô vers! noirs compagnons sans oreille et sans yeux,\n" \ 38 | "Voyez venir à vous un mort libre et joyeux;\n" \ 39 | "Philosophes viveurs, fils de la pourriture,\n" \ 40 | "À travers ma ruine allez donc sans remords,\n" \ 41 | "Et dites-moi s'il est encor quelque torture\n" \ 42 | "Pour ce vieux corps sans âme et mort parmi les morts!\n" 43 | "\xfe"; 44 | 45 | void 46 | test_tlv_encode_short(void) 47 | { 48 | uint8_t *res; 49 | size_t osize; 50 | 51 | res = tlv_encode(3, shortdata, sizeof(shortdata), &osize); 52 | cut_assert_equal_int(sizeof(eshortdata), osize, cut_message("Wrong encoded message length.")); 53 | cut_assert_equal_int(3, res[0], cut_message("Wrong type")); 54 | cut_assert_equal_int(sizeof(shortdata), res[1], cut_message("Wrong value length")); 55 | cut_assert_equal_memory(eshortdata, sizeof(eshortdata), res, osize, cut_message("Wrong encoded value")); 56 | free(res); 57 | } 58 | 59 | void 60 | test_tlv_encode_long(void) 61 | { 62 | uint8_t *res; 63 | size_t osize; 64 | 65 | res = tlv_encode(7, longdata, sizeof(longdata), &osize); 66 | cut_assert_equal_int(sizeof(elongdata), osize, cut_message("Wrong encoded message length.")); 67 | cut_assert_equal_int(7, res[0], cut_message("Wrong type")); 68 | cut_assert_equal_int(0xff, res[1], cut_message("Wrong value length")); 69 | cut_assert_equal_int(0x02, res[2], cut_message("Wrong value length")); 70 | cut_assert_equal_int(0x94, res[3], cut_message("Wrong value length")); 71 | cut_assert_equal_memory(elongdata, sizeof(elongdata), res, osize, cut_message("Wrong encoded value")); 72 | free(res); 73 | } 74 | 75 | void 76 | test_tlv_decode_short(void) 77 | { 78 | uint8_t *res; 79 | uint16_t size; 80 | uint8_t type; 81 | 82 | res = tlv_decode(eshortdata, &type, &size); 83 | cut_assert_equal_int(3, type, cut_message("Wrong type")); 84 | cut_assert_equal_int(sizeof(shortdata), size, cut_message("Wrong value length")); 85 | cut_assert_equal_memory(shortdata, sizeof(shortdata), res, size, cut_message("Wrong decoded value")); 86 | free(res); 87 | } 88 | 89 | void 90 | test_tlv_decode_long(void) 91 | { 92 | uint8_t *res; 93 | uint16_t size; 94 | uint8_t type; 95 | 96 | res = tlv_decode(elongdata, &type, &size); 97 | cut_assert_equal_int(7, type, cut_message("Wrong type")); 98 | cut_assert_equal_int(sizeof(longdata), size, cut_message("Wrong value length")); 99 | cut_assert_equal_memory(longdata, sizeof(longdata), res, size, cut_message("Wrong decoded value")); 100 | free(res); 101 | } 102 | 103 | void 104 | test_tlv_rfu(void) 105 | { 106 | uint8_t *data = malloc(0xffff); 107 | cut_assert_not_null(data, cut_message("Out of memory")); 108 | 109 | uint8_t *res = tlv_encode(7, data, 0xffff, NULL); 110 | cut_assert_null(res, cut_message("Size reserved for future use")); 111 | 112 | free(data); 113 | } 114 | 115 | void 116 | test_tlv_append(void) 117 | { 118 | const uint8_t a[] = { 0xde, 0xad, 0xbe, 0xef }; 119 | const uint8_t b[] = { 0x42 }; 120 | 121 | uint8_t ndef_ab_ref[] = { 0x03, 0x04, 0xde, 0xad, 0xbe, 0xef, 0x03, 0x01, 0x42, 0xfe }; 122 | 123 | uint8_t *ndef_a = tlv_encode(3, a, 4, NULL); 124 | uint8_t *ndef_b = tlv_encode(3, b, 1, NULL); 125 | ndef_a = tlv_append(ndef_a, ndef_b); 126 | cut_assert_equal_memory(ndef_ab_ref, sizeof(ndef_ab_ref), ndef_a, sizeof(ndef_ab_ref), cut_message("Wrong appended data")); 127 | 128 | free(ndef_a); 129 | free(ndef_b); 130 | } 131 | --------------------------------------------------------------------------------