├── NEWS ├── AUTHORS ├── ChangeLog ├── src ├── nfc-iclass.h ├── Makefile.am ├── nfc-iclass.1 ├── nfc-utils.h ├── iclass.h ├── nfc-utils.c ├── iclass.c └── nfc-iclass.c ├── .gitmodules ├── Makefile.am ├── configure.ac └── README.md /NEWS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Adam Laurie 2 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 0.1.1: may 2020 2 | first cut 3 | -------------------------------------------------------------------------------- /src/nfc-iclass.h: -------------------------------------------------------------------------------- 1 | char errorexit(char *message); 2 | bool strncasecmp(char *s1, char *s2, int len); 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "loclass"] 2 | path = loclass 3 | url = https://github.com/AdamLaurie/loclass.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = @libnfc_CFLAGS@ 2 | AM_CPPFLAGS = $(all_includes) -I @srcdir@/../loclass/loclass 3 | 4 | bin_PROGRAMS = nfc-iclass 5 | VPATH = @srcdir@:@srcdir@/../loclass/loclass 6 | nfc_iclass_SOURCES = nfc-iclass.c iclass.c iclass.h nfc-utils.c nfc-utils.h \ 7 | ikeys.c cipher.c optimized_cipher.c cipherutils.c elite_crack.c des.c fileutils.c 8 | nfc_iclass_LDADD = @libnfc_LIBS@ 9 | 10 | dist_man_MANS = nfc-iclass.1 11 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = $(LIBNFC_CFLAGS) 2 | 3 | SUBDIRS = src 4 | 5 | style: 6 | find . -path ./loclass -prune -o -name "*.[ch]" -exec perl -pi -e 's/[ \t]+$$//' {} \; 7 | find . -path ./loclass -prune -o -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \ 8 | --indent=spaces=2 --indent-switches --indent-preprocessor \ 9 | --keep-one-line-blocks --max-instatement-indent=60 \ 10 | --brackets=linux --pad-oper --unpad-paren --pad-header \ 11 | --align-pointer=name {} \; 12 | -------------------------------------------------------------------------------- /src/nfc-iclass.1: -------------------------------------------------------------------------------- 1 | .TH nfc-iclass 1 "May 2020" "libnfc" "NFC Tools" 2 | .SH NAME 3 | nfc-iclass \- iClass (Picopass) command line tool 4 | .SH SYNOPSIS 5 | .B nfc-iclass 6 | .RI \fR\fBr\fR|\fBw\fR 7 | .IR DUMP 8 | 9 | .SH DESCRIPTION 10 | .B nfc-iclass 11 | is an iClass tool that allows one to read or write 12 | a tag data to/from a 13 | .IR DUMP 14 | file. 15 | 16 | HID iClass, previously Picopass, uses a binary Dump file to store data for all sectors. 17 | 18 | Be cautious that some parts of an iClass memory can be written only once 19 | and some parts are used as lock bits, so please read the tag documentation 20 | before experimenting too much! 21 | 22 | .SH OPTIONS 23 | .BR r " | " w 24 | Perform read from ( 25 | .B r 26 | ) or write to ( 27 | .B w 28 | ) card. 29 | .TP 30 | .IR DUMP 31 | IClass Dump (ICD) used to write (card to ICD) or (ICD to card) 32 | 33 | .SH BUGS 34 | Please report any bugs on the 35 | .B nfc-iclass 36 | issue tracker at: 37 | .br 38 | .BR https://github.com/nfc-tools/nfc-iclass/issues 39 | .SH LICENCE 40 | .B libnfc 41 | is licensed under the GNU Lesser General Public License (LGPL), version 3. 42 | .br 43 | .B nfc-iclass is licensed under the terms of the GNU GPL (version 2 or later). 44 | 45 | .SH AUTHORS 46 | Adam Laurie , 47 | .PP 48 | This manual page was written by Adam Laurie . 49 | It is licensed under the terms of the GNU GPL (version 2 or later). 50 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([nfc-iclass],[0.1.1],[adam@algroup.co.uk]) 2 | 3 | AC_CONFIG_HEADER(config.h) 4 | 5 | AC_CONFIG_MACRO_DIR([m4]) 6 | 7 | # SVN Revision 8 | define([svn_revision], esyscmd([sh -c "svnversion -n"])) 9 | SVN_REVISION=svn_revision 10 | AC_DEFINE_UNQUOTED([SVN_REVISION], ["$SVN_REVISION"], [SVN revision]) 11 | 12 | # Automake 13 | AM_INIT_AUTOMAKE([foreign]) 14 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) 15 | 16 | AC_LANG([C]) 17 | AC_PROG_CC 18 | AC_PROG_MAKE_SET 19 | 20 | AC_PATH_PROG(PKG_CONFIG, pkg-config, [AC_MSG_ERROR([pkg-config not found.])]) 21 | 22 | # Checks for header files. 23 | AC_HEADER_STDC 24 | AC_HEADER_STDBOOL 25 | AC_CHECK_HEADERS([stdio.h stdlib.h stdint.h stddef.h stdbool.h]) 26 | AC_CHECK_FUNCS([memset]) 27 | AC_CHECK_FUNCS([strcasecmp]) 28 | AC_CHECK_FUNCS([strchr]) 29 | AC_CHECK_FUNCS([strdup], [AC_DEFINE([_XOPEN_SOURCE], [600], [Enable POSIX extensions if present])]) 30 | AC_CHECK_FUNCS([strerror]) 31 | AC_CHECK_FUNCS([strstr]) 32 | AC_CHECK_FUNCS([strtol]) 33 | AC_CHECK_HEADERS([syslog.h]) 34 | AC_C_CONST 35 | AC_FUNC_FORK 36 | AC_FUNC_MALLOC 37 | AC_FUNC_REALLOC 38 | AC_FUNC_VPRINTF 39 | AC_HEADER_SYS_WAIT 40 | 41 | # Checks for types 42 | AC_TYPE_SIZE_T 43 | AC_TYPE_UINT8_T 44 | AC_TYPE_UINT16_T 45 | AC_TYPE_UINT32_T 46 | AC_TYPE_UINT64_T 47 | AC_TYPE_INT32_T 48 | 49 | # --enable-debug support (default:no) 50 | AC_ARG_ENABLE([debug],AS_HELP_STRING([--enable-debug],[Debug flags]),[enable_debug=$enableval],[enable_debug="no"]) 51 | 52 | AC_MSG_CHECKING(for debug flag) 53 | AC_MSG_RESULT($enable_debug) 54 | 55 | if test x"$enable_debug" = "xyes" 56 | then 57 | CFLAGS="$CFLAGS -O0 -g3 -Wall -DDEBUG -pedantic" 58 | fi 59 | AC_SUBST([DEBUG_CFLAGS]) 60 | 61 | # Checks for pkg-config modules. 62 | LIBNFC_REQUIRED_VERSION=1.8.0 63 | PKG_CHECK_MODULES([libnfc], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])]) 64 | 65 | # Crypto functions 66 | AC_CHECK_LIB([crypto], [DES_ecb_encrypt], [], [AC_MSG_ERROR([Cannot find libcrypto.])]) 67 | AC_CHECK_HEADERS([openssl/des.h], [], [AC_MSG_ERROR([Cannot find openssl headers.])]) 68 | 69 | 70 | AC_SUBST(libnfc_LIBS) 71 | AC_SUBST(libnfc_CFLAGS) 72 | 73 | # Set C standard to C99 74 | CFLAGS="$CFLAGS -std=c99" 75 | 76 | AC_CONFIG_FILES([ 77 | Makefile 78 | src/Makefile 79 | ]) 80 | 81 | AC_OUTPUT 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nfc-iclass 2 | iClass / Picopass tool for libnfc 3 | 4 | A CLI tool for reading and writing HID iClass (Picopass) Access Control cards. 5 | 6 | ## Building & Installing 7 | 8 | ``` 9 | git submodule update --init 10 | autoreconf -vis 11 | rm -rf build && mkdir build 12 | cd build 13 | ../configure 14 | make 15 | sudo make install 16 | ``` 17 | 18 | ## Running 19 | 20 | Default behaviour is to dump APP1. 21 | 22 | For more options: 23 | ``` 24 | nfc-iclass -h 25 | 26 | Usage: ./src/nfc-iclass [options] [BINARY FILE|HEX DATA] 27 | 28 | Options: 29 | 30 | -c Use CREDIT KEY Kc / APP2 (default is DEBIT KEY Kd / APP1) 31 | -C Create CONFIG card (? prints list of config cards) 32 | -d Use non-default DEBIT KEY for APP1 33 | -e AUTH KEY is ELITE 34 | -h You're looking at it 35 | -k Keyroll KEY for CONFIG card 36 | -n Do not DIVERSIFY key 37 | -o Write TAG data to FILE 38 | -r Re-Key with KEY (assumes new key is ELITE) 39 | -R Re-Key to non-ELITE 40 | -w WRITE to tag starting from BLOCK (specify # in HEX) 41 | 42 | If no KEY is specified, default HID Kd (APP1) will be used 43 | ``` 44 | ### Examples 45 | 46 | Use ELITE key for APP1: 47 | 48 | ``` 49 | nfc-iclass -d DEADBEEFCAFEF00D -e 50 | ``` 51 | Dump contents of APP2: 52 | 53 | ``` 54 | nfc-iclass -c 0DC442031337D00F 55 | ``` 56 | Write APP1 blocks 8 & 9: 57 | 58 | ``` 59 | nfc-iclass -w 8 aabbccddaabbccddaabbccddaabbccdd 60 | ``` 61 | or 62 | 63 | ``` 64 | nfc-iclass -w 8 /tmp/iclass-8-9-dump.icd 65 | ``` 66 | Re-key to ELITE key: 67 | ``` 68 | nfc-iclass -r deadbeefcafef00d 69 | ``` 70 | Revert to default iClass Kd (note re-key to NON-ELITE with -R) 71 | ``` 72 | nfc-iclass -d deadbeefcafef00d -e -R AFA785A7DAB33378 73 | ``` 74 | Show available CONFIG cards: 75 | 76 | ``` 77 | nfc-iclass -C ? 78 | ``` 79 | Create CONFIG card AV1: 80 | 81 | ``` 82 | nfc-iclass -C AV1 83 | ``` 84 | Create KEYROLL card: 85 | ``` 86 | nfc-iclass -C KRE -k F00FBEEBD00BEEEE 87 | ``` 88 | 89 | ### Config cards 90 | 91 | iClass readers can be reconfigured using CONFIG cards. These will normally be provided free of charge 92 | upon request but as we now have the master Kd it's easy enough to dump the set and recreate them at will. 93 | 94 | The available cards are: 95 | 96 | * AV1: Audio/Visual #1 - Beep ON, LED Off, Flash GREEN on read 97 | * AV2: Audio/Visual #2 - Beep ON, LED RED, Host must flash GREEN 98 | * AV3: Audio/Visual #3 - Beep ON, LED Off, Host must flash RED and/or GREEN 99 | * KP1: Keypad Output #1 - Buffer ONE key (8 bit Dorado) 100 | * KP2: Keypad Output #2 - Buffer ONE to FIVE kets (standard 26 bit) 101 | * KP3: Keypad Output #3 - Local PIN verify 102 | * CSN1: Mifare CSN #1 - 32 bit reverse output 103 | * CSN2: Mifare CSN #2 - 16 bit output 104 | * CSN3: Mifare CSN #3 - 34 bit output 105 | * KRD: Keyroll DISABLE - Set ELITE Key and DISABLE Keyrolling 106 | * KRE: Keyroll ENABLE - Set ELITE Key and ENABLE Keyrolling 107 | * RSTR: Reset READER - Reset READER to defaults 108 | * RSTE: Reset ENROLLER - Reset ENROLLER to defaults 109 | 110 | *Note that a config card is slightly different from a standard one in that APP1 uses more blocks. This matters 111 | for KEYROLL cards as they need the extra space to store the new keys. Other types may work on a standard card 112 | but the most reliable method is to use an existing config card and overwrite it.* 113 | 114 | -------------------------------------------------------------------------------- /src/nfc-utils.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Free/Libre Near Field Communication (NFC) library 3 | * 4 | * Libnfc historical contributors: 5 | * Copyright (C) 2009 Roel Verdult 6 | * Copyright (C) 2009-2013 Romuald Conty 7 | * Copyright (C) 2010-2012 Romain Tartière 8 | * Copyright (C) 2010-2013 Philippe Teuwen 9 | * Copyright (C) 2012-2013 Ludovic Rousseau 10 | * See AUTHORS file for a more comprehensive list of contributors. 11 | * Additional contributors of this file: 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 1) Redistributions of source code must retain the above copyright notice, 16 | * 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 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | * Note that this license only applies on the examples, NFC library itself is under LGPL 34 | * 35 | */ 36 | 37 | /** 38 | * @file nfc-utils.h 39 | * @brief Provide some examples shared functions like print, parity calculation, options parsing. 40 | */ 41 | 42 | #ifndef _EXAMPLES_NFC_UTILS_H_ 43 | # define _EXAMPLES_NFC_UTILS_H_ 44 | 45 | # include 46 | # include 47 | # include 48 | 49 | /** 50 | * @macro DBG 51 | * @brief Print a message of standard output only in DEBUG mode 52 | */ 53 | #ifdef DEBUG 54 | # define DBG(...) do { \ 55 | warnx ("DBG %s:%d", __FILE__, __LINE__); \ 56 | warnx (" " __VA_ARGS__ ); \ 57 | } while (0) 58 | #else 59 | # define DBG(...) {} 60 | #endif 61 | 62 | /** 63 | * @macro WARN 64 | * @brief Print a warn message 65 | */ 66 | #ifdef DEBUG 67 | # define WARN(...) do { \ 68 | warnx ("WARNING %s:%d", __FILE__, __LINE__); \ 69 | warnx (" " __VA_ARGS__ ); \ 70 | } while (0) 71 | #else 72 | # define WARN(...) warnx ("WARNING: " __VA_ARGS__ ) 73 | #endif 74 | 75 | /** 76 | * @macro ERR 77 | * @brief Print a error message 78 | */ 79 | #ifdef DEBUG 80 | # define ERR(...) do { \ 81 | warnx ("ERROR %s:%d", __FILE__, __LINE__); \ 82 | warnx (" " __VA_ARGS__ ); \ 83 | } while (0) 84 | #else 85 | # define ERR(...) warnx ("ERROR: " __VA_ARGS__ ) 86 | #endif 87 | 88 | #ifndef MIN 89 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) 90 | #endif 91 | #ifndef MAX 92 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) 93 | #endif 94 | 95 | uint8_t oddparity(const uint8_t bt); 96 | void oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar); 97 | 98 | void print_hex(const uint8_t *pbtData, const size_t szLen); 99 | void print_hex_bits(const uint8_t *pbtData, const size_t szBits); 100 | void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar); 101 | 102 | void print_nfc_target(const nfc_target *pnt, bool verbose); 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /src/iclass.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Free/Libre Near Field Communication (NFC) library 3 | * 4 | * Libnfc historical contributors: 5 | * Copyright (C) 2009 Roel Verdult 6 | * Copyright (C) 2009-2013 Romuald Conty 7 | * Copyright (C) 2010-2012 Romain Tartière 8 | * Copyright (C) 2010-2013 Philippe Teuwen 9 | * Copyright (C) 2012-2013 Ludovic Rousseau 10 | * See AUTHORS file for a more comprehensive list of contributors. 11 | * Additional contributors of this file: 12 | * Copyright (C) 2020 Adam Laurie 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions are met: 16 | * 1) Redistributions of source code must retain the above copyright notice, 17 | * this list of conditions and the following disclaimer. 18 | * 2 )Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in the 20 | * documentation and/or other materials provided with the distribution. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND 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 COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | * 34 | * Note that this license only applies on the examples, NFC library itself is under LGPL 35 | * 36 | */ 37 | 38 | /** 39 | * @file iclass.h 40 | * @brief provide samples structs and functions to manipulate HID iClass (picopass) tags using libnfc 41 | */ 42 | 43 | #ifndef _ICLASS_H_ 44 | # define _ICLASS_H_ 45 | 46 | #include 47 | #include "cipherutils.h" 48 | 49 | #define ICLASS_ACTIVATE_ALL 0x0A 50 | #define ICLASS_SELECT 0x0C 51 | #define ICLASS_READ_BLOCK 0x0C 52 | #define ICLASS_ANTICOL 0x81 53 | #define ICLASS_UPDATE 0x87 54 | 55 | #define KEYTYPE_DEBIT 0x88 56 | #define KEYTYPE_CREDIT 0x18 57 | 58 | // block 6 byte masks 59 | #define MASK_CREDENTIAL 0x01 // 0 = ???, 1 == CREDENTIAL (byte 4) 60 | #define MASK_PIN_LENGTH 0x0F // BCD PIN length in lower nibble (byte 6) - PIN is BCD nibbles 0->n of block 9 61 | #define MASK_ENCRYPTED 0x01 // 0 == DISABLED, 1 == ENABLED (byte 7) 62 | #define MASK_3DES 0x02 // 0 == DES, 1 == TDES (byte 7) 63 | 64 | //#define DEBUG true 65 | 66 | // config card descriptors 67 | extern char * Config_cards[]; 68 | extern char * Config_types[]; 69 | extern uint8_t * Config_block6[]; 70 | extern uint8_t * Config_block7[]; 71 | extern uint8_t * Config_block_other; 72 | extern bool Elite_Override; 73 | 74 | void iclass_add_crc(uint8_t *buffer, uint8_t length); 75 | unsigned int iclass_crc16(unsigned char *data_p, unsigned char length); 76 | bool iclass_select(nfc_device *pnd, nfc_target *nt); 77 | bool iclass_authenticate(nfc_device *pnd, nfc_target nt, uint8_t *key, bool elite, bool diversify, bool debit_key); 78 | bool iclass_read(nfc_device *pnd, uint8_t block, uint8_t *buff); 79 | bool iclass_write(nfc_device *pnd, uint8_t blockno, uint8_t *data); 80 | uint8_t iclass_print_type(nfc_device *pnd, int *app2_limit); 81 | void iclass_print_blocktype(uint8_t block, uint8_t limit, uint8_t *data); 82 | void iclass_print_configs(void); 83 | // stuff that should be in loclass 84 | void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_key_p, uint8_t mac[4]); 85 | void divkey_elite(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key); 86 | void xorstring(uint8_t *target, uint8_t *src1, uint8_t *src2, uint8_t length); 87 | #endif // _ICLASS_H_ 88 | -------------------------------------------------------------------------------- /src/nfc-utils.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Free/Libre Near Field Communication (NFC) library 3 | * 4 | * Libnfc historical contributors: 5 | * Copyright (C) 2009 Roel Verdult 6 | * Copyright (C) 2009-2013 Romuald Conty 7 | * Copyright (C) 2010-2012 Romain Tartière 8 | * Copyright (C) 2010-2013 Philippe Teuwen 9 | * Copyright (C) 2012-2013 Ludovic Rousseau 10 | * See AUTHORS file for a more comprehensive list of contributors. 11 | * Additional contributors of this file: 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 1) Redistributions of source code must retain the above copyright notice, 16 | * 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 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | * Note that this license only applies on the examples, NFC library itself is under LGPL 34 | * 35 | */ 36 | /** 37 | * @file nfc-utils.c 38 | * @brief Provide some examples shared functions like print, parity calculation, options parsing. 39 | */ 40 | #include 41 | #include 42 | 43 | #include "nfc-utils.h" 44 | 45 | uint8_t 46 | oddparity(const uint8_t bt) 47 | { 48 | // cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel 49 | return (0x9669 >> ((bt ^ (bt >> 4)) & 0xF)) & 1; 50 | } 51 | 52 | void 53 | oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar) 54 | { 55 | size_t szByteNr; 56 | // Calculate the parity bits for the command 57 | for (szByteNr = 0; szByteNr < szLen; szByteNr++) { 58 | pbtPar[szByteNr] = oddparity(pbtData[szByteNr]); 59 | } 60 | } 61 | 62 | void 63 | print_hex(const uint8_t *pbtData, const size_t szBytes) 64 | { 65 | size_t szPos; 66 | 67 | for (szPos = 0; szPos < szBytes; szPos++) { 68 | printf("%02x ", pbtData[szPos]); 69 | } 70 | printf("\n"); 71 | } 72 | 73 | void 74 | print_hex_bits(const uint8_t *pbtData, const size_t szBits) 75 | { 76 | uint8_t uRemainder; 77 | size_t szPos; 78 | size_t szBytes = szBits / 8; 79 | 80 | for (szPos = 0; szPos < szBytes; szPos++) { 81 | printf("%02x ", pbtData[szPos]); 82 | } 83 | 84 | uRemainder = szBits % 8; 85 | // Print the rest bits 86 | if (uRemainder != 0) { 87 | if (uRemainder < 5) 88 | printf("%01x (%d bits)", pbtData[szBytes], uRemainder); 89 | else 90 | printf("%02x (%d bits)", pbtData[szBytes], uRemainder); 91 | } 92 | printf("\n"); 93 | } 94 | 95 | void 96 | print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar) 97 | { 98 | uint8_t uRemainder; 99 | size_t szPos; 100 | size_t szBytes = szBits / 8; 101 | 102 | for (szPos = 0; szPos < szBytes; szPos++) { 103 | printf("%02x", pbtData[szPos]); 104 | if (oddparity(pbtData[szPos]) != pbtDataPar[szPos]) { 105 | printf("! "); 106 | } else { 107 | printf(" "); 108 | } 109 | } 110 | 111 | uRemainder = szBits % 8; 112 | // Print the rest bits, these cannot have parity bit 113 | if (uRemainder != 0) { 114 | if (uRemainder < 5) 115 | printf("%01x (%d bits)", pbtData[szBytes], uRemainder); 116 | else 117 | printf("%02x (%d bits)", pbtData[szBytes], uRemainder); 118 | } 119 | printf("\n"); 120 | } 121 | 122 | void 123 | print_nfc_target(const nfc_target *pnt, bool verbose) 124 | { 125 | char *s; 126 | str_nfc_target(&s, pnt, verbose); 127 | printf("%s", s); 128 | nfc_free(s); 129 | } 130 | -------------------------------------------------------------------------------- /src/iclass.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Free/Libre Near Field Communication (NFC) library 3 | * 4 | * Libnfc historical contributors: 5 | * Copyright (C) 2009 Roel Verdult 6 | * Copyright (C) 2009-2013 Romuald Conty 7 | * Copyright (C) 2010-2012 Romain Tartière 8 | * Copyright (C) 2010-2013 Philippe Teuwen 9 | * Copyright (C) 2012-2013 Ludovic Rousseau 10 | * See AUTHORS file for a more comprehensive list of contributors. 11 | * Additional contributors of this file: 12 | * Copyright (C) 2020 Adam Laurie 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions are met: 16 | * 1) Redistributions of source code must retain the above copyright notice, 17 | * this list of conditions and the following disclaimer. 18 | * 2 )Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in the 20 | * documentation and/or other materials provided with the distribution. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND 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 COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | * 34 | * Note that this license only applies on the examples, NFC library itself is under LGPL 35 | * 36 | */ 37 | /** 38 | * @file iclass.c 39 | * @brief provide samples structs and functions to manipulate HID iClass (Picopass) tags using libnfc 40 | */ 41 | #include "iclass.h" 42 | 43 | // loclass includes 44 | #include "ikeys.h" 45 | #include "cipherutils.h" 46 | #include "cipher.h" 47 | #include "elite_crack.h" 48 | 49 | // system 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | static const nfc_modulation nmiClass = { 56 | .nmt = NMT_ISO14443BICLASS, 57 | .nbr = NBR_106, 58 | }; 59 | 60 | static const nfc_modulation nmTypeB = { 61 | .nmt = NMT_ISO14443B, 62 | .nbr = NBR_106, 63 | }; 64 | 65 | // global iclass diversified key 66 | static unsigned char Div_key[8]; 67 | static unsigned char KeyType; 68 | static unsigned char Uid[8]; 69 | bool Elite_Override= false; 70 | 71 | // iclass config card descriptors 72 | char * Config_cards[]= { 73 | "AV1", 74 | "AV2", 75 | "AV3", 76 | "KP1", 77 | "KP2", 78 | "KP3", 79 | "CSN1", 80 | "CSN2", 81 | "CSN3", 82 | "KRD", 83 | "KRE", 84 | "RSTR", 85 | "RSTE", 86 | NULL 87 | }; 88 | 89 | char * Config_types[]= { 90 | "Audio/Visual #1 - Beep ON, LED Off, Flash GREEN on read", 91 | "Audio/Visual #2 - Beep ON, LED RED, Host must flash GREEN", 92 | "Audio/Visual #3 - Beep ON, LED Off, Host must flash RED and/or GREEN", 93 | "Keypad Output #1 - Buffer ONE key (8 bit Dorado)", 94 | "Keypad Output #2 - Buffer ONE to FIVE keys (standard 26 bit)", 95 | "Keypad Output #3 - Local PIN verify", 96 | "Mifare CSN #1 - 32 bit reverse output", 97 | "Mifare CSN #2 - 16 bit output", 98 | "Mifare CSN #3 - 34 bit output", 99 | "Keyroll DISABLE - Set ELITE Key and DISABLE Keyrolling", 100 | "Keyroll ENABLE - Set ELITE Key and ENABLE Keyrolling", 101 | "Reset READER - Reset READER to defaults", 102 | "Reset ENROLLER - Reset ENROLLER to defaults", 103 | NULL 104 | }; 105 | 106 | uint8_t * Config_block6[]= { 107 | "\x00\x00\x00\x00\x00\x00\xBF\x18", 108 | "\x00\x00\x00\x00\x00\x00\x87\x18", 109 | "\x00\x00\x00\x00\x00\x00\xBF\x18", 110 | "\x00\x00\x00\x00\x00\x00\xBF\x18", 111 | "\x00\x00\x00\x00\x00\x00\xBF\x18", 112 | "\x00\x00\x00\x00\x00\x00\xBF\x18", 113 | "\x00\x00\x00\x00\x00\x00\xBF\x18", 114 | "\x00\x00\x00\x00\x00\x00\xBF\x18", 115 | "\x00\x00\x00\x00\x00\x00\xBF\x18", 116 | "\x0C\x00\x00\x01\x00\x00\xBF\x18", 117 | "\x0C\x00\x00\x01\x00\x00\xBF\x18", 118 | "\x00\x00\x00\x00\x00\x00\x00\x1C", 119 | "\x06\x00\x00\x00\x00\x00\x00\x1C", 120 | NULL 121 | }; 122 | 123 | uint8_t * Config_block7[]= { 124 | "\xAC\x00\xA8\x8F\xA7\x80\xA9\x01", 125 | "\xAC\x00\xA8\x1F\xA7\x80\xA9\x01", 126 | "\xAC\x00\xA8\x0F\xA9\x03\xA7\x80", 127 | "\xAE\x01\x00\x00\x00\x00\x00\x00", 128 | "\xAE\x0B\xAF\xFF\xAD\x15\xB3\x03", 129 | "\xAD\x6D\xB3\x03\x00\x00\x00\x00", 130 | "\xAC\x01\xA7\x80\xA8\x9F\xA9\x01", 131 | "\xAC\x02\xA7\x80\xA8\x9F\xA9\x01", 132 | "\xAC\x03\xA7\x80\xA8\x9F\xA9\x01", 133 | "\xBF\x01\xFF\xFF\xFF\xFF\xFF\xFF", 134 | "\xBF\x03\xFF\xFF\xFF\xFF\xFF\xFF", 135 | "\x00\x00\x00\x00\x00\x00\x00\x00", 136 | "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF", 137 | NULL 138 | }; 139 | 140 | uint8_t * Config_block_other= "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; 141 | 142 | // iclass card descriptors 143 | char * Card_Types[]= { 144 | "PicoPass 16K / 16", // 000 145 | "PicoPass 32K with current book 16K / 16", // 001 146 | "Unknown Card Type!", // 010 147 | "Unknown Card Type!", // 011 148 | "PicoPass 2K", // 100 149 | "Unknown Card Type!", // 101 150 | "PicoPass 16K / 2", // 110 151 | "PicoPass 32K with current book 16K / 2", // 111 152 | }; 153 | 154 | uint8_t Card_App2_Limit[]= { 155 | 0xff, 156 | 0xff, 157 | 0xff, 158 | 0xff, 159 | 0x1f, 160 | 0xff, 161 | 0xff, 162 | 0xff, 163 | }; 164 | 165 | char * Coding[]= { 166 | "ISO 14443 type B only", // 00 167 | "ISO 14443-2 Type B / ISO 15693", // 01 168 | "RFU", // 10 169 | "RFU" // 11 170 | }; 171 | 172 | // add CRC to command buffer - calling routine must ensure there are two spare bytes 173 | void iclass_add_crc(uint8_t *buffer, uint8_t length) 174 | { 175 | uint16_t crc; 176 | 177 | crc= iclass_crc16(&buffer[1], length - 1); 178 | buffer[length]= (unsigned char) ((crc >> 8) & 0x00ff); 179 | buffer[length + 1]= (unsigned char) (crc & 0x00ff); 180 | } 181 | 182 | unsigned int iclass_crc16(unsigned char *data_p, unsigned char length) 183 | { 184 | unsigned char i; 185 | unsigned int data; 186 | unsigned int crc = 0xffff; 187 | 188 | if (length == 0) 189 | return (~crc); 190 | 191 | do 192 | { 193 | for (i=0, data=(unsigned int)0xff & *data_p++; i < 8; i++, data >>= 1) 194 | { 195 | if ((crc & 0x0001) ^ (data & 0x0001)) 196 | crc = (crc >> 1) ^ 0x8408; 197 | else crc >>= 1; 198 | } 199 | } 200 | while (--length); 201 | 202 | crc = ~crc; 203 | data = crc; 204 | crc = (crc << 8) | (data >> 8 & 0xff); 205 | crc = crc ^ 0xBC3; 206 | return (crc); 207 | } 208 | 209 | bool 210 | iclass_select(nfc_device *pnd, nfc_target *nt) 211 | { 212 | // Let the device only try once to find a tag 213 | if (nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false) < 0) 214 | return false; 215 | 216 | // set up for type B 217 | if (nfc_initiator_select_passive_target(pnd, nmTypeB, NULL, 0, nt) < 0) 218 | return false; 219 | 220 | // Try to find an iClass 221 | if (nfc_initiator_select_passive_target(pnd, nmiClass, NULL, 0, nt) <= 0) 222 | return false; 223 | 224 | return true; 225 | } 226 | 227 | // return TRUE if auth OK or FALSE if failed 228 | bool 229 | iclass_authenticate(nfc_device *pnd, nfc_target nt, uint8_t *key, bool elite, bool diversify, bool debit_key) 230 | { 231 | static uint8_t update[14], data[10], nonce[16]; 232 | static uint8_t tmac[4], challenge[16], confirm[10]; 233 | static uint8_t mac[4], uid[8]; 234 | int i; 235 | 236 | // calculate diversified key 237 | if(diversify) 238 | { 239 | // iClass stores uid LSB first but libnfc reverses it 240 | for(i= 0 ; i < 8 ; ++i) 241 | uid[i]= nt.nti.nhi.abtUID[7 - i]; 242 | #if DEBUG 243 | printf("UID:"); 244 | for(i= 0 ; i < 8 ; ++i) 245 | printf("%02x", (unsigned char) uid[i]); 246 | printf("\n"); 247 | printf("KEY:"); 248 | for(i= 0 ; i < 8 ; ++i) 249 | printf("%02x", (unsigned char) key[i]); 250 | printf("\n"); 251 | #endif 252 | if(elite) 253 | divkey_elite((uint8_t *) uid, (uint8_t *) key, (uint8_t *) Div_key); 254 | else 255 | diversifyKey((uint8_t *) uid, (uint8_t *) key, (uint8_t *) Div_key); 256 | } 257 | else 258 | memcpy(Div_key, key, 8); 259 | #if DEBUG 260 | printf("Div KEY:"); 261 | for(i= 0 ; i < 8 ; ++i) 262 | printf("%02x", (unsigned char) Div_key[i]); 263 | printf("\n"); 264 | #endif 265 | 266 | // save for re-keying 267 | memcpy(Uid, uid, 8); 268 | 269 | // get card challenge (block 2) 270 | // 88 is 'debit key' 271 | // 18 is 'credit key' 272 | if(debit_key) 273 | data[0]= KeyType= (unsigned char) KEYTYPE_DEBIT; 274 | else 275 | data[0]= KeyType= (unsigned char) KEYTYPE_CREDIT; 276 | data[1]= 0x02; // block 2 277 | if (nfc_initiator_transceive_bytes(pnd, (uint8_t *) data, 2, (uint8_t *)challenge, 8, -1) < 0) { 278 | nfc_perror(pnd, "nfc_initiator_transceive_bytes"); 279 | return false; 280 | } 281 | #if DEBUG 282 | printf("CC: "); 283 | for(i= 0 ; i < 8 ; ++i) 284 | printf("%02X", (unsigned char) challenge[i]); 285 | printf("\n"); 286 | #endif 287 | 288 | doReaderMAC((uint8_t *) challenge, (uint8_t *) Div_key, (uint8_t *) mac); 289 | 290 | #if DEBUG 291 | printf("MAC: "); 292 | for(i= 0 ; i < 4 ; ++i) 293 | printf("%02X", (unsigned char) mac[i]); 294 | printf("\n"); 295 | #endif 296 | 297 | // send NR 298 | // nR = 0, MAC(k1, cC · nR) 299 | nonce[0]= 0x05; // iclass AUTH 300 | memset(&nonce[1], 0x00, 4); // our challenge is all 00 301 | memcpy(&nonce[5], mac, 4); // plus MAC 302 | 303 | #if DEBUG 304 | printf("SEND: "); 305 | for(i= 0 ; i < 9 ; ++i) 306 | printf("%02X", (unsigned char) nonce[i]); 307 | printf("\n"); 308 | #endif 309 | if (nfc_initiator_transceive_bytes(pnd, (uint8_t *)nonce, 9, (uint8_t *)tmac, 4, -1) < 0) { 310 | nfc_perror(pnd, "nfc_initiator_transceive_bytes"); 311 | return false; 312 | } 313 | 314 | #if DEBUG 315 | printf("TMAC: "); 316 | for(i= 0 ; i < 4 ; ++i) 317 | printf("%02X", (unsigned char) tmac[i]); 318 | printf("\n"); 319 | #endif 320 | 321 | // TMAC should be MAC(k1, cC · nR · 0 32) 322 | // calculate that and compare 323 | memcpy(nonce, challenge, 8); 324 | memset(&challenge[8], 0x00, 8); // both tag and reader are all 00 325 | doMAC_N((uint8_t *) challenge, (uint8_t) 16, (uint8_t *) Div_key, (uint8_t *) mac); 326 | 327 | #if DEBUG 328 | printf("(MAC): "); 329 | for(i= 0 ; i < 4 ; ++i) 330 | printf("%02X", (unsigned char) mac[i]); 331 | printf("\n"); 332 | #endif 333 | 334 | // auth fail? 335 | if(memcmp(mac, tmac, 4)) 336 | return false; 337 | 338 | // TODO: figure out why UPDATE doesn't work with ELITE keys on PN532 339 | // when it works fine on PN531 340 | // (doesn't seem to matter as skipping this step doesn't break anything!) 341 | return true; 342 | 343 | // send update so future writes are allowed 344 | update[0]= 0x87; // update 345 | update[1]= 0x02; // block 2 346 | memcpy(&update[2], challenge, 8); 347 | // find the non 'ff' value and subtract 1 from it 348 | for(i= 2 ; i < 10 ; ++i) 349 | if(update[i] != 0xff) 350 | update[i]--; 351 | // calculate mac 352 | doMAC_N((uint8_t *)&update[1], (uint8_t) 9, (uint8_t *) Div_key, (uint8_t *) mac); 353 | memcpy(&update[10], mac, 4); 354 | 355 | #if DEBUG 356 | printf("SEND: "); 357 | for(i= 0 ; i < 14 ; ++i) 358 | printf("%02X", (unsigned char) update[i]); 359 | printf("\n"); 360 | #endif 361 | 362 | if (nfc_initiator_transceive_bytes(pnd, (uint8_t *) update, 14, (uint8_t *)confirm, 10, 30000) < 0) { 363 | nfc_perror(pnd, "nfc_initiator_transceive_bytes"); 364 | return false; 365 | } 366 | 367 | #if DEBUG 368 | printf("CONF: "); 369 | for(i= 0 ; i < 8 ; ++i) 370 | printf("%02X", (unsigned char) confirm[i]); 371 | printf("\n"); 372 | #endif 373 | 374 | return true; 375 | } 376 | 377 | // return false if read OK or true if failed 378 | bool iclass_read(nfc_device *pnd, uint8_t block, uint8_t *buff) 379 | { 380 | uint8_t command[4], tmp[10], error; 381 | 382 | command[0]= ICLASS_READ_BLOCK; 383 | command[1]= block; 384 | iclass_add_crc(command, 2); 385 | if (nfc_initiator_transceive_bytes(pnd, (uint8_t *) command, 4, tmp, 10, -1) < 0) { 386 | nfc_perror(pnd, "nfc_initiator_transceive_bytes"); 387 | return true; 388 | } 389 | // todo: check CRC 390 | memcpy(buff, tmp, 8); 391 | return false; 392 | } 393 | 394 | // return false if write OK or true if failed 395 | bool iclass_write(nfc_device *pnd, uint8_t blockno, uint8_t *data) 396 | { 397 | int i; 398 | 399 | static unsigned char update[16], mac[4], tmp[10], newdata[8]; 400 | char error; 401 | 402 | // special case - write to block 3 or 4 is a re-key (normally to Elite) 403 | // which can only be done if we know the current key 404 | if(blockno == 3 && KeyType != KEYTYPE_DEBIT) 405 | return true; 406 | if(blockno == 4 && KeyType != KEYTYPE_CREDIT) 407 | return true; 408 | if(blockno == 3 || blockno == 4) 409 | { 410 | // calculate new diversified key (need override to allow re-key back to normal!) 411 | if(!Elite_Override) 412 | divkey_elite((uint8_t *) Uid, (uint8_t *) data, (uint8_t *) tmp); 413 | else 414 | diversifyKey((uint8_t *) Uid, (uint8_t *) data, (uint8_t *) tmp); 415 | // xor with current key 416 | xorstring(newdata, tmp, Div_key, 8); 417 | 418 | #if DEBUG 419 | printf("\nWRITING NEW KEY: "); 420 | for(i= 0 ; i < 8 ; ++i) 421 | printf("%02X", newdata[i]); 422 | printf("\n"); 423 | #endif 424 | } 425 | 426 | update[0]= ICLASS_UPDATE; 427 | update[1]= blockno; 428 | if(blockno == 3 || blockno == 4) 429 | memcpy(&update[2], newdata, 8); 430 | else 431 | memcpy(&update[2], data, 8); 432 | doMAC_N((uint8_t *) &update[1], (uint8_t) 9, (uint8_t *) Div_key, (uint8_t *) mac); 433 | memcpy(&update[10], mac, 4); 434 | iclass_add_crc(update, 14); 435 | if (nfc_initiator_transceive_bytes(pnd, (uint8_t *) update, 16, tmp, 10, -1) < 0) { 436 | nfc_perror(pnd, "nfc_initiator_transceive_bytes"); 437 | return true; 438 | } 439 | 440 | // verify can't ever see result of key block writes 441 | if(blockno == 3 || blockno == 4) 442 | return false; 443 | return (memcmp(data, tmp, 8) != 0); 444 | } 445 | 446 | 447 | // print card details and return number of blocks in application 1 (debit key protected) 448 | uint8_t iclass_print_type(nfc_device *pnd, int *app2_limit) 449 | { 450 | uint8_t type, data[8]; 451 | int i, app1_limit; 452 | 453 | if(iclass_read(pnd, 1, data)) 454 | return 0; 455 | 456 | printf("\n"); 457 | 458 | // get 3 config bits 459 | type= (data[4] & 0x10) >> 2; 460 | type |= (data[5] & 0x80) >> 6; 461 | type |= (data[5] & 0x20) >> 5; 462 | printf(" %s\n", Card_Types[(int) type]); 463 | app1_limit= (int) data[0] - 5; // minus header blocks 464 | *app2_limit= Card_App2_Limit[(int) type]; 465 | 466 | printf(" %s Mode\n", data[7] & 0x80 ? "Personalisation" : "Application"); 467 | printf(" Keys %sLocked\n", data[7] & 0x08 ? "Un" : ""); 468 | printf(" APP1 Blocks: %d\n", app1_limit); 469 | printf(" APP2 Blocks: %d\n", (*app2_limit - app1_limit) - 5); // minus app1 and header 470 | printf("\n Block write locks: \n\n"); 471 | printf(" Chip: %s\n\n", data[3] >> 7 & 0x01 ? "R/W" : "R/O"); 472 | for(i= 0 ; i < 7 ; ++i) 473 | printf(" Block: %02x %s\n", i + 6, data[3] >> i & 0x01 ? "R/W" : "R/O"); 474 | 475 | return data[0]; 476 | } 477 | 478 | // print description of block 479 | void iclass_print_blocktype(uint8_t block, uint8_t limit, uint8_t *data) 480 | { 481 | switch(block) 482 | { 483 | case 0: 484 | printf("UID"); 485 | break; 486 | case 1: 487 | printf("APP1 Blocks: %02X, ", data[0]); 488 | printf("OTP1: %02X, ", data[1]); 489 | printf("OTP2: %02X, ", data[2]); 490 | printf("Write Lock: %02X, ", data[3]); 491 | printf("Chip Config: %02X, ", data[4]); 492 | printf("Memory Config: %02X, ", data[5]); 493 | printf("EAS: %02X, ", data[6]); 494 | printf("Fuses: %02X", data[7]); 495 | break; 496 | case 2: 497 | printf("Card Challenge"); 498 | break; 499 | case 3: 500 | printf("Kd - Debit KEY (hidden)"); 501 | break; 502 | case 4: 503 | printf("Kc - Credit KEY (hidden)"); 504 | break; 505 | case 5: 506 | printf("Application issuer area"); 507 | break; 508 | default: 509 | if(block <= limit) 510 | printf("APP1 Data"); 511 | else 512 | printf("APP2 Data"); 513 | break; 514 | } 515 | } 516 | 517 | void iclass_print_configs(void) 518 | { 519 | int i; 520 | 521 | printf("\n\tConfig Cards:\n\n"); 522 | for(i= 0 ; ; ++i) 523 | { 524 | if(Config_cards[i] == NULL) 525 | break; 526 | printf("\t\t%s:\t%s\n", Config_cards[i], Config_types[i]); 527 | } 528 | printf("\n"); 529 | } 530 | 531 | // at some point this went missing from loclass, so re-creating it here 532 | void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_key_p, uint8_t mac[4]) 533 | { 534 | uint8_t *address_data; 535 | uint8_t div_key[8]; 536 | address_data = (uint8_t*) malloc(address_data_size); 537 | if(address_data == NULL) 538 | { 539 | printf("malloc failed!\n"); 540 | return; 541 | } 542 | 543 | memcpy(address_data, address_data_p, address_data_size); 544 | memcpy(div_key, div_key_p, 8); 545 | 546 | reverse_arraybytes(address_data, address_data_size); 547 | BitstreamIn bitstream = {address_data, address_data_size * 8, 0}; 548 | uint8_t dest []= {0,0,0,0,0,0,0,0}; 549 | BitstreamOut out = { dest, sizeof(dest)*8, 0 }; 550 | MAC(div_key, bitstream, &out); 551 | //The output MAC must also be reversed 552 | reverse_arraybytes(dest, sizeof(dest)); 553 | memcpy(mac, dest, 4); 554 | free(address_data); 555 | return; 556 | } 557 | 558 | // keep temporary key 559 | uint8_t Key_sel_p[8]= { 0 }; 560 | void divkey_elite(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key){ 561 | uint8_t keytable[128] = {0}; 562 | uint8_t key_index[8] = {0}; 563 | uint8_t key_sel[8] = { 0 }; 564 | uint8_t i; 565 | hash2(KEY, keytable); 566 | hash1(CSN, key_index); 567 | for(i = 0; i < 8 ; i++) 568 | key_sel[i] = keytable[key_index[i]] & 0xFF; 569 | 570 | //Permute from iclass format to standard format 571 | permutekey_rev(key_sel, Key_sel_p); 572 | diversifyKey(CSN, Key_sel_p, div_key); 573 | } 574 | 575 | void xorstring(uint8_t *target, uint8_t *src1, uint8_t *src2, uint8_t length) 576 | { 577 | int i; 578 | 579 | for(i= 0 ; i < length ; ++i) 580 | target[i]= src1[i] ^ src2[i]; 581 | } 582 | -------------------------------------------------------------------------------- /src/nfc-iclass.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Free/Libre Near Field Communication (NFC) library 3 | * 4 | * Libnfc historical contributors: 5 | * Copyright (C) 2009 Roel Verdult 6 | * Copyright (C) 2009-2013 Romuald Conty 7 | * Copyright (C) 2010-2012 Romain Tartière 8 | * Copyright (C) 2010-2013 Philippe Teuwen 9 | * Copyright (C) 2012-2013 Ludovic Rousseau 10 | * See AUTHORS file for a more comprehensive list of contributors. 11 | * Additional contributors of this file: 12 | * Copyright (C) 2020 Adam Laurie 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions are met: 16 | * 1) Redistributions of source code must retain the above copyright notice, 17 | * this list of conditions and the following disclaimer. 18 | * 2 )Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in the 20 | * documentation and/or other materials provided with the distribution. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND 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 COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | * 34 | * Note that this license only applies on the examples, NFC library itself is under LGPL 35 | * 36 | */ 37 | 38 | /** 39 | * @file nfc-iclass.c 40 | * @brief HID iClass (picopass) tool 41 | */ 42 | 43 | #ifdef HAVE_CONFIG_H 44 | # include "config.h" 45 | #endif // HAVE_CONFIG_H 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #include 56 | #include 57 | 58 | #include 59 | #include 60 | 61 | #include "nfc-utils.h" 62 | #include "iclass.h" 63 | #include "nfc-iclass.h" 64 | 65 | #include 66 | 67 | // loclass includes 68 | #include "elite_crack.h" 69 | 70 | static nfc_device *pnd; 71 | static nfc_target nt; 72 | // unpermuted version of https://github.com/ss23/hid-iclass-key/blob/master/key 73 | // permuted is 3F90EBF0910F7B6F 74 | uint8_t *Default_kd= (uint8_t *) "\xAF\xA7\x85\xA7\xDA\xB3\x33\x78"; 75 | 76 | // HID DES keys needed for this to work! 77 | static DES_cblock Key1 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 78 | static DES_cblock Key2 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 79 | static DES_key_schedule SchKey1,SchKey2; 80 | 81 | #define MAXWRITE 2000 // 0xff * 8 byte blocks - 5 * 8 byte reserved blocks 82 | int main(int argc, char **argv) 83 | { 84 | int i, j, c, app1_limit, app2_limit; 85 | int infile, outfile, writelen= 0; 86 | static uint8_t buff[8], buff2[8], kc[8], kd[8], kr[8], krekey[8], *key, writedata[MAXWRITE]; 87 | static uint8_t ku[8], kp[8]; 88 | bool got_kc= false, got_kd= false, got_kr= false, dump= false, config= false, elite= false; 89 | bool rekey= false, got_kp= false, got_ku= false; 90 | unsigned int tmp, writeblock= 0; 91 | uint8_t *configdata[2]; // config card block data 92 | uint8_t *configtype; // the config card type requested 93 | char *p; 94 | 95 | while ((c= getopt(argc, argv, "c:C:d:ehk:no:p:r:R:u:w:")) != -1) 96 | { 97 | switch (c) 98 | { 99 | case 'c': 100 | if(strlen(optarg) != 16) 101 | return errorexit("\nCredit KEY must be 16 HEX digits!\n"); 102 | for(i= 0 ; i < 8 ; ++i) 103 | { 104 | if(sscanf(&optarg[i * 2], "%02x", &tmp) != 1) 105 | return errorexit("\nInvalid HEX in key!\n"); 106 | kc[i]= (uint8_t) tmp; 107 | } 108 | got_kc= true; 109 | continue; 110 | 111 | case 'C': 112 | configtype= optarg; 113 | if(*configtype == '?') 114 | { 115 | iclass_print_configs(); 116 | return 0; 117 | } 118 | else 119 | { 120 | for(i= 0 ; ; ++i) 121 | { 122 | if(Config_cards[i] == NULL) 123 | break; 124 | if(!strncasecmp(configtype, Config_cards[i], strlen(Config_cards[i]))) 125 | { 126 | config= true; 127 | configdata[0]= Config_block6[i]; 128 | configdata[1]= Config_block7[i]; 129 | break; 130 | } 131 | } 132 | if(!config) 133 | { 134 | printf("\nInvalid CONFIG card!\n"); 135 | return 1; 136 | } 137 | } 138 | continue; 139 | 140 | case 'd': 141 | if(strlen(optarg) != 16) 142 | return errorexit("\nDebit KEY must be 16 HEX digits!\n"); 143 | for(i= 0 ; i < 8 ; ++i) 144 | { 145 | if(sscanf(&optarg[i * 2], "%02x", &tmp) != 1) 146 | return errorexit("\nInvalid HEX in key!\n"); 147 | kd[i]= (uint8_t) tmp; 148 | } 149 | got_kd= true; 150 | continue; 151 | 152 | case 'e': 153 | elite= true; 154 | continue; 155 | 156 | case 'k': 157 | if(strlen(optarg) != 16) 158 | return errorexit("\nKeyroll KEY must be 16 HEX digits!\n"); 159 | for(i= 0 ; i < 8 ; ++i) 160 | { 161 | if(sscanf(&optarg[i * 2], "%02x", &tmp) != 1) 162 | return errorexit("\nInvalid HEX in key!\n"); 163 | kr[i]= (uint8_t) tmp; 164 | } 165 | got_kr= true; 166 | // this config card will not work unless you have the HID master 3DES key! 167 | if(!memcmp(Key1, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) || !memcmp(Key2, "\x00\x00\x00\x00\x00\x00\x00\x00", 8)) 168 | return errorexit("Master 3DES KEY required for KEYROLLing! (see source comments)\n"); 169 | continue; 170 | 171 | case 'p': 172 | if(strlen(optarg) != 16) 173 | return errorexit("\nPermute KEY must be 16 HEX digits!\n"); 174 | for(i= 0 ; i < 8 ; ++i) 175 | { 176 | if(sscanf(&optarg[i * 2], "%02x", &tmp) != 1) 177 | return errorexit("\nInvalid HEX in key!\n"); 178 | kp[i]= (uint8_t) tmp; 179 | } 180 | got_kp= true; 181 | continue; 182 | 183 | case 'r': 184 | if(strlen(optarg) != 16) 185 | return errorexit("\nRe-key KEY must be 16 HEX digits!\n"); 186 | for(i= 0 ; i < 8 ; ++i) 187 | { 188 | if(sscanf(&optarg[i * 2], "%02x", &tmp) != 1) 189 | return errorexit("\nInvalid HEX in key!\n"); 190 | krekey[i]= (uint8_t) tmp; 191 | } 192 | rekey= true; 193 | continue; 194 | 195 | case 'R': 196 | if(strlen(optarg) != 16) 197 | return errorexit("\nRe-key KEY must be 16 HEX digits!\n"); 198 | for(i= 0 ; i < 8 ; ++i) 199 | { 200 | if(sscanf(&optarg[i * 2], "%02x", &tmp) != 1) 201 | return errorexit("\nInvalid HEX in key!\n"); 202 | krekey[i]= (uint8_t) tmp; 203 | } 204 | rekey= true; 205 | Elite_Override= true; 206 | continue; 207 | 208 | case 'u': 209 | if(strlen(optarg) != 16) 210 | return errorexit("\nUnpermute KEY must be 16 HEX digits!\n"); 211 | for(i= 0 ; i < 8 ; ++i) 212 | { 213 | if(sscanf(&optarg[i * 2], "%02x", &tmp) != 1) 214 | return errorexit("\nInvalid HEX in key!\n"); 215 | ku[i]= (uint8_t) tmp; 216 | } 217 | got_ku= true; 218 | continue; 219 | 220 | case 'w': 221 | // don't allow writing of reserved blocks! 222 | if(sscanf(optarg, "%x", &tmp) != 1 || tmp < 5) 223 | return errorexit("Can't write - Bad block number! (Lowest valid block is 5)\n"); 224 | writeblock= (int) tmp; 225 | continue; 226 | 227 | case 'o': 228 | if((outfile= open(optarg, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) <= 0) 229 | return errorexit("Can't open output file!\n"); 230 | dump= true; 231 | continue; 232 | 233 | case 'h': 234 | default: 235 | printf("\nUsage: %s [options] [BINARY FILE|HEX DATA]\n", argv[0]); 236 | printf("\n Options:\n\n"); 237 | printf("\t-c Use CREDIT KEY Kc / APP2 (default is DEBIT KEY Kd / APP1)\n"); 238 | printf("\t-C Create CONFIG card (? prints list of config cards)\n"); 239 | printf("\t-d Use non-default DEBIT KEY for APP1\n"); 240 | printf("\t-e AUTH KEY is ELITE\n"); 241 | printf("\t-h You're looking at it\n"); 242 | printf("\t-k Keyroll KEY for CONFIG card\n"); 243 | printf("\t-n Do not DIVERSIFY key\n"); 244 | printf("\t-o Write TAG data to FILE\n"); 245 | printf("\t-p Permute KEY\n"); 246 | printf("\t-r Re-Key with KEY (assumes new key is ELITE)\n"); 247 | printf("\t-R Re-Key to non-ELITE\n"); 248 | printf("\t-u Unpermute KEY\n"); 249 | printf("\t-w WRITE to tag starting from BLOCK (specify # in HEX)\n"); 250 | printf("\n"); 251 | printf("\tIf no KEY is specified, default HID Kd (APP1) will be used\n"); 252 | printf("\n"); 253 | printf(" Examples:\n\n"); 254 | printf(" Use non-default key for APP1:\n\n"); 255 | printf("\t%s -d DEADBEEFCAFEF00D\n\n", argv[0]); 256 | printf(" Dump contents of APP2:\n\n"); 257 | printf("\t%s -c 0DC442031337D00F\n\n", argv[0]); 258 | printf(" Write APP1 blocks 8 & 9:\n\n"); 259 | printf("\t%s -w 8 aabbccddaabbccddaabbccddaabbccdd\n\n", argv[0]); 260 | printf(" or\n\n"); 261 | printf("\t%s -w 8 /tmp/iclass-8-9-dump.icd\n\n", argv[0]); 262 | return 1; 263 | } 264 | } 265 | 266 | // do non-tag related stuff first 267 | if(got_kp) 268 | { 269 | printf("\n Permuting key: %02x%02x%02x%02x%02x%02x%02x%02x\n", kp[0], kp[1], kp[2], kp[3], kp[4], kp[5], kp[6], kp[7]); 270 | permutekey(kp, buff); 271 | printf(" Permuted key: %02x%02x%02x%02x%02x%02x%02x%02x\n", buff[0], buff[1], buff[2], buff[3], buff[4], buff[5], buff[6], buff[7]); 272 | } 273 | 274 | if(got_ku) 275 | { 276 | printf("\n Unpermuting key: %02x%02x%02x%02x%02x%02x%02x%02x\n", ku[0], ku[1], ku[2], ku[3], ku[4], ku[5], ku[6], ku[7]); 277 | permutekey_rev(ku, buff); 278 | printf(" Unpermuted key: %02x%02x%02x%02x%02x%02x%02x%02x\n", buff[0], buff[1], buff[2], buff[3], buff[4], buff[5], buff[6], buff[7]); 279 | } 280 | 281 | // check for conflicting args 282 | if(writeblock && config) 283 | printf("*** WARNING! WRITE may overwrite CONFIG blocks! ***"); 284 | 285 | // prepare data for writing 286 | if(writeblock) 287 | { 288 | if(optind >= argc) 289 | return errorexit("Can't write - No data!\n"); 290 | p= argv[argc - 1]; 291 | // is it a file? 292 | if((infile= open(p, O_RDONLY)) > 0) 293 | { 294 | if((writelen= read(infile, writedata, MAXWRITE)) <= 0) 295 | return errorexit("\nRead failed!\n"); 296 | } 297 | else 298 | { 299 | writelen= strlen(p) / 2; 300 | for(i= 0 ; i < writelen && i < MAXWRITE ; ++i, p += 2) 301 | { 302 | if(sscanf(p, "%02x", &tmp) != 1) 303 | return errorexit("\nInvalid HEX in data!\n"); 304 | writedata[i]= (char) tmp; 305 | } 306 | close(infile); 307 | } 308 | if(writelen > MAXWRITE) 309 | return errorexit("Can't write - Data too long!\n"); 310 | if(writelen % 8) 311 | return errorexit("Can't write - Data must be 8 byte blocks!\n"); 312 | } 313 | 314 | nfc_context *context; 315 | nfc_init(&context); 316 | if (context == NULL) { 317 | ERR("Unable to init libnfc (malloc)"); 318 | exit(EXIT_FAILURE); 319 | } 320 | 321 | // Try to open the NFC device 322 | pnd = nfc_open(context, NULL); 323 | if (pnd == NULL) { 324 | ERR("Error opening NFC device"); 325 | nfc_exit(context); 326 | exit(EXIT_FAILURE); 327 | } 328 | 329 | if (nfc_initiator_init(pnd) < 0) { 330 | nfc_perror(pnd, "nfc_initiator_init"); 331 | nfc_close(pnd); 332 | nfc_exit(context); 333 | exit(EXIT_FAILURE); 334 | } 335 | 336 | printf("\nNFC device: %s opened\n", nfc_device_get_name(pnd)); 337 | 338 | // Try to find an iClass 339 | if (!iclass_select(pnd, &nt)) { 340 | ERR("no tag was found\n"); 341 | nfc_close(pnd); 342 | nfc_exit(context); 343 | exit(EXIT_FAILURE); 344 | } 345 | 346 | // Get the info from the current tag 347 | printf("Found iClass card with UID: "); 348 | size_t szPos; 349 | for (szPos = 0; szPos < 8; szPos++) { 350 | printf("%02x", nt.nti.nhi.abtUID[szPos]); 351 | } 352 | printf("\n"); 353 | 354 | if(!(app1_limit= (int) iclass_print_type(pnd, &app2_limit))) 355 | { 356 | printf(" could not determine card type!\n"); 357 | app1_limit= 0xff; 358 | } 359 | 360 | printf("\n reading header blocks...\n\n"); 361 | for(i= 0 ; i < 6 ; ++i) 362 | { 363 | printf(" Block 0x%02x: ", i); 364 | if(!iclass_read(pnd, i, buff)) 365 | { 366 | for(j= 0 ; j < 8 ; ++j) 367 | printf("%02x", (uint8_t) buff[j]); 368 | printf(" "); 369 | for(j= 0 ; j < 8 ; ++j) 370 | printf("%c", isprint(buff[j]) ? (char) buff[j] : '.'); 371 | printf(" "); 372 | iclass_print_blocktype(i, app1_limit, buff); 373 | if(dump) 374 | if(write(outfile, buff, 8) != 8) 375 | errorexit("Write to output file failed!\n"); 376 | } 377 | else 378 | printf("read failed!"); 379 | printf("\n"); 380 | } 381 | printf("\n"); 382 | 383 | // APP1 operations only if APP2 not requested OR APP1 key specifically provided 384 | // (this allows you to get past an unknown key for APP1 without causing an auth error) 385 | if(!got_kc || got_kd) 386 | { 387 | // authenticate with default Debit key if no key provided 388 | if(got_kd) 389 | key= kd; 390 | else 391 | key= Default_kd; 392 | printf(" authing to APP1 with key: "); 393 | for(i= 0 ; i < 8 ; ++i) 394 | printf("%02x", key[i]); 395 | printf("\n\n"); 396 | if(!iclass_authenticate(pnd, nt, key, elite, true, true)) 397 | { 398 | ERR("authentication failed\n"); 399 | nfc_close(pnd); 400 | nfc_exit(context); 401 | // carry on if we wanted to read APP2 402 | exit(EXIT_FAILURE); 403 | } 404 | 405 | // write config card if specified 406 | if(config) 407 | { 408 | // keyroll card 409 | if(!strncasecmp(configtype, "KR", 2)) 410 | { 411 | if(!got_kr) 412 | { 413 | printf("\nPlease specify KEYROLL key!\n"); 414 | return 1; 415 | } 416 | if(app1_limit < 0x16) 417 | return errorexit("\nAPP1 too small for KEYROLL!\n"); 418 | printf("\n Writing KEYROLL card: %s\n\n", configtype); 419 | for(i= 0 ; i < 2 ; ++i) 420 | { 421 | if(iclass_write(pnd, i +6, configdata[i])) 422 | return errorexit("Write failed!\n"); 423 | else 424 | printf(" Written block %02x\n", i + 6); 425 | } 426 | for(i= 0x08 ; i < 0x0d ; ++i) 427 | if(iclass_write(pnd, i, Config_block_other)) 428 | return errorexit("Write failed!\n"); 429 | else 430 | printf(" Written block %02x\n", i); 431 | // update keyroll blocks 432 | // keyroll cards are 3DES encrypted for block 0x0d upwards 433 | DES_set_key_unchecked(&Key1, &SchKey1); 434 | DES_set_key_unchecked(&Key2, &SchKey2); 435 | DES_ecb2_encrypt((unsigned char (*)[8]) kr, (unsigned char (*)[8]) buff, &SchKey1, &SchKey2, DES_ENCRYPT); 436 | if(iclass_write(pnd, 0x0d, buff)) 437 | return errorexit("Write failed!\n"); 438 | else 439 | printf(" Written block 0d (KEYROLL KEY)\n"); 440 | DES_ecb2_encrypt((unsigned char (*)[8]) Config_block_other, (unsigned char (*)[8]) buff, &SchKey1, &SchKey2, DES_ENCRYPT); 441 | for(i= 0x0e ; i < 0x14 ; ++i) 442 | if(iclass_write(pnd, i, buff)) 443 | return errorexit("Write failed!\n"); 444 | else 445 | printf(" Written block %02x\n", i); 446 | buff2[0]= 0x15; 447 | memcpy(&buff2[1], kr, 7); 448 | DES_ecb2_encrypt((unsigned char (*)[8]) buff2, (unsigned char (*)[8]) buff, &SchKey1, &SchKey2, DES_ENCRYPT); 449 | if(iclass_write(pnd, 0x14, buff)) 450 | return errorexit("Write failed!\n"); 451 | else 452 | printf(" Written block 14 (Partial KEYROLL KEY)\n"); 453 | memset(buff2, 0xff, 8); 454 | buff2[0]= kr[7]; 455 | DES_ecb2_encrypt((unsigned char (*)[8]) buff2, (unsigned char (*)[8]) buff, &SchKey1, &SchKey2, DES_ENCRYPT); 456 | if(iclass_write(pnd, 0x15, buff)) 457 | return errorexit("Write failed!\n"); 458 | else 459 | printf(" Written block 15 (Partial KEYROLL KEY)\n"); 460 | DES_ecb2_encrypt((unsigned char (*)[8]) Config_block_other, (unsigned char (*)[8]) buff, &SchKey1, &SchKey2, DES_ENCRYPT); 461 | for(i= 0x16 ; i <= app1_limit ; ++i) 462 | if(iclass_write(pnd, i, buff)) 463 | return errorexit("Write failed!\n"); 464 | else 465 | printf(" Written block %02x\n", i); 466 | } 467 | else 468 | { 469 | //standard config card 470 | printf("\n Writing CONFIG card: %s\n\n", configtype); 471 | for(i= 0 ; i < 2 ; ++i) 472 | if(iclass_write(pnd, i + 6, configdata[i])) 473 | return errorexit("Write failed!\n"); 474 | else 475 | printf(" Written block %02x\n", i + 6); 476 | for(i= 0x08 ; i <= app1_limit ; ++i) 477 | if(iclass_write(pnd, i, Config_block_other)) 478 | return errorexit("Write failed!\n"); 479 | else 480 | printf(" Written block %02x\n", i); 481 | } 482 | printf("\n"); 483 | } 484 | 485 | // write to APP1 486 | if(writeblock && writeblock <= app1_limit) 487 | { 488 | printf("\n writing...\n\n"); 489 | for(i= 0 ; i < writelen ; i += 8, writeblock++) 490 | { 491 | if(iclass_write(pnd, writeblock, &writedata[i])) 492 | return errorexit("Write failed!\n"); 493 | else 494 | { 495 | printf(" Block 0x%02x: ", writeblock); 496 | for(j= i ; j < i + 8 ; ++j) 497 | printf("%02x", (uint8_t) writedata[j]); 498 | printf(" "); 499 | for(j= i ; j < i + 8 ; ++j) 500 | printf("%c", isprint(writedata[j]) ? (char) writedata[j] : '.'); 501 | printf(" "); 502 | iclass_print_blocktype(writeblock, app1_limit, writedata); 503 | } 504 | printf("\n"); 505 | } 506 | printf("\n"); 507 | } 508 | 509 | // show APP1 510 | printf(" reading APP1 blocks...\n\n"); 511 | for(i= 6 ; i <= app1_limit ; ++i) 512 | { 513 | printf(" Block 0x%02x: ", i); 514 | if(!iclass_read(pnd, i, buff)) 515 | { 516 | for(j= 0 ; j < 8 ; ++j) 517 | printf("%02x", (uint8_t) buff[j]); 518 | printf(" "); 519 | for(j= 0 ; j < 8 ; ++j) 520 | printf("%c", isprint(buff[j]) ? (char) buff[j] : '.'); 521 | printf(" "); 522 | iclass_print_blocktype(i, app1_limit, buff); 523 | if(dump) 524 | if(write(outfile, buff, 8) != 8) 525 | return errorexit("Write to output file failed!\n"); 526 | } 527 | else 528 | printf("read failed!"); 529 | printf("\n"); 530 | } 531 | printf("\n"); 532 | } // end of APP1 operations 533 | 534 | // show APP2 if requested 535 | if(got_kc) 536 | { 537 | printf(" authing to APP2 with key: "); 538 | key= kc; 539 | for(i= 0 ; i < 8 ; ++i) 540 | printf("%02x", key[i]); 541 | printf("\n\n"); 542 | if(!iclass_authenticate(pnd, nt, key, elite, true, false)) { 543 | ERR("authentication failed\n"); 544 | nfc_close(pnd); 545 | nfc_exit(context); 546 | exit(EXIT_FAILURE); 547 | } 548 | 549 | // write to APP2 550 | if(writeblock && writeblock > app1_limit) 551 | { 552 | printf("\n writing...\n\n"); 553 | for(i= 0 ; i < writelen ; i += 8, writeblock++) 554 | { 555 | if(iclass_write(pnd, writeblock, &writedata[i])) 556 | return errorexit("Write failed!\n"); 557 | else 558 | { 559 | printf(" Block 0x%02x: ", writeblock); 560 | for(j= 0 ; j < 8 ; ++j) 561 | printf("%02x", (uint8_t) writedata[j]); 562 | printf(" "); 563 | for(j= 0 ; j < 8 ; ++j) 564 | printf("%c", isprint(writedata[j]) ? (char) writedata[j] : '.'); 565 | printf(" "); 566 | iclass_print_blocktype(writeblock, app1_limit, writedata); 567 | } 568 | printf("\n"); 569 | } 570 | printf("\n"); 571 | } 572 | 573 | printf(" reading APP2 blocks:\n\n"); 574 | for(i= app1_limit + 1 ; i <= app2_limit ; ++i) 575 | { 576 | printf(" Block 0x%02x: ", i); 577 | if(!iclass_read(pnd, i, buff)) 578 | { 579 | for(j= 0 ; j < 8 ; ++j) 580 | printf("%02x", (uint8_t) buff[j]); 581 | printf(" "); 582 | for(j= 0 ; j < 8 ; ++j) 583 | printf("%c", isprint(buff[j]) ? (char) buff[j] : '.'); 584 | printf(" "); 585 | iclass_print_blocktype(i, app1_limit, buff); 586 | if(dump) 587 | if(write(outfile, buff, 8) != 8) 588 | return errorexit("Write to output file failed!\n"); 589 | } 590 | else 591 | printf("read failed!"); 592 | printf("\n"); 593 | } 594 | printf("\n"); 595 | } 596 | 597 | 598 | if(dump) 599 | close(outfile); 600 | 601 | // rekey last so we don't have to worry about re-authing 602 | if(rekey) 603 | { 604 | // block 3 (debit key) or 4 (credit key) writes will be xor'd as appropriate 605 | if(got_kc) 606 | { 607 | if(iclass_write(pnd, 4, krekey)) 608 | return errorexit("Re-Key CREDIT failed!\n"); 609 | } 610 | else 611 | { 612 | if(iclass_write(pnd, 3, krekey)) 613 | return errorexit("Re-Key DEBIT failed!\n"); 614 | } 615 | printf("\n Re-Key OK\n"); 616 | } 617 | 618 | nfc_close(pnd); 619 | nfc_exit(context); 620 | exit(EXIT_SUCCESS); 621 | } 622 | 623 | char errorexit(char *message) 624 | { 625 | printf("%s\n", message); 626 | return 1; 627 | } 628 | 629 | bool strncasecmp(char *s1, char *s2, int len) 630 | { 631 | char *us1 = s1, *us2 = s2; 632 | 633 | while (tolower(*us1++) == tolower(*us2++) && --len) 634 | ; 635 | return (tolower(*--us1) != tolower(*--us2)); 636 | } 637 | --------------------------------------------------------------------------------